Hash It Right: Implementing PBKDF2 in .NET

Computer Password Security

Following on the heels of my last post User Account Security Using Password Based KDF’s regarding password security utilizing a password-based key derivation function, I wanted to put a post together that illustrated the use of the password-based key derivation function PBKDF2 in .NET.

Rfc2898DerivedBytes is a class that implements the PBKDF2 key derivation function and is available from the System.Security.Cryptography library in .NET.  There are other password-based key derivation functions such as BCrypt that I won’t be demonstrating here but you can find additional information about here.

As it was pointed out in the related post, having a good hashing algorithm is no longer sufficient security for security of passwords due to the processing power of hardware that is available to today’s attackers.  Therefore, utilization of a PBKDF’s and its iteration count to slow the hashing process, we can help impede an attacker’s ability to gain access.  But if we keep Moore’s Law in mind we should be mindful of what an attacker might not be able to do today, they will be able to do tomorrow.

To be more precise, allot of numbers are thrown out there for what the iteration count should be for a PBKDF.  A numerical range for the iteration count can fluctuate from who you talk to, but ranges from 12,000 – 32,000.  It really comes down to striking a balance between an attackers patience and a legitimate user’s experience.

 The iteration count is the number of times the algorithm is going to iterate through the algorithm, slowing the hashing process by that factor.  The attacker is directly affected by the deliberate slowness of a password-based key derivation function

So back to Moore’s Law, 12,000 might be enough today, but what will be the required iteration count in 2, 4, 6 years from now (or at which time we might not be using passwords as pointed out by Russell Brandon)?  A hashed password at 1000x is not the same as 12000x even with the same salt and derived key length.  So, if you know that most likely the iteration count today might not be enough tomorrow, we should have some way to adjust over time.  We can accomplish this through the use of versioning so that we can move forward and maintain backwards compatibility.

Objectives

The intention of this article is to give you an example of implementing the PBKDF2 function in a .NET application with the use of the Rfc2898DerivedBytes System.Security.Cryptography library.   As an overview, we need be able to perform the following tasks:

  1. Hash a new password
  2. Verify a proposed password guess

 

These can be further broken down:

 Hash a new password

  1.  Generating the unique random salt
  2.  Obtaining the current iteration count
  3.  Hashing the users password
  4.  Saving all 3 pieces of data (salt, iteration count, hashed password)

 

Verify a proposed password guess

  1. Disassemble the saved data value into the 3 parts (salt, iteration count, hashed password)
  2. Hash proposed password guess with the correct salt and iteration count
  3. Compare results with correct password hash

 

Implementation

So now that we know what we are setting out to do, let’s get started looking at some code.  First off we have a summarizing method that encapsulates the entire process of hashing a valid password and constructing a data object to be persisted.

 

public string CreatePasswordHash(string password)
{
    var salt = GenerateRandomSalt();
    var iterationCount = GetIterationCount();
    var hashValue = GenerateHashValue(password, salt, iterationCount);
    var iterationCountBtyeArr = BitConverter.GetBytes(iterationCount);
    var valueToSave = new byte[SaltByteLength + DerivedKeyLength + iterationCountBtyeArr.Length];
    Buffer.BlockCopy(salt, 0, valueToSave, 0, SaltByteLength);
    Buffer.BlockCopy(hashValue, 0, valueToSave, SaltByteLength, DerivedKeyLength);
    Buffer.BlockCopy(iterationCountBtyeArr, 0, valueToSave, salt.Length + hashValue.Length, iterationCountBtyeArr.Length);
    return Convert.ToBase64String(valueToSave);
}

 

 

We are simply generating the salt, getting the current iteration count, asking for the password hash, concatenating all 3 pieces of data together into a single byte array and finally returning the string equivalent of that byte array.

Throughout the code you will see a few references to some constant class members

private const int SaltByteLength = 24;
private const int DerivedKeyLength = 24;

 

These define the size of our salt in bytes (keeping in range of the recommended size of 128-192 bits) and the size of the outputted hash of the password.

So so breaking this core function down, let’s next look at how we are generating the salt:

private static byte[] GenerateRandomSalt()
{
   var csprng = new RNGCryptoServiceProvider();
   var salt = new byte[SaltByteLength];
   csprng.GetBytes(salt);
   return salt;
}

 

We are using the RNGCryptoServiceProvider class to create a Cryptography Secure Pseudo-Random Number Generator that will generate the level of randomness and uniqueness we require for a salt.   This returns the byte array we need as our salt ingredient.

Moving on, we are acquiring the iteration count that our application is currently using.  The Iteration Count can be pulled from any number of sources such as an application configuration, passed in through your friendly neighborhood IoC or another source.  But I mentioned earlier about tracking the iteration count, we will see how we will do this momentarily.  The bottom line is that GetIterationCount() is simply a method that returns and integer (24000) and is here strictly to represent whatever option you use to provide the current iteration count your application is using.

