Needed nuget packages :
- Microsoft.AspNetCore.Cryptography.KeyDerivation
Needed Namespaces :
- using Microsoft.AspNetCore.Cryptography.KeyDerivation;
- using System;
- using System.Security.Cryptography;
There are two functions :
- HashPassword : This function accepts three parameters:
- password : Password to hash
- salt : the custom salt of 16 byte length
- needsOnlyHash : If you don’t want to return salt with hash
- VerifyPassword : This function accepts two parameters:
- hashedPasswordWithSalt : Password and salt in format hasedPassword:salt
- passwordToCheck: The password that is to be checked for correctness.
The HashPassword function returns the result in format :
hasedPassword:salt Or hasedPassword
private string HashPassword(string password, byte[] salt = null, bool needsOnlyHash = false)
{
if (salt == null || salt.Length != 16)
{
// generate a 128-bit salt using a secure PRNG
salt = new byte[128 / 8];
using (var rng = RandomNumberGenerator.Create())
{
rng.GetBytes(salt);
}
}
string hashed = Convert.ToBase64String(KeyDerivation.Pbkdf2(
password: password,
salt: salt,
prf: KeyDerivationPrf.HMACSHA256,
iterationCount: 10000,
numBytesRequested: 256 / 8));
if (needsOnlyHash) return hashed;
// password will be concatenated with salt using ':'
return $"{hashed}:{Convert.ToBase64String(salt)}";
}
private bool VerifyPassword(string hashedPasswordWithSalt, string passwordToCheck)
{
// retrieve both salt and password from 'hashedPasswordWithSalt'
var passwordAndHash = hashedPasswordWithSalt.Split(':');
if (passwordAndHash == null || passwordAndHash.Length != 2)
return false;
var salt = Convert.FromBase64String(passwordAndHash[1]);
if (salt == null)
return false;
// hash the given password
var hashOfpasswordToCheck = HashPassword(passwordToCheck, salt, true);
// compare both hashes
if (String.Compare(passwordAndHash[0], hashOfpasswordToCheck) == 0)
{
return true;
}
return false;
}