I'm working on a private project where I need to store a users financial data in a database. I'll encrypt this data using AES, and I'll be using scrypt to generate a AES encryption key from a more simple user password.

I also want to be able to tell the user if he is using the correct password when logging in. Speed is not an issue: the program will run on the user's device and not on a multi-user server.

So summarizing: I want to use one password both to encrypt data and authenticate users.

I can see two options for doing this:

  1. Generate a SHA-256 hash from the scrypt output, store the hash in StoredHash and check if SHA256(scrypt("supplied password")) == StoredHash.

  2. Encrypt the scrypt-output of the password using AES in EncryptedScryptOutput using the scrypt-output as the key and store that, and check if scrypt("supplied password") == AESdescrypt(decryptionKey = scrypt("supplied password"), EncryptedScryptOutput).

I (think I :-) am aware of the technical way this should be done, using salts and/or initial vectors. My questions are: Am I correct that both versions will be secure? Would you say that one option is better than the other, and why?



Both options are secure but the first is preferable.

Your first proposal is to use scrypt(password) as the encryption key and SHA256(scrypt(password)) as the password verifier. This is fine. Since it's computationally infeasible to calculate a SHA256 preimage it will not be possible for an attacker to calculate the encryption key from the password verifier.

Your second proposal is to use scrypt(password) as the encryption key and to use AES(scrypt(password), scrypt(password)) as the password verifier. Using a value as the key to encrypt itself is a form of hash, so this is equivalent to your first proposal except that you're using AES(x,x) to hash scrypt(password) instead of using SHA256. Since SHA256 is a proper hash function and AES(x,x) is not your first proposal is preferable.

  • Thanks! I sort-of thought that because I had seen that it's better to use a proper hashing function than basically a made up one. The only reason why I thought it might be less secure in this situation is because an attacker knows the parameters I'll use in SCrypt, and therefore knows the format of the data I'm putting in the SHA function (allways a 32 byte pseudorandom number). I didn't know if that would compromise it. Even when salting the SHA256 the attacker would still know the exact number of bytes going in. – Jelle Veraa Nov 9 '12 at 8:32

As far as I can tell, your scheme is this:

  • Compute scrypt(pass) and store it as the authentication key in your database.
  • Compute sha256(scrypt(pass)) and use that as your data encryption key.

The problem with this technique is that an attacker with access to your database can simply compute the SHA256 hash of your scrypt hashes to gain the encryption keys.

A better solution would be to use a second scrypt hash as your data encryption key, with a surrogate key to facilitate easy password changes:

  • Generate two salts (s1 and s2) and store them in plaintext.
  • Generate a cryptographically secure random key k - this is our surrogate key.
  • Compute scrypt(pass, s1) and store it as the authentication key in your database.
  • Compute scrypt(pass, s2) and xor k with it. Store this value in your database.
  • Use 'k' as your data encryption key.

When decrypting, you compute scrypt(pass, s2) and xor it with the stored key value to get the original value of k back.

This protects you against cases where the database is breached, and allows you to change passwords by computing the original value of k, then xoring that with scrypt hash of the new password and salt. Keep in mind that if a user forgets their password they will not be able to recover the data.

  • I think the point of generating sha256(scrypt(pass)) is so they don't need to store scrypt(pass) in the database. – Brendan Long Nov 8 '12 at 20:49
  • @BrendanLong That would work, but I still think the key should be independent. – Polynomial Nov 8 '12 at 21:42
  • @BrendanLong correct, that is the purpose - I'm not storing the scrypted key directly. Polynomial: I think David in the other answer got my question better, sorry for not formulating it more clearly for you. Thanks for the answer though, I learned something anyway! :) – Jelle Veraa Nov 9 '12 at 8:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.