Now having the salt, the iteration count and the password we want hashed, we have the 3 ingredients and can now proceed to utilize the PBKDF2 function to provide us a hash of that password.

 

private static byte[] GenerateHashValue(string password, byte[] salt, int iterationCount)
{
    byte[] hashValue;
    var valueToHash = string.IsNullOrEmpty(password) ? string.Empty : password;
    using (var pbkdf2 = new Rfc2898DeriveBytes(valueToHash, salt, iterationCount))
    {
        hashValue = pbkdf2.GetBytes(DerivedKeyLength);
    }
    return hashValue;
}

 

We ensure that we are passing something in as the password we want to hash as it won’t throw an exception on an empty string, but it will if the password parameter is null.  Also, the Rfc2898DerivedBytes class implements the IDispose interface, so we need to wrap the instantiation of this class with a using directive in order to help with resource cleanup.  Finally we can pass the desired size of our hash to the GetBytes function on our Rfc2898DerivedBytes instance which will return a byte array of our hashed password.

I should note that the Rfc2898DerivedBytes has a couple different constructors and will also generate the salt for you.  I wanted to demonstrate the use of a CSPRNG for you, so I opted to supply my own.

Password’s Hashed, Now What?

If you look back at the main function that encapsulates all the work we just expounded on, you should have noticed that we are returning a string, but at this point we only have a byte array.  The second half of this function is the second step of which we want to construct the value we will actually save.

In order to be able to verify a password guess that is submitted against the actual saved password, we need to be able to run the submitted password guess through this process using the same hash and iteration count that was used with the correct password in order to verify whether it is correct.  So we are going to construct a byte array that contains all three ingredients (salt, iteration count and password) for the ability to do this.

But wait!  Did you just say you are going to save the salt and iteration count with the password?  Isn’t that like making 3 of the 4 numbers in your bank accounts pin number public knowledge?  Well, not quit.  Let me take a quick moment to explain:

Let’s first remember why we use salt.  Salt helps make constructing attacker tools such as rainbow, look-up and reverse tables harder if not, in a lot of cases, impossible  to use (If you need a refresher on the exact use and how salt impedes these tools, check out my post on User Account Security Using Password Based KDF’s).  Now, I will go onto say that its not frowned on to try and make these ingredients secret, but doing so can complicate a setup as well.   For example, if you find yourself attempting to use the same salt for all password hashing in order to hide the salt in a config file or source code, you will have just violated one of the first rules of using a salt – the importance of using a unique and random salt per password hash.  And observing the Kerckhoffs’s principle your supposedly hidden salt is mostly likely not all that hidden.

var iterationCountBtyeArr = BitConverter.GetBytes(iterationCount);
var valueToSave = new byte[SaltByteLength + DerivedKeyLength + iterationCountBtyeArr.Length];
Buffer.BlockCopy(salt, 0, valueToSave, 0, SaltByteLength);
Buffer.BlockCopy(hashValue, 0, valueToSave, SaltByteLength, DerivedKeyLength);
Buffer.BlockCopy(iterationCountBtyeArr, 0, valueToSave, salt.Length + hashValue.Length, iterationCountBtyeArr.Length);

 

So let’s construct an object that we can save with these ingredients.    There are a couple ways we can do this, but here we are just going to utilize the static class Buffer and its BlockCopy function to copy the contents of our individual byte arrays into a single byte array.   Since our salt and hashed password is a byte arrays, we convert the integer iterationCount to a byte array in order to initialize the valueToSave byte array to the correct size.  From here we start copying the salt, hashValue and iterationCountByteArr into the valueToSave.

We mentioned in the introduction that today’s iteration count might not be sufficient tomorrow and he importance of incorporated a way to version or track the iteration count used per password.  Here we are going to save the iteration count with the salt and password hash so we can do two things:

  1. Properly construct a matching hash when the correct password is submitted
  2. Be able to easily update the iteration count without affecting all passwords across the board.

 

Let me take a moment and elaborate on how this fits into the big picture.  Today you are hashing your passwords with an iteration count of 12,000, but 2 years from now, we should be hashing with an iteration count of 24,000.  By saving this data with the persisted string, you have the ability to automatically make this adjustment per account when they, for example, request a password change, forget their password, after logging in successfully or a new account is created using the latest version.

Instead of saving the iteration count as we have, another suggestion would be to save a version number that maps to the iteration count integer stored in your application or storage

Finally, we return a string representation of the valueToSave byte array using ToBase64String function off of the static Convert class.  This string can be saved in your application’s storage of choice.

return Convert.ToBase64String(valueToSave);

 

Verifying a Password Guess

So Mr. Smith returns to your application to login, we need a way to verify their password guess.

 

