0

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.

surpavan
  • 1,372
  • 7
  • 34
  • 66

2 Answers2

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();
JoelCrypto
  • 462
  • 2
  • 12
  • 1
    Found the reason as in https://stackoverflow.com/a/3866449/610928 & https://stackoverflow.com/a/19859753/610928 – surpavan May 07 '22 at 12:03
1

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.

martinstoeckli
  • 23,430
  • 6
  • 56
  • 87
  • 1
    thank you, I changed to Bcrypt.net-next package now. @JeolCrypto solution worked for me with existing code. – surpavan May 07 '22 at 12:45
  • 1
    You can use bcrypt with this code! Bcrypt is common used hashing solution nowadays and way better than MD5. Be sure to use a verify function insensible to timing attacks: https://en.m.wikipedia.org/wiki/Timing_attack – JoelCrypto May 07 '22 at 13:10
  • Changed the code, only 3-4 lines are modified, and it is actually more clean to read. Removed the support functions like createhash and verifypassword. Thank you. – surpavan May 07 '22 at 18:03
  • @surpavan - Good to hear, well done! – martinstoeckli May 07 '22 at 20:24