A common scenario in web applications involve using a single password as a means of authentication as well as a means to derive a secret for use in encrypting data.
Many strong key derivation functions like
properties that make them strong password hashing functions as well. However,
the same derived value cannot be used as an encryption key and a password hash.
The password hash value has to be stored by the server to compare against the
provided password in future authentication attempts. If this same value is
used as an encryption key, an attacker that compromises the server will be
able to decrypt the data easily.
There is an easy solution for this problem. While I will be using
pbkdf2 can be substituted for any strong algorithm like
Generate a random key
kusing a cryptographically secure random number generator. This means using
CryptGenRandomon Windows and
/dev/urandomon *nix operating systems. This random key
kwill be used for encryption.
Generate two salts
s2and store them in plaintext.
pbkdf2(password, s1)and store this value. This will be the password hash you use to compare against for future authentication attempts.
pbkdf2(password, s2) xor kand store this value.
When the random key
kis required for encrypting or decrypting data, simply
xorthe value of
pbkdf2(password, s2)against the value computed in step 4.
The advantage of this scheme is that the encryption key
k is not tied to the
password. This means that passwords can be changed without re-encrypting
the data with a new key repeating steps 1 - 4. A very useful property to have
in the event of a server compromise where passwords have to be reset en masse.