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...

Sign In or Register to comment.