Hash passwords in ASP.NET Core Or Dotnet
Hello guys, Welcome...
In this blog, we will learn how to create a Hashed password that can only be verified and cannot be cracked.
For this functionality, we will separately create a class with some method that will convert normal text into a specified password.
Firstly, Let's have a class named as SecurePasswordHasher with two constants as below.
public static class SecurePasswordHasher { private const int SaltSize = 16; private const int HashSize = 20; //code }
- What are SaltSize and HashSize?
SaltSize is basically a byte array size type by which an array of bytes create and by combining both Sizes password hashing takes place.
Now We will create a function or a method that will hash the password.
public static class SecurePasswordHasher { private const int SaltSize = 16; private const int HashSize = 20; public static string Hash(string password, int iterations) { // Create a salt using (var rng = new RNGCryptoServiceProvider()) { byte[] salt; rng.GetBytes(salt = new byte[SaltSize]); using (var pbkdf2 = new Rfc2898DeriveBytes(password, salt, iterations)) { var hash = pbkdf2.GetBytes(HashSize); // Combine salt and hash var hashBytes = new byte[SaltSize + HashSize]; Array.Copy(salt, 0, hashBytes, 0, SaltSize); Array.Copy(hash, 0, hashBytes, SaltSize, HashSize); // Convert to base64 var base64Hash = Convert.ToBase64String(hashBytes); // Format hash with extra information return $"$ANYCode|V1${iterations}${base64Hash}"; } } } }
After Creating the hash code we will store it in the database and all fine but when we have to verify we have to use another function.
public static bool IsHashSupported(string hashString) { return hashString.Contains("ANYCode|V1$"); } public static bool Verify(string password, string hashedPassword) { // Check hash if (!IsHashSupported(hashedPassword)) { throw new NotSupportedException("The hashtype is not supported"); } // Extract iteration and Base64 string var splittedHashString = hashedPassword.Replace("$ANYCode|V1$", "").Split('$'); var iterations = int.Parse(splittedHashString[0]); var base64Hash = splittedHashString[1]; // Get hash bytes var hashBytes = Convert.FromBase64String(base64Hash); // Get salt var salt = new byte[SaltSize]; Array.Copy(hashBytes, 0, salt, 0, SaltSize); // Create hash with given salt using (var pbkdf2 = new Rfc2898DeriveBytes(password, salt, iterations)) { byte[] hash = pbkdf2.GetBytes(HashSize); // Get result for (var i = 0; i < HashSize; i++) { if (hashBytes[i + SaltSize] != hash[i]) { return false; } } return true; } }
After both of the methods are completed, we are now ready to go, But we will use a Simple function in any call as we can have some type of control on the number of iterations in hashing as below.
public static string Hash(string password) { return Hash(password, 10000); }
Let's see the total class at a time:
public static class SecurePasswordHasher { private const int SaltSize = 16; private const int HashSize = 20; public static string Hash(string password, int iterations) { // Create a salt using (var rng = new RNGCryptoServiceProvider()) { byte[] salt; rng.GetBytes(salt = new byte[SaltSize]); using (var pbkdf2 = new Rfc2898DeriveBytes(password, salt, iterations)) { var hash = pbkdf2.GetBytes(HashSize); // Combine salt and hash var hashBytes = new byte[SaltSize + HashSize]; Array.Copy(salt, 0, hashBytes, 0, SaltSize); Array.Copy(hash, 0, hashBytes, SaltSize, HashSize); // Convert to base64 var base64Hash = Convert.ToBase64String(hashBytes); // Format hash with extra information return $"$ANYCode|V1${iterations}${base64Hash}"; } } } public static string Hash(string password) { return Hash(password, 10000); } public static bool IsHashSupported(string hashString) { return hashString.Contains("ANYCode|V1$"); } public static bool Verify(string password, string hashedPassword) { // Check hash if (!IsHashSupported(hashedPassword)) { throw new NotSupportedException("The hashtype is not supported"); } // Extract iteration and Base64 string var splittedHashString = hashedPassword.Replace("$ANYCode|V1$", "").Split('$'); var iterations = int.Parse(splittedHashString[0]); var base64Hash = splittedHashString[1]; // Get hash bytes var hashBytes = Convert.FromBase64String(base64Hash); // Get salt var salt = new byte[SaltSize]; Array.Copy(hashBytes, 0, salt, 0, SaltSize); // Create hash with given salt using (var pbkdf2 = new Rfc2898DeriveBytes(password, salt, iterations)) { byte[] hash = pbkdf2.GetBytes(HashSize); // Get result for (var i = 0; i < HashSize; i++) { if (hashBytes[i + SaltSize] != hash[i]) { return false; } } return true; } } }
As we created class now its time to know how to use them :
//to encript=> var hashcode= SecurePasswordHasher.Hash(inputs.password) //to verify=> SecurePasswordHasher.Verify(inputs.password, hashcode)
Thank you...