Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Key Strengthening. Am I Doing It Right?

I am writing a class to hash passwords which implements Key Stretching by using the System.Security.Cryptography.Rfc2898DeriveBytes class to generate the keys used to compute the hash value.

The code essentially does this:

// Higher iterations value results in better key strength
var db = new Rfc2898DeriveBytes(password + salt + secretKeyFromConfigFile,
                                saltAsBytes,
                                iterations);

byte[] hashKey = db.GetBytes(64); // 64 bytes is the recommended size for the HMACSHA512 class

var sha512 = new System.Security.Cryptography.HMACSHA512(hashKey);

byte[] hashInput = System.Text.Encoding.UTF8.GetBytes(password + salt + secretKeyFromConfigFile);

byte[] hash = sha512.ComputeHash(hashInput);

return System.Convert.ToBase64String(hash);

The documentation for System.Security.Cryptography.Rfc2898DeriveBytes indicates that it uses "... a pseudo-random number generator based on System.Security.Cryptography.HMACSHA1" to derive the key.

Since SHA512 is better than SHA1 Would it be better to simply apply the SHA512 hash function like so?

byte[] hash;

for (int i = 0; i < iterations; i++)
{
    hash = sha512.ComputeHash(hash ?? hashInput);
}

return System.Convert.ToBase64String(hash);

What is the difference between strengthening the key (as shown in the 1st code block) and strengthening the hash (as shown in the 2nd code block)?

What is the preferred method to do key stretching when hashing passwords?

like image 884
Rudy Avatar asked Mar 22 '11 13:03

Rudy


2 Answers

Unless you're a crypto guru, just stick to Rfc2898DeriveBytes which is very probably correctly implemented. Resist the temptation of hacking together a custom solution which will break the security of your system.

There's no reason to hash the output of Rfc2898DeriveBytes.

Directly use GetBytes(), it's been designed for that intent.

What's the purpose of your key stretching? Cipher or password hash? For a password hash, you probably want to use a different algorithm.

like image 190
Edouard A. Avatar answered Sep 24 '22 21:09

Edouard A.


This is pretty old, but I came across this when I was googling for the same question and the solution is indeed to stick to the output of Rfc2898DeriveBytes.

Rfc2898DeriveBytes is the .NET implementation of PBKDF2. It takes your password, a salt and the number of iterations. That is already the whole implementation and there is no need to rehash the outcome with another hashing algorithm.

In fact it is strongly advised to not create your own implementation around this, as you might break the security as other people already mentioned here.

That's what https://openid.stackexchange.com does as well, as you can see here: https://code.google.com/p/stackid/source/browse/OpenIdProvider/Current.cs#1135

like image 32
dustinmoris Avatar answered Sep 23 '22 21:09

dustinmoris