public static bool VerifyPassword(string passwordGuess, string actualSavedHashResults)
{
    //ingredient #1: password salt byte array
    var salt = new byte[SaltByteLength];
    
    //ingredient #2: byte array of password
    var actualPasswordByteArr = new byte[DerivedKeyLength];
    
    //convert actualSavedHashResults to byte array
    var actualSavedHashResultsBtyeArr = Convert.FromBase64String(actualSavedHashResults);
   
    //ingredient #3: iteration count
    var iterationCountLength = actualSavedHashResultsBtyeArr.Length - (salt.Length + actualPasswordByteArr.Length);
    var iterationCountByteArr = new byte[iterationCountLength];
    Buffer.BlockCopy(actualSavedHashResultsBtyeArr, 0, salt, 0, SaltByteLength);
    Buffer.BlockCopy(actualSavedHashResultsBtyeArr, SaltByteLength, actualPasswordByteArr, 0, actualPasswordByteArr.Length);
    Buffer.BlockCopy(actualSavedHashResultsBtyeArr, (salt.Length + actualPasswordByteArr.Length), iterationCountByteArr, 0, iterationCountLength);
    var passwordGuessByteArr = GenerateHashValue(passwordGuess, salt, BitConverter.ToInt32(iterationCountByteArr, 0));
    return ConstantTimeComparison(passwordGuessByteArr, actualPasswordByteArr);
}

 

The overview of this function is to construct the byte arrays for holding the salt, password hash and iteration count.  Then convert the saved data string from a string to a byte array.  Followed by, copying each appropriate part of the actualSavedHashResultsByteArr into the appropriate btye array, constructing a hash of the submitted password guess and finally, comparing the correct password with the password guess.  This obviously requires ensuring the actualSavedHashResultsByteArr is deconstructed the same way it was constructed. To be more precise, the first 24 bytes is the salt, the second 24 bytes is the actual password hash, followed by the last 4 bytes being the iteration count.

Once we have all the ingredients required, we will retrieve a hash of the submitted password guess by passing the salt, iteration count and the submitted password guess to our same GenerateHashValue function.  You will notice that we are utilizing the static BitConverter class’ ToInt32 function to convert our iteration count byte array to an integer.

Finally, we will send both the actualPasswordByteArr and the passwordGuessByteArr to the ConstantTimeComparison function which is borrowed from crackstation.net.

 

private static bool ConstantTimeComparison(byte[] passwordGuess, byte[] actualPassword)
{
    uint difference = (uint) passwordGuess.Length ^ (uint) actualPassword.Length;
    for (var i = 0; i < passwordGuess.Length && i < actualPassword.Length; i++)
    {
        difference |= (uint)(passwordGuess[i] ^ actualPassword[i]);
    }
    
    return difference == 0;
}

 

It’s been mentioned before about the need to avoid inadvertently leaking information to an attacker.  We have seen this through typical string comparison where a fail early mentality is implemented when comparing hashes.  Again you can read more here.  In order to try and avoid giving any information away about what the correct password hash is, we want to ensure we iterate through the entire submitted password guess when validating.

For those of you with a keen eye, you might have recalled that one of the points of a hash algorithm is to map arbitrary data to a fixed size hash value.  You might be wondering why the need to verify the actual password’s length since a value of “A” and “AAAAA” hashed with sha-256 algorithm and a derived key of 24 bytes renders you the same sized hash value.  This is simply a defense programming measure in case there is a situation where the values would come in different that wasn’t accounted for and ensuring we validate to the length of the provided password guess in order not to divulge any information about the correct password hash.  But based on your individual scenario, this might not be required and can be removed.  I have left it here for the sake of making a point.

The meat of this function is in the for loop which is computing the bitwise exclusive-OR of each byte in the current array index.  Without going into the underpinnings, understand that with the exclusive or (XOR), we are essentially asking the question “are you not equal” on each byte.  It will return 1 if that the answer is true (not equal) or 0 if false (they are equal) – yes, you might need to read that twice  If you iterate through all bytes and the resulting passwordMatch variable is 0, then indeed the provided password guess is equal.

Summary

So we have concluded implementing the PBKDF2 function with the Rfc2898DerivedBytes class as well as implementing a cryptography secure pseudo-random number generator for generating a salt with the RNGCryptoServiceProvider class.  How to version or track the iteration count used for the PBKDF2 function for the ability to update it without application wide implications.  Followed by how we can construct a hash from the submitted password guess by deconstructing the persisted data and hashing the password guess with the same ingredients.  And finally, how to safely compare the two hashes.

[headline tag=”div” css_class=”h1″ color=”color2″]But Wait! There’s More![/headline]

If you are examining the use the PBKDF2 function in a .NET application, you might not need to go through implementing your own implementation. Stay tuned for my next post which looks at how the SimpleMembershipProvider in .NET might be exactly what you are looking for.

 

 

Hash It Right:  Implementing PBKDF2 in .NET  appeared first here on LockMeDown.com

 

 

About the author

Max McCarty

Max McCarty is a software developer with a passion for breathing life into big ideas. He is the founder and owner of LockMeDown.com and host of the popular Lock Me Down podcast.