Properly storing password (Hashing and Salting)

Passwords should never have been stored as plain text, but they were and when databases were compromised there was no protection. Then again people shouldn’t reused passwords but they do, all the time. However with services like LastPass, 1Password and iCloud keychain hopefully people will start to shift away from reusing simple passwords. Regardless we as developers should err on the side of caution and always ensure that when we store passwords it’s in a way that prevents anyone who would happen to get them to use them maliciously.

The simplest and recommended way to do this is by cryptographically hashing the passwords before storing it. Hashing is the action of taking a message of variable length and computing a fixed length representation of the message, while also ensuring that every message only generates one hash. A cryptographic hash has four main properties that benefit it’s use as a method to secure passwords.  The hash value for any given message is easy to compute, while being infeasible to generate a message that has a given hash, infeasible to modify a message without changing the hash, and infeasible to find two different messages with the same hash.

It should also be noted that it is generally unfeasible to reverse a hash, I say unfeasible as given enough time and computational power you could employ a dictionary attack or pre-computed rainbow tableattack.  Both these methods however can be mitigated by salting, salting is the process of adding random data to password before it’s hashed.  A new salt is randomly generated each time and is stored with the hashed password in a database.

Now lets look at how to implement this, starting by the hashing function itself.


private static byte[] Hasher(string password, byte[] salt, int iterations, int length)
{
   Rfc2898DeriveBytes pbkdf2 = new Rfc2898DeriveBytes(password, salt, iterations);
   return pbkdf2.GetBytes(length);
}
								

The inputs to the function are:

  • password: The users unencrypted password
  • salt: The random data we will be generating and storing with the hash
  • iterations: the number of times the function should run, the idea being more iterations the stronger the hash becomes.
  • length: how long do you want the hash to be in bytes

The function starts by initializing an instance of Rfc2898DeriveBytes named PBKDF2 (Password-Based Key Derivation Function 2) with the password, salt and number of iterations. This will generate the hash, finally the function returns the hash.

Now that we have our private hashing function lets create two a public functions one to create the hash another to verify it.

First lets create some constants as no one likes magic numbers


public const int SALT_BYTE_SIZE = 24;
public const int HASH_BYTE_SIZE = 24;
public const int ITERATIONS = 20000;
								

To keep is easy we will create salts and hashes with a length of 24 bytes and lets set the iterations to 20000, always benchmark your server you want to keep the iterations high but not so high that users have to wait for minutes while you check their password.


public static string CreateHash(string password)
{
   RNGCryptoServiceProvider csprng = new RNGCryptoServiceProvider();
   byte[] salt = new byte[SALT_BYTE_SIZE];
   csprng.GetBytes(salt);
   byte[] hash = Hasher(password, salt, ITERATIONS, HASH_BYTE_SIZE);
   return Convert.ToBase64String(hash) + ":" + Convert.ToBase64String(salt);
}
								

The first line create a cryptographic Random Number Generator in this case CSPRNG (cryptographically secure pseudo-random number generator). The second a byte variable to hold the salt and the third fills the salt with random bytes from the number generator.

Now that we have the password and a salt we can call Hasher function and generate our hash and return the hash and salt.


public static bool Validate(string password, byte[] hash, byte[] salt )
{
   byte[] testHash = Hasher(password, salt, ITERATIONS, HASH_BYTE_SIZE);
   uint diff = (uint)hash.Length ^ (uint)testHash.Length;
   for (int i = 0; i < hash.Length && i < testHash.Length; i++)
      diff |= (uint)(hash[i] ^ testHash [i]);
   return diff == 0;
}
								

To validate a password we need the password from the user, and the hash and salt from the database passed into the Validate function, the first line of the function then creates a testHash using the password entered by the user, and the same salt that was used to create the original hash, if the salt has been modified then the hashes will not match even if the correct password is entered.

Once the testHash has been created we start checking if both hashes have the same length using a bitwise exclusive-OR.  Once we know the hashes are the same length we step through them comparing byte to byte using an bitwise exclusive-OR and setting diff using OR assignment that way if a single byte is different the function will return false.

And there you have it, simple secure password protection.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s