相同的密码哈希不匹配

Same password hash not matching

我正在尝试使用 C# 创建和测试我的 api 登录。以下是代码的主要部分:

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);
            }
        }

我的 Db 是 Mysql 8,CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_520_ci 格式。 值存储为 varchar(512),因此在保存时长度不是问题。

保存数据的DB部分代码为:

        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);

从数据库中检索数据以进行密码检查的代码是:

                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();

但是我在做密码匹配的时候,总是匹配不上,请问是哪里做错了,是不是编码等问题

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

tutorial 学习代码,但教程来自 DB 提取,所以想知道我在这个过程中是否做错了什么导致它不匹配。

我认为您需要使用 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();

这是存储密码哈希值的错误方法,使用普通硬件计算它的速度可能太快(每秒几千兆 SHA512)。因此你需要一个像 BCrypt 或 Argon2 这样的 password-hash 函数,它有一个成本因素来控制单个计算的必要时间。

BCrypt 库 https://www.nuget.org/packages/BCrypt.Net-Next/ 是一个不错的选择。它还将 includes/extracts 盐放入生成的 password-hash 字符串中,因此您只需要一个数据库字段来存储哈希值。