uses SHA-256.
First off, to do a MD5 hash we can use the following :
static string Md5(string input){
using (var md5 = MD5.Create()){
var byteHash = md5.ComputeHash(Encoding.UTF8.GetBytes(input));
var hash = BitConverter.ToString(byteHash).Replace("-", "");
return hash;
}
}
And to test it out we can run the following:
void Md5Demo()
{
string inputPassword = "abc123";
string md5Hash = Md5(inputPassword);
Console.WriteLine("MD5 Demonstration in .NET");
Console.WriteLine("-------------------------");
Console.WriteLine($"Password to hash: {inputPassword}");
Console.WriteLine($"MD5 hashed password: {md5Hash}");
Console.WriteLine();
}
MD5 Demonstration in .NET
-------------------------
Password to hash: abc123
MD5 hashed password: E99A18C428CB38D5F260853678922E03
The MD5 hash above agrees with the online MD5 hash here:
https://www.md5hashgenerator.com/
MD5 method here does not mention any salt, but this could be concatenated with the password to prevent against rainbow table attacks, that is
dictionary attacks.
Next, to perform PDKDF2 hashing, the code below can be used. Note that this algorithm will be run iteratively to generate a hash value that is
increasingly more computationally expensive to calculate the hash of compared to the number of iterations and includes a salt, making it scalable to be more and more difficult for attacks.
static byte[] _salt = RandomNumberGenerator.GetBytes(32);
static void HashPassword(string passwordToHash, int numberOfRounds)
{
var sw = Stopwatch.StartNew();
var hashedPassword = Rfc2898DeriveBytes.Pbkdf2(
passwordToHash,
_salt,
numberOfRounds,
HashAlgorithmName.SHA256,
32);
sw.Stop();
Console.WriteLine();
Console.WriteLine("Password to hash : " + passwordToHash);
Console.WriteLine("Hashed Password : " + Convert.ToBase64String(hashedPassword));
Console.WriteLine("Iterations < " + numberOfRounds + "> Elapsed Time: " + sw.ElapsedMilliseconds + " ms");
}
The value 32 here is the desired output length of the hash, we can decide how long the hash we get out of the call to the method.
We can then test out the Pbkdf2 method using an increasing number of iterations.
void RunPbkdf2HashDemo()
{
const string passwordToHash = "abc123";
Console.WriteLine("Password Based Key Derivation Function Demonstration in .NET");
Console.WriteLine("------------------------------------------------------------");
Console.WriteLine();
Console.WriteLine("PBKDF2 Hashes using Rfc2898DeriveBytes");
Console.WriteLine();
HashPassword(passwordToHash, 1);
HashPassword(passwordToHash, 10);
HashPassword(passwordToHash, 100);
HashPassword(passwordToHash, 1000);
HashPassword(passwordToHash, 10000);
HashPassword(passwordToHash, 100000);
HashPassword(passwordToHash, 1000000);
HashPassword(passwordToHash, 5000000);
}
This gives the following output:
Password Based Key Derivation Function Demonstration in .NET
------------------------------------------------------------
PBKDF2 Hashes using Rfc2898DeriveBytes
Password to hash : abc123
Hashed Password : eqeul5z7l2dPrOo8WjH/oTt0RYHvlZ2lvk8SUoTjZq4=
Iterations (1) Elapsed Time: 0 ms
Password to hash : abc123
Hashed Password : wfd8qQobzBPZvdemqrtZczqctFe0JeAkKjU3IJ48cms=
Iterations (10) Elapsed Time: 0 ms
Password to hash : abc123
Hashed Password : VY45SxzhqjYronha0kt1mQx+JRDVlXj82prX3H7kjII=
Iterations (100) Elapsed Time: 0 ms
Password to hash : abc123
Hashed Password : B0LfHgRSslG/lWe7hbp4jb8dEqQ/bZwNtxsaqbVBZ2I=
Iterations (1000) Elapsed Time: 0 ms
Password to hash : abc123
Hashed Password : LAHwpS4bnbO7CQ1r7buYgUTrp10FyaRyeK6hCwGwv20=
Iterations (10000) Elapsed Time: 1 ms
Password to hash : abc123
Hashed Password : WDjyPySpULXtVOVmSR9cYlzAY4LWeJqDBhszKAfIaPc=
Iterations (100000) Elapsed Time: 13 ms
Password to hash : abc123
Hashed Password : sDx6sOrTl2b7cNZGUAecg7YO4Md/g3eAtfQSvh/vxpM=
Iterations (1000000) Elapsed Time: 127 ms
Password to hash : abc123
Hashed Password : ruywLaR0QApOU5bkqE/x2AAhYJzBj5y6D3P3IxlIF2I=
Iterations (5000000) Elapsed Time: 643 ms
Note that it takes many iterations before the computation takes significant time.
Sources / links :
- OWASP recommends using 600 000 iterations when using SHA256 as noted here: https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#pbkdf2
- Hashing passwords using PBKDF2 are explained by Stephen Haunts here: Hashing Passwords Safely using a Password Based Key Derivation Function (PBKDF2)