Generate a Random Salt. Use a new salt each time a hash is computed.
public static byte[] GenerateSalt()
{
byte[] salt = new byte[16];
new RNGCryptoServiceProvider().GetBytes(salt);
return salt;
}
hash a password with a salt into a Base64 string for storing into a database (or wherever)
public static String HashPassword(string password, byte[] salt)
{
var hasher = new Rfc2898DeriveBytes(password, salt, 10000);
byte[] hash = hasher.GetBytes(20);
byte[] hashBytes = new byte[36];
Array.Copy(salt, 0, hashBytes, 0, 16);
Array.Copy(hash, 0, hashBytes, 16, 20);
return Convert.ToBase64String(hashBytes);
}
Verify that a password matches a hash. You could alternatively also use HashPassword() with the same salt stored elsewhere or from other data and compare the output. This uses the Salt present in the original Hash and checks if the provided password matches instead:
public static bool VerifyPassword(String password,String StoredHash)
{
byte[] hashBytes = Convert.FromBase64String(StoredHash);
byte[] salt = new byte[16];
Array.Copy(hashBytes, 0, salt, 0, 16);
var hasher = new Rfc2898DeriveBytes(password, salt, 10000);
byte[] hash = pbkdf2.GetBytes(20);
for (int i = 0; i < 20; i++)
if (hashBytes[i + 16] != hash[i])
return false;
return true;
}