2

In my new secret document encryption utility, the key for symmetric encryption = the hash of a random salt and a user provided password.

It is necessary to have a slow hash function in order to prevent brute force on less than optimal passwords. MD5 and SHA1 have proved immensely speedy, so that is obviously not enough. I also do not have high hopes for SHA256.

One options is to repeat the hashing operation an absurd number of times. Due to the vast repetition necessary (100k minimum), I was somewhat concerned about attackers who would know a way of skipping ahead with shortcuts, perhaps using the rho table, or some other means.

Is this 100,000 rehash approach sound, or should I use some other algorithm to create a key from a password and salt?

Obviously I can also require a more complex password, but I think a good goal would be to support the 6 letter, non dictionary variation, even if I do require a whole second of rehashing to perform the unlock. This is an acheivable goal, and I feel it is better to allow shorter passwords if a) that is what the user wants and b) it does not impact security in a significant way.

1. An estimate on how long the hash would take for a <2 Ghz processor is 1 millisecond for every 1-2 thousand repetitions (depending on the algorithm). For 6 letter, non dictionary passwords that need to hold up for 1 year, we would need the key generation to take at least 100 milliseconds.

700 Software
  • 13,807
  • 3
  • 52
  • 82
  • I know you have explicitly stated 6, but is there any reason you wouldn't go for 8 letters? Length gives you an excellent multiplier... – Rory Alsop Feb 27 '12 at 17:13
  • I plan on providing settings for encryption level, and then telling how long it would take to crack based on the encryption level and password complexity, including comparison against one or more password lists and dictionaries. The utility will not actually prevent the user from using a weak password. – 700 Software Feb 27 '12 at 18:18
  • MD5 is a hashing function. You cannot "Decrypt" MD5. Why are trying to limit the passwords to such few characters? – Ramhound Feb 27 '12 at 18:25
  • @Ramhound, I am not limiting the user to 6 characters, I am instead giving them the option of using 6 characters if that is what they want to do. And encryption level is actually a layman's way of saying how long the hash will take until we get the encryption key. – 700 Software Feb 27 '12 at 18:31
  • @GeorgeBailey - I understand that. You have provided some important information since my comment. I still suggest not using the term encrypting in the context of using hashing methods like SHA1, SHA256, SHA512, ect – Ramhound Feb 28 '12 at 15:41

3 Answers3

5

Some of the popular options for this are PBKDF2, bcrypt, and scrypt. A related answer has plenty of good info. The gist is bcrypt is better than PBKDF2, but either would be fine and secure. scrypt looks promising, but is quite new, and in the world of cryptography, we often default to the tried and tested unless absolutely necessary. See the answer I linked to for attacks against which scrypt is better than bcrypt.

mikeazo
  • 2,827
  • 12
  • 29
  • 1
    My question is about encryption key generation, not really about password storage. However, I should be able [separate the salt and resulting hash](http://stackoverflow.com/a/5882472/463304) with little difficulty. I plan on storing the salt, and using the resulting hash as an encryption key. – 700 Software Feb 27 '12 at 18:03
  • 2
    @GeorgeBailey You dont really need to worry about the salt... Anyway, as the answer notes, PBKDF2 is an excellent option, in fact it was built specifically for this: it stands for Password Based Key Deriviation Function. Which is *exactly* what you're asking for. – AviD Feb 27 '12 at 22:03
  • @AviD, Thanks for that information, however, it does seem that I need to store the salt with the encrypted file. If subsequent key generations on the same password use different salt, the decryption key would turn out different from the encryption key and therefore would be unusable. – 700 Software Feb 27 '12 at 22:08
  • On a separate note, my thoughts are to use both PBKDF2 and bcrypt, and xor the two hashes together to create the key. – 700 Software Feb 27 '12 at 22:11
  • @GeorgeBailey of course it would need to be same, otherwise it would be pointless... Not sure how PBKDF2 lets you handle the salt, but that would be the way to go. – AviD Feb 27 '12 at 22:13
2

I recommend you use PBKDF2. It is designed exactly for this purpose: deriving a cryptographic key from a password. You can tune PBKDF2, to make deriving the crypto key take exactly as long as you would like it to take (longer = more secure, but too long = inconvenient). You can store the salt in the clear along with the ciphertext.

I don't think I'd recommend using bcrypt or scrypt. They are designed for hashing passwords. While bcrypt or scrypt certainly could form the basis for a reasonable solution, they're not directly suitable and you might need to make some tweaks (carefully), so it'll probably be easier to use PBKDF2 safely.

I would not bother with xor-ing bcrypt and PBKDF2. PBKDF2 is fine on its own; no need to xor it with anything else.

D.W.
  • 98,420
  • 30
  • 267
  • 572
2

On a separate note, I want to warn you about the security problems with using short passphrases to derive cryptographic keys.

You mention a hypothetical "6 letter, non dictionary password". Well, here's a note of caution about that. Most 6-letter passwords do not have anywhere near the strength of a random collection of 6 letters; most 6-letter passwords have a good deal of structure. And simply telling users "don't use a dictionary word" is not enough to change that.

I also want to warn you about the possibility of parallelization. You mention that a "6 letter, non dictionary password" should "hold up for 1 year" if key generation takes at least 100 milliseconds. Well, I think what you mean is that if there is no structure in the password, then breaking the crypto key will take at least 1 CPU-year. There's a big difference between 1 CPU-year and 1 year. Someone who obtains 100 machines could crack the password in a few days. That's a pretty low level of security, in today's world of botnets, EC2, and cloud computing. And that already assumes that your users will pick perfectly random 6-letter passwords -- an assumption that we know to be totally false.

For these reasons, user-chosen passwords are generally not a very good basis for a cryptographic key. It is likely that a substantial fraction of user-chosen passwords will be breakable through brute-force attacks, even if you use PBKDF2. Therefore, you might want to seriously consider what else you can do, in addition to PBKDF2, to protect your users.

One possibility might be to generate a random suggested passphrase for the user (e.g., five words chosen at random from a 4096-word dictionary, or ten characters chosen at random from a-zA-Z0-9), and make it easy for the user to use your suggestion. Another method might be to test the quality of the user's passphrase, and if it seems poor, warn the user that their passphrase is likely insecure and maybe provide a recommended alternative (e.g., use the following suggested passphrase). Another method is to use public-key cryptography, but automate the process so that the user doesn't need to be aware of what's going on. There are probably many other creative possibilities you could consider, too, depending upon the details of your specific application domain.

D.W.
  • 98,420
  • 30
  • 267
  • 572