Salted Hash

In cryptography, a salt is random data that is used as an additional input to a one-way function that “hashesdata, a password or passphrase. Salts are closely related to the concept of nonce. The primary function of salts is to defend against dictionary attacks or against its hashed equivalent, a pre-computed rainbow table attack.

This can be visually demonstrated as:

Salted Hash

Cool, how do we do this in code?

Updated 24/04/2022

HMACSHA512

The salt string can be passed as the users email if you are lazy but its better to generate your own byte array.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class EncryptionService
{
public string Encrypt(string password)
{
var key = new byte[32];
var buffer = Encoding.UTF8.GetBytes(password);
var bytes = new HMACSHA512(key).ComputeHash(buffer);

return Convert.ToBase64String(bytes);
}

public string Encrypt(string password, byte[] key)
{
var buffer = Encoding.UTF8.GetBytes(password);
var bytes = new HMACSHA512(key).ComputeHash(buffer);

return Convert.ToBase64String(bytes);
}

public string Encrypt(string password, string salt)
{
var saltBytes = Encoding.ASCII.GetBytes(salt);
var value = Encoding.UTF8.GetBytes(password);
var key = value.Concat(saltBytes).ToArray();

var buffer = Encoding.UTF8.GetBytes(password);
var bytes = new HMACSHA512(key).ComputeHash(buffer);

return Convert.ToBase64String(bytes);
}
}

MD5

MD5 is considered deprecated

Consider the following username and password:

1
2
var email = "foo@domain.com";
var password = "qwerty";

The password value needs to be hashed and then persisted to the database.

  1. Create the salt by getting the byte array values of the email, the assumption would be that an email address is unique.

You can SHOULD create a random byte array for the salt using RNGCryptoServiceProvider. You would then need to persist that byte array to the database and use it in your user authentication challenge routine. The use of email here is just a dirty example.

1
var salt = Encoding.ASCII.GetBytes(email);
  1. Create a byte array of the password and concatenate the two into one byte array
1
2
var value = Encoding.UTF8.GetBytes(password);
var saltedValue = value.Concat(salt).ToArray();
  1. Create a MD5 hash from the ‘salted value’
1
2
3
4
// need MD5 to calculate the hash
byte[] hashedBytes = ((HashAlgorithm)CryptoConfig
.CreateFromName("MD5"))
.ComputeHash(saltedValue);
  1. Encode and to string the hash. You can also use Convert.ToBase64String(hashedBytes);
1
2
3
4
// string representation (similar to UNIX format)
var encoded = BitConverter.ToString(hashedBytes)
.Replace("-", string.Empty)
.ToLower();

This would then result in a value of A9419D55933FBCF43BA46087F8F20B22

References