The first time a user logs in to our app, we derive an AES key from their password using PBKDF2. The AES key is kept in RAM only and used to encrypt and wrap other keys and data during the session.
When the current session ends, we throw away the key but keep the encrypted data and the derivation settings (salt/iteration count/etc.) for next time.
On subsequent logins, we re-derive the key based on the password and settings, but want to check the key (password) is valid (to some reasonable level of confidence) before attempting to use it.
We don't want to also compute a hash over the password because the key derivation is already (deliberately) long-running and we don't want to make that process longer with another long-running hash algorithm.
I've seen a few solutions to this but I'm wondering if there is any standard that should be followed. What I've seen so far:
- In Cryptography Engineering, Schneier et al suggest taking hash data from the n-1th iteration of your derivation function and hashing that with the salt, password, etc. to form a verification code. You can store this, and compute the same code for the candidate while you derive the key. If they don't match, you reject. Downside: If using third-party crypto libraries, it probably won't be possible to get access to the internal state of PBKDF2 to do this.
- Compute something like
SHA256(key+salt+password)and store that. Compute for the candidate and reject if they don't match.
Use the key to encrypt something with a known pattern or suffix, and store that. e.g.
E(key, <32 bytes random data> + <32 bytes of 0>`.
Store this, decrypt using the candidate key and check if the suffix matches. The number of 0s you choose determines the chance of a false positive.
The latter seems simple and effective, but I'm looking for clear advice from an expert/authority on the matter.