I've read that storing password hashes in a database, you can store the salt in plaintext alongside the actual hash with no detriment to security. I was thinking that one could derive a key from the user's password, and use that key to encrypt the random salt, so that every time the user goes to login, the salt is decrypted and the salt can be concatenated with the password at that point and hashed, and check to see if it is valid. This way, if the database becomes compromised, the salt values themselves would be dependent on the user's password, and an attacker would have no hope of ever knowing the salt. Would there be any additional benefit to this scheme?

  • 1
    $\begingroup$ Note that the "common" goal of a salt is to make finding the preimage (hash) of the password a different problem for each user so progress for user A can not be used for user B. in this regard encrypting the salt does not help. Now for your suggestion of encrypting the salt: Iff I have to do trials with candidate passwords then having the salt encrypted "just" adds some cost for each trial which, arguably, can be done better (and with provable consequences) with constructions like pbkdf (iterated hashing) or more fancy stuff like scrypt $\endgroup$ – Christoph Egger Jun 29 '20 at 16:05

Would there be any additional benefit to this scheme?

Not really; password hashing is storing the hashed password in this form:

$$H( \text{password}, \text{salt} )$$

where $H$ is some hard-to-compute hash function. What you are suggesting is to replace this with:

$$H( \text{password}, D( \text{password}, \text{encrypted_salt}) )$$

(where $D$ is the decryption function). However, this can be rewritten in the original format, as:

$$H'( \text{password}, \text{salt'} )$$

where $H'(A, B) = H( A, D( A, B ))$, and $salt'$ is the encrypted salt in the database. In particular, any attack against a hashed format in the first form also applies to a hashed format generated by the second form.

What would be an incremental improvement would be if we 'encrypted' [1] the salt, not with the password, but with a key which is stored outside the database (e.g. in a Hardware Security Module, or HSM); for extra security, we would never import the key into memory, but instead have the HSM decrypt the encrypted salts for us (and have it stir in the password as a part of the decryption process, e.g. as a tweak).

What that would do is imply that it would not be sufficient for the adversary to recover the database, but they would also need either the decrypted version of the salt, or the key used to decrypt the salt. And, if we place the key in the HSM, they wouldn't be able to get that key, and if we have the HSM stir in the password in the decryption process, then not only would they need to gain control of the server (so that they can issue decrypt commands to the HSM), but they could only test guesses to the password only as fast as the HSM can decrypt, no matter what other computational resources he has available.

[1]: Scare quotes are there because we don't actually need reversible encryption; what we could do is have the 'decryption' process be $D(\text{key}, \text{encrypted_salt}, \text{password}) = Hash( \text{key}, \text{encrypted_salt}, \text{password} )$. Then, we wouldn't actually select the salt; instead, we would select a random encrypted salt, compute the salt based on that, and then pass that value to our password-hashing function.


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.