Password hash using PBKDF2 with HMAC SHA256/ SHA512 in .NET Framework 4.7.2 and .NET Core 2.0

Here I am back with more updates on PBKDF2 with HMAC but this time I am talking about SHA-2 family of hashes which includes SHA-256 and SHA-512, both that to in standard .NET framework.

I have posted another article for implementing PBKDF2 with SHA-2 family for password hashing which has custom implementation of PBKDF2 as at that time this option was not available in standard .NET framework.

Latest version (at the time of writing this article) of .NET framework that is 4.7.2 has introduced in-build feature to use PBKDF2 with SHA-2 (that is SHA-256 and SHA-512).

I have written a sample class which you can use for generating PBKDF2 based salted hash using SHA-2 family.

using System;
using System.Security.Cryptography;

namespace pbkdf2_sha2
{
    class PasswordHash
    {
        private const int SaltByteSize = 32;
        private const int HashByteSize = 32;
        private const int Iterations = 4096;

        private static string GetSalt()
        {
            var cryptoProvider = new RNGCryptoServiceProvider();
            byte[] b_salt = new byte[SaltByteSize];
            cryptoProvider.GetBytes(b_salt);
            return Convert.ToBase64String(b_salt);
        }

        public static string GetPasswordHash(string password)
        {
            string salt = GetSalt();

            byte[] saltBytes = Convert.FromBase64String(salt);
            byte[] derived;

            using (var pbkdf2 = new Rfc2898DeriveBytes(
                password,
                saltBytes,
                Iterations,
                HashAlgorithmName.SHA512))
            {
                derived = pbkdf2.GetBytes(HashByteSize);
            }

            return string.Format("{0}:{1}:{2}", Iterations, Convert.ToBase64String(derived), Convert.ToBase64String(saltBytes));
        }

        public static bool VerifyPasswordHash(string password, string hash)
        {
            try
            {
                string[] parts = hash.Split(new char[] { ':' });

                byte[] saltBytes = Convert.FromBase64String(parts[2]);
                byte[] derived;

                int iterations = Convert.ToInt32(parts[0]);

                using (var pbkdf2 = new Rfc2898DeriveBytes(
                    password,
                    saltBytes,
                    iterations,
                    HashAlgorithmName.SHA512))
                {
                    derived = pbkdf2.GetBytes(HashByteSize);
                }

                string new_hash = string.Format("{0}:{1}:{2}", Iterations, Convert.ToBase64String(derived), Convert.ToBase64String(saltBytes));

                return hash == new_hash;
            }
            catch
            {
                return false;
            }
        }
    }
}

For calling these methods for generating and then verifying use it like this:

var password = "YourTestPassword";
string hash = PasswordHash.GetPasswordHash(password);
Console.WriteLine(hash);
Console.WriteLine(PasswordHash.VerifyPasswordHash(password, hash));