On L421-L423 of src/blowfish.c, a sha256_key()
function is created for password-based key derivation with a salt for blowfish. Unfortunately, even with 1,000 rounds, SHA-256 is designed to be fast, and can be parallelized with GPUs when brute forcing a file. Instead, the Blowfish key should be derived using bcrypt or scrypt. Both defeat parallelization on GPUs, and scrypt further defeats FPGAs.
—
Reply to this email directly or view it on GitHub.
Note that unlike scrypt (or PBKDF2, or Argon2), bcrypt is not designed to be a KDF.
Note that unlike scrypt (or PBKDF2, or Argon2), bcrypt is not designed to be a KDF.
Indeed. Bad recommendation on my part, although I wouldn't recommend Argon2 quite yet either. Scrypt seems to be the most fitting here.
Argon2 is implemented in libsodium and is the winner of the Password Hashing Competition. It is designed as a KDF.
However, note that the rest of Vim's cryptmethod is also poorly implemented. My suggestion is to use Argon2 as a KDF and either XSalsa20-Poly1305 or XChaCha20-Poly1305 (with a strong, random nonce) for authenticated encryption.
libsodium provides high-level APIs for password hashing and authenticated encryption and is my strong suggestion.
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub
There's also TweetNaCl if you want something smaller to vendor, although you'd have to vendor Argon2 separately:
https://tweetnacl.cr.yp.to/software.html
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub
My thoughts on this are:
It's best to use a library. With a library we're going to get any security updates from people who presumably know what they're doing and spend time learning about exploits so they can address them in their code. Also researchers are actually likely to test an external library, but not Vim's internal code.
However it's useful to have *something* available on every system Vim supports, so I think something should be baked in, still. Also Vim needs to be able to read old files.
I think adding a 'cryptkdf' option would be a decent idea. Include something built-in; either copied from a library with a license that allows it (probably best), or something simple like PDKDF2 (we already have a SHA256 we could use a a building block). But also include an option for a library implementation of a few algorithms. Argon2 is a good idea but it's still pretty new so if a flaw is found another method would probably be nice to have already available, so maybe the choices could be something like 'pdkdf2', 'lib-scrypt', and 'lib-argon2' for starters.
The number of iterations is key for the security of these algorithms. I'm vaguely aware that scrypt and argon2 are also configurable in memory use, but I know a lot less about that. But regardless we'll want to allow configuring the KDF to scale with hardware without recompiling Vim. So a 'cryptkdfcount' or similar option should also be provided. I think a good way to do this would be to allow both numeric values, but also time values. For example, the user could do ":set cryptkdfcount=1s" and Vim would estimate how many iterations would take a full second on the current hardware and use that. 1-3 seconds is probably a reasonable default value as well.
Speaking of defaults: I think Vim should default to the strongest method available. I additionally think Vim should warn on saving with a known broken format such as the original blowfish implementation, or the zip algorithm, or even blowfish2 without a decent KDF. Maybe even compile without the broken algorithms altogether unless the user specifically passes --include-bad-crypto to the configure script or something.
As for blowfish: I'm not very concerned about the weaknesses in the algorithm *for the specific uses Vim is likely to use it for*, however having a better encryption algorithm available is much nicer. Nevertheless, I *am* a little concerned whether we know the algorithm is implemented properly. I'd like to see output from Vim's implementation matched up against output from a well-known library implementation. In theory with the same salt, same IV, and same key, I think they should be compatible.
I should note here that I'm also a little uneasy with the current salt/IV generation. Basically it's just one system time (in microseconds) and a hash (I doubt the rand() adds anything useful). That could be a lot better, using /dev/urandom for example where supported, or the equivalent. Or maybe hash system time (still in microseconds) with a previous hash periodically, say while waiting for user input or something; I'm not familiar with best practices when a good system-provided random source is missing. I say I'm "uneasy" because I doubt there's any good exploit for this in Vim's use scenarios, but it's documented widely that a good unpredictable IV is required for CBC mode encryption, so I don't get any warm fuzzies from the "random" code here.
Bram, are you already working on any of this? I have been thinking about starting an implementation of some of the above but that's a lot of work I don't want going to waste if you have other ideas. Maybe hashing out a top-level interface and goals, then making a fork for more distributed development, would be a decent idea? I don't think any halfway implementations will be useful, especially since we'll probably need to grow a blowfish3 or other cryptmethod to use the new KDF (preferably in a forwards-compatible way to handle other new KDFs that may come along in the future).
(Slight nit: it's PBKDF2. The acronym stands for "Password-Based Key Derivation Function #2".)
—
You are receiving this because you commented.
Reply to this email directly or view it on GitHub
Oh, and I forgot one more:
While there *may* not be any exploitable weakness related to non-authenticated encryption *in Vim's case*, we can't prove it. And, if such an attack exists, Vim *will* be vulnerable. If we're already modifying the crypto code (and we should, because the KDF is way too weak) then we may as well throw in a MAC to prevent the *possibility* of a chosen-ciphertext attack. It shouldn't harm anything and it could potentially help a lot. I say we re-open the issue that got created for non-authenticated encryption.
Thanks, I knew that, I just was typing faster than I was thinking apparently. That's one of those acronyms I really need to expand out in my head before typing correctly. I do the same thing with IMDB which occasionally lands me on some interesting cyber-squatter pages. :-(
On Wednesday, March 23, 2016 at 6:21:21 PM UTC-5, Manuel Ortega wrote:
> > That reminds me of something else. Why isn't 'modified' set when you change cryptmethod or the encryption password?
>
>
> Isn't it because the *buffer* hasn't changed? IIUC, in the latter case the *file* changes, not the buffer. In the former case neither has changed, so for sure 'modified' should not be set.
>
>
If you change any of 'fileformat', 'fileencoding', 'bomb', or 'nofixeol' then the buffer doesn't change either, only the file. 'cryptmethod' is the oddball here.
I view the 'modified' flag as saying "if you save this buffer then the file will change".
I got caught once while I was testing something where I had the wrong password because I had quit Vim after changing the password, but I hadn't saved yet. Vim let me do that without any complaint, because the buffer wasn't modified.
Your definition of broken is wrong. Broken means it doesn't work at all.
Not quite. Think "broken" in the sense of "code-breaker". Is it easy for a skilled analyst to subvert? What about a large team of skilled analysts and mathematicians with billions of dollars of specialized computer hardware?
—
You are receiving this because you commented.
Reply to this email directly or view it on GitHub
I call something "broken" when it cannot serve its intended purpose. Cryptography's purpose is to keep data secret.
On Thu, Mar 24, 2016 at 6:08 AM, Bram Moolenaar <Br...@moolenaar.net> wrote:
>
>
> Ben Fritz wrote:
>
> > On Wed, Mar 23, 2016 at 4:58 PM, Bram Moolenaar <Br...@moolenaar.net> wrote:
> > > The original blowfish encryption is not broken, it's just weaker than it
> > > should be. It's still a lot stronger than zip.
> >
> > Is it? This page makes it sound like "blowfish" was pretty much completely
> > broken if you knew any of the plaintext: https://dgl.cx/2014/10/vim-blowfish
>
> Your definition of broken is wrong. Broken means it doesn't work at
> all. e.g., Vim crashes when using it, or when decrypting you can't get
> back the original text. When do you call a car broken? When you can't
> drive. Not when you can't open the window.
>
—
You are receiving this because you commented.
Reply to this email directly or view it on GitHub
It's more like breaking in. Or breakable. That skilled person doesn't
break the encryption, it finds the password. For the next password you
have to start over. English can be quite confusing.
Let's also consider the case of, say, the recent compression oracle against iMessage attachments. You don't "figure out the password", you grab an encrypted message, alter it, send it, and look for errors in the response. Keep doing this (the paper estimated 2^18 messages) until you have the original plaintext message.
In a similar vein, Vaudenay's CBC mode padding oracle.
The consequence of these attacks? Cryptographers say "unauthenticated encryption is broken". Someone else responds: "No it's not; look, it still works".
—
You are receiving this because you commented.
Reply to this email directly or view it on GitHub
Few thoughts from a cryptographer (https://rist.tech.cornell.edu). I use vim as my primary editor for everything (thanks for all the great work on it!). I wanted to know if there was built in password-based encryption for exactly the Dropbox use case mentioned on the thread and lead me eventually to this here.
1) Modern authenticated encryption is now universally thought by cryptographers to be necessary for secure encryption. Encrypt-then-MAC (e.g., CTR mode followed by HMAC) is a good way to go, or an all-in-one scheme like GCM or OCB. Using an authenticated encryption scheme provides resistance against any active attacks that manipulate ciphertexts. This is in my opinion clearly in the threat model for untrusted remote storage (such as Dropbox) --- I for one would not want a malicious insider at Dropbox to be able to undetectably modify at will what my encrypted text document contains.
2) Reiterating something from earlier: Looking at the existing code, the randomness used to generate salts and seeds (usually called IVs by cryptographers) does indeed look very weak. Really this should be replaced as indicated above by a call to a system RNG. If no good system RNG is available, probably safest to just disallow use of encryption (decryption would still be ok). It is a pain to integrate portable RNG code, as Windows, BSD, and Linux all do different things and direct reads from devices like /dev/urandom can introduce race conditions, but it is possible to do well and several other libraries out there have done it. This should be a relatively modest change to sha2_seed() given the RNG logic. By the way, the sha2_seed() function has a latent bug unless I am misunderstanding something, as it repeats random data when 32 < salt_len or 32 < header_len. One shouldn't be repeating random data if it is to be used with crypto algorithms. Doesn't appear to curren tly be a n issue since largest salt_len and header_len is 8 bytes, but an 8 byte salt is too small for security these days even if one has a good RNG --- I'd increase it to 16 or 32.
3) I started playing with the code to understand how hard it would be to build in a good authenticated encryption scheme. Right now I have an Encrypt-then-MAC module built that supports authenticated encryption using AES CTR mode and HMAC-SHA256. But this doesn't seem to work for anything but the main file encryption, as there are several places where encryption is assumed to be length-preserving. (Note that authenticated encryption always means that ciphertexts are longer than decryption, by a fixed number of bytes dependent on mode. For my example it is 32 bytes extra.) These calls are (at least) in undo.c and memline.c, and would need to be modified to support authenticated encryption of (I believe) the undo and swap data. I don't understand the implementation of these modules so not sure how invasive a change this will be. Right now I have my toy implementation default to just using CTR mode for these calls and things seem to work though obviously with weaker guarante es for t hose files. (I haven't done extensive testing.)
4) Side point: the messages one gets when recovering from an encrypted swap file is really confusing. I think I may understand the issue, but this would actually be dealt with in a seemingly more user friendly way if one used authenticated encryption since entering the wrong password would be detectable.
5) The issue of validating crypto implementations is an important one, but this should be easy to do with standard test vectors for low-level primitives like AES and SHA-256 (NIST gives out some, for example). The whole encryption format would do well to be documented as well, though, so one could, e.g., implement a separate utility that just decrypts vim encrypted files.
Happy to help someone with developing a good solution. I think having a built in strong password-based encryption would be a very nice feature for vim, and one that I would use.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub, or mute the thread.
Some more thoughts:
libsodium
as a dependency and statically link to it. This avoids all issues relating to libsodium
not being present on the user's system. Distributions that provide a recent enough libsodium
can substitute system libsodium with a configure switch. Substituting a too-old version will result in a compile-time error.libsodium
provides high-level APIs, so this should be easy. My preference (assuming that we only need to worry about symmetric-key encryption) is the ChaCha20-Poly1305 AEAD, with Argon2 for password-based key derivation. libsodium
also provides a portable CSPRNG that gets entropy from the operating system; this solves the portability problems. It even works around bugs such as Linux /dev/urandom
not blocking when not seeded.libsodium
offers no way to interrupt Argon2 asynchronously. Therefore, it is best to run Argon2 in a subprocess that is given the password, salt, and other parameters over stdin
(in binary form) and returns the hash on stdout
(again in binary form). The subprocess can be killed with a SIGKILL on Unix or TerminateProcess on Windows in the event of a timeout, with no risk of leaking resources (since it owns none other than memory).I think this can be closed now, that we are (optionally) using libsodium.
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.
Closed #639 as completed.
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.