Home / Cryptography / Password Storage

Password Storage

Using Hashes to Store Passwords

A common usage scenario for hashes is to encode passwords for storing in a database. With the rise of modern processors and graphical processing units (GPUs), it is not recommended you take this approach as hashes can be brute force attacked or attacked by using rainbow tables.

A much better strategy would be to boost the entropy of the password being attacked by making it harder to recover. This can be done by adding a salt onto the password before hashing.

Note that a rainbow table contains precomputed hashes for different combinations of messages. These tables are used to get the original plaintext from an already computed hash value.

A random number can be generated as salt and then attached on the password before hashing. In the following code, we have a hash class containing everything we need to do this. This has the hash function itself, the salt generator, and a method to combine two byte arrays together.

public class Hash

{

public static byte[] HashPass(byte[] intoHash, byte[] salt)

{

using (var hash256 = SHA256.Create())

{

return hash256.ComputeHash(Combine(intoHash, salt));

}

}

private static byte[] Combine(byte[] first, byte[] second)

{

var value = new byte[first.Length + second.Length];

Buffer.BlockCopy(first, 0, value , 0, first.Length);

Buffer.BlockCopy(second, 0, value , first.Length, second.Length);

return value;

}

public static byte[] GenSalt()

{

const int SALT_LENGTH = 32;

using (var rNumGen = new RNGCryptoServiceProvider())

{

var rNum = new byte[SALT_LENGTH];

rNumGen.GetBytes(rNum);

return rNum;

}

}

}

To use the preceding code example to salt and hash a password, we use the following code.

class Example

{

static void Main(string[] args)

{

var pass = “KS#2wD%%S&i3@#WSD*3SA##QEDS%A12”;

byte[] salt = Hash.GenerateSalt();

Console.WriteLine(“Hash Password with Salt Demonstration in .NET”);

Console.WriteLine(“–––––––––––––––”);

Console.WriteLine();

Console.WriteLine(“Original Message 1 : ” + password);

Console.WriteLine(“Salt = ” + Convert.ToBase64String(salt));

Console.WriteLine();

var hashedPass = Hash.HashPasswordWithSalt(

Encoding.UTF8.GetBytes(pass),

salt);

Console.WriteLine();

Console.WriteLine(“Hashed Password = ” +

Convert.ToBase64String(hashedPass));

Console.WriteLine();

Console.ReadLine();

}

}

In this example, the salt value is combined with the password and then hashed by using SHA-256. When you store the password in the database, you also store the salt value. The salt does not need to be secret; it is there to add entropy to the password to make it harder to brute force attack or attack by using a rainbow table.

This solution for storing a password is much better than just storing a hashed pass but it is still susceptible to brute force attacks as processor speeds scale with Moore’s law. A stored hashed and salted password may be safe today but, in five years, it might be a trivial job to crack it.

A better solution is to use a password-based key derivation function to hash and store your password.

Password-based Key Derivation Functions

As we just mentioned, the issue with hashing and storing a password is that as processors get faster through the years, we run the risk of what we currently believe are safe passwords being compromised because processors can use brute force attacks and rainbow table attacks faster. What we need is a solution that allows us to still hash our passwords but helps us guard against advancements in Moore’s law.

A password-based key derivation function, or PBKDF2 as it is also known, is part of the RSA Public Key Cryptographic Standards series (PKCS #5 version 2.0). A password-based key derivation function takes a password, a salt to add additional entropy to the password, and a number of iterations value. The number of iterations value repeats a hash or encryption cipher over the password multiple times to produce a derived key for the password that can be stored in a database or used as an encryption key.

You are algorithmically slowing down the hashing process by repeating a hash process over the password numerous times which makes brute force attacks against the password significantly harder. This means that less passwords can be tested at once. As processors get faster over time, you might increase the number of iterations used to create the new password, which means a password-based key derivation function can scale with Moore’s law. A good default to start with for the number of iterations is around 50,000.

By adding a salt to the derivation function, you further decrease the ability of a rainbow table to be used to recuperate the original password. A good minimum length for your salt is at least 64 bits (8 bytes). The following code demonstrates how to hash a password with Rfc2898DeriveBytes.

public class PBKDF2

{

public static byte[] GenerateSalt()

{

using (var rNumGen = new RNGCryptoServiceProvider())

{

var rNum = new byte[32];

rNumGen.GetBytes(rNum);

return rNum;

}

}

public static byte[] HashPass(byte[] intoHash, byte[] salt, int

numOfRounds)

{

using (var RFC2898 = new Rfc2898DeriveBytes(intoHash, salt,

numOfRounds))

{

return RFC2898.GetBytes(32);

}

}

}


Once Rfc2898DeriveBytes has been instantiated, you then call GetBytes() to retrieve the number of bytes you want to represent the hashed password. In the previous example, we get 32 bytes (256 bits) of data for our password. I don’t recommend using less, but you can use more. This depends on how many passwords you have to store and the amount of storage you want to use.

In the following code, I demonstrate the usage of the PBKDF2 class created in the preceding example. The example calculates multiple hashes, with varying numbers of rounds being used. Each hashed password is timed so that you can see the impact of increasing the number of iterations.

class Example

{

static void Main(string[] args)

{

var passToHash = “SomeRandomPassword”;

Console.WriteLine(“Password Based Key Derivation Function Demonstration in

.NET”);

Console.WriteLine(“––––––––––––––––––––”);

Console.WriteLine();

Console.WriteLine(“PBKDF2 Hashes”);

Console.WriteLine();

HashPassword(passToHash, 100);

HashPassword(passToHash, 1000);

HashPassword(passToHash, 10000);

HashPassword(passToHash, 50000);

HashPassword(passToHash, 100000);

HashPassword(passToHash, 200000);

HashPassword(passToHash, 500000);

Console.ReadLine();

}

private static void HashPass(string passToHash, int

numOfRounds)

{

var sWatch = new Stopwatch();

sWatch.Start();

var hashedPass =

PBKDF2.HashPass(Encoding.UTF8.GetBytes(passToHash),

PBKDF2.GenerateSalt(),

numberOfRounds);

sw.Stop();

Console.WriteLine();

Console.WriteLine(“Password to hash : ” + passToHash);

Console.WriteLine(“Hashed Password : ” +

Convert.ToBase64String(hashedPass));

Console.WriteLine(“Iterations ” + numOfRounds + ” Elapsed Time : ” +

sw.ElapsedMilliseconds + “ms”) ;

}

}

 

Check Also

digital signature

Digital Signature

An essential purpose of cryptography would be  to ensure nonrepudiation of a delivered message. This …

Leave a Reply

Your email address will not be published. Required fields are marked *