【问题标题】:Hashing same string and same salt giving different hash result散列相同的字符串和相同的盐给出不同的散列结果
【发布时间】:2020-03-12 02:03:42
【问题描述】:

我正在尝试使用来自Microsoft Docs Hashing 的代码来散列密码并将其存储在数据库中。保存哈希和盐工作正常。 我的哈希方法:

public Tuple<string,string> PasswordCrypting(string password)
    {
        byte[] salt = new byte[128 / 8];
        using (var rng = RandomNumberGenerator.Create())
        {
            rng.GetBytes(salt);
        }
        string hashed = Convert.ToBase64String(KeyDerivation.Pbkdf2(
        password: password,
        salt:salt,
        prf: KeyDerivationPrf.HMACSHA1,
        iterationCount: 10000,
        numBytesRequested: 256 / 8));
        Tuple<string, string> credentials = new Tuple<string, string>(hashed, Convert.ToBase64String(salt));
        return credentials;
    }

在用户登录时,我从数据库中检索 salt,并使用它使用用户的密码输入和 salt 重新创建散列。我会使用我得到的哈希值与存储在数据库中的哈希值进行比较。

public string PasswordDecrypting(string username,string password)
    {
        string salt = _userManager.GetPassSalt(username);
        string hashed = Convert.ToBase64String(KeyDerivation.Pbkdf2(
        password: password,
        salt: Convert.FromBase64String(salt),
        prf: KeyDerivationPrf.HMACSHA1,
        iterationCount: 10000,
        numBytesRequested: 256 / 8));
        return hashed;
    }

问题是我永远无法获得与数据库中相同的哈希值。我调试了我的代码,盐与数据库中的盐匹配,密码字符串与第一次散列时相同;使用了相同的算法,但生成的哈希与我应该得到的不同。

这个算法是不是让它永远不会产生相同的散列,如果是这样,我该如何重新创建我的散列?

【问题讨论】:

  • 盐与数据库中的盐相匹配,但您确定它与用于创建初始哈希的盐相同吗?
  • 有了哈希,就没有“解密”。相反,您通过用于原始的 same 散列函数运行输入。拥有一个单独的“Decyrpt”功能是没有意义的。
  • PasswordCrypting 应该将 Salt(由外部代码为其生成)作为参数。那么它是否从随机生成或数据库中获取盐并不重要。你可以把它变成一个简单的字符串返回值。
  • @JonathonChase 如何确保保存用于创建哈希的那个?
  • 确保保存用于创建哈希的 [salt] 的方式是确保保存用于创建哈希的盐。您可以将其作为用户记录的一部分保存在数据库中,或者以不会针对特定用户更改的方式进行计算。例如,如果您有一个与用户记录关联的不变 GUID,请将其用作盐。

标签: c# asp.net-core hash passwords


【解决方案1】:

我创建了一个单元测试来测试您的代码。并且必须得出结论,您没有正确存储盐,或者您在存储之前或从数据库中检索盐之后以某种方式更改了盐。

我写了以下单元测试:

    [TestMethod]
    public void Test_SaltGeneration()
    {
        var password = "48F3A112-F574-4B25-B226-CE97888FCBCB";

        var firstResult = PasswordCrypting(password);

        var secondResult = PasswordDecrypting(password, firstResult.salt);

        Assert.IsTrue(firstResult.hash.Equals(secondResult));
    }

    public (string hash, string salt) PasswordCrypting(string password)
    {
        byte[] salt = new byte[128 / 8];
        using (var rng = RandomNumberGenerator.Create())
        {
            rng.GetBytes(salt);
        }
        string hashed = Convert.ToBase64String(KeyDerivation.Pbkdf2(
            password: password,
            salt: salt,
            prf: KeyDerivationPrf.HMACSHA1,
            iterationCount: 10000,
            numBytesRequested: 256 / 8));

        return (hashed, Convert.ToBase64String(salt));
    }

    public string PasswordDecrypting(string password, string salt )
    {
        string hashed = Convert.ToBase64String(KeyDerivation.Pbkdf2(
            password: password,
            salt: Convert.FromBase64String(salt),
            prf: KeyDerivationPrf.HMACSHA1,
            iterationCount: 10000,
            numBytesRequested: 256 / 8));
        return hashed;
    }

正如你可能猜到的那样。该测试通过。暗示我的第一个断言。

【讨论】:

  • 是的,我犯了一个愚蠢的错误,在保存哈希和盐时,我调用了两次该方法,从而产生了不同的盐。感谢您的宝贵时间。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-09-03
  • 2020-02-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-30
相关资源
最近更新 更多