'Same password hash not matching

I am trying to create and test my api for login using C#. Below is the major part of the code:

private static void CreatePasswordHash(string password, out byte[] passwordHash, out byte[] passwordSalt)
        {
            using (var hmac = new HMACSHA512())
            {
                passwordSalt = hmac.Key;
                passwordHash = hmac.ComputeHash(System.Text.Encoding.UTF8.GetBytes(password));
            }
        }

        private static bool VerifyPasswordHash(string password, byte[] passwordHash, byte[] passwordSalt)
        {
            using (var hmac = new HMACSHA512(passwordSalt))
            {
                var computedHash = hmac.ComputeHash(System.Text.Encoding.UTF8.GetBytes(password));
                return computedHash.SequenceEqual(passwordHash);
            }
        }

My Db is Mysql 8 with CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_520_ci format. Values are stored as varchar(512) so that length is not a problem when saving.

The code for the DB part for saving data is:

        Cmd.Parameters.Add(new MySqlParameter("@username", MySqlDbType.VarChar)).Value = user.UserName;
        Cmd.Parameters.Add(new MySqlParameter("@passwordhash", MySqlDbType.VarChar)).Value = Convert.ToBase64String(user.PasswordHash);
        Cmd.Parameters.Add(new MySqlParameter("@passwordsalt", MySqlDbType.VarChar)).Value = Convert.ToBase64String(user.PasswordSalt);

The code for retrieving data from db for password check is:

                while (Rdr.Read() == true)
                {
                    user.UserName = Rdr.GetString("username");
                    user.PasswordHash = System.Text.Encoding.UTF8.GetBytes(Rdr.GetString("passwordhash"));
                    user.PasswordSalt = System.Text.Encoding.UTF8.GetBytes(Rdr.GetString("passwordsalt"));
                    user.UserID = Rdr.GetInt16("userid");
                }
                Rdr.Close();

However when I am doing password match, it is always not matching, could you please help me where I am doing wrong, is it in encoding etc..

VerifyPasswordHash(request.Password, user.PasswordHash, user.PasswordSalt)

learning the code from the tutorial but tutorial is from DB extraction, so want to know if I am doing anything wrong in the process for it to not match.



Solution 1:[1]

I think you need to convert back hash and salt using Convert.FromBase64String.

while (Rdr.Read() == true)
                {
                    user.UserName = Rdr.GetString("username");
                    user.PasswordHash = Convert.FromBase64String(Rdr.GetString("passwordhash"));
                    user.PasswordSalt = Convert.FromBase64String(Rdr.GetString("passwordsalt"));
                    user.UserID = Rdr.GetInt16("userid");
                }
                Rdr.Close();

Solution 2:[2]

This is the wrong approach for storing password hashes, it can be calculated way too fast (several Giga SHA512 per second) with common hardware. Thus you need a password-hash function like BCrypt or Argon2 which have a cost factor to control the necessary time for a single calculation.

The BCrypt library https://www.nuget.org/packages/BCrypt.Net-Next/ is a good choice. It also includes/extracts the salt into the resulting password-hash-string, so you need only a single db field to store the hash.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 martinstoeckli