The "right" way to hash a password for storing in the database

So, you're storing a password in that database, huh?

Published on Tuesday, 28 June 2011

So, given that password security is in the news quite a bit lately with all sorts of high-profile hacking incidents, I figured I'd write down a little code here that I've been considering.

Because MD5 and SHA1 (and to some extent, SHA2) are designed to be fast, they're not a good choice for hashing passwords (the speed makes brute force attacks fast...). There is, however, a class of cryptographic algorithms known as "key derivation functions" that are designed specifically to be SLOW, and therefore not vulnerable to brute force or "rainbow table" attacks. Fortunately, the .NET cryptography classes include PBKDF2, which is a common KDF. Following is an example of how it should be used:

static byte[] Hash(string password, out byte[] salt, int iterations = 1000, int saltSize = 16, int keySize = 24)
{
    using( var rng = RandomNumberGenerator.Create() )
    {
        salt = new byte[saltSize];

        // create the salt
        rng.GetBytes(salt);

        using( var pbkdf2 = new Rfc2898DeriveBytes(Encoding.UTF8.GetBytes(password), salt, iterations) )
            return pbkdf2.GetBytes(keySize);
     }
}

Note that the number of iterations should be AT LEAST 1,000. When the specification was first published in 2000, the initial recommended number of iterations was 1,000, and that number was expected to increase as CPU power increased. iOS currently uses 10,000 iterations, and a number in that range (or even higher!) would be a good idea. The number of iterations should be stored along with the resulting hash in the user table so that this parameter can be altered in the future to increase security without invalidating previously-stored password hashes.