将散列密码与salt进行比较始终失败

时间:2017-03-19 21:49:10

标签: c# .net

我看到了关于密码哈希和盐的多个问题,但它们似乎都对我失败了。我使用此函数对其进行哈希/加盐,然后将其放入数据库:

    public string HashPassword(string password)
    {
        byte[] salt;
        new RNGCryptoServiceProvider().GetBytes(salt = new byte[16]);
        var pbkdf2 = new Rfc2898DeriveBytes(PasswordTextbox.Password, salt, 10000);
        byte[] hash = pbkdf2.GetBytes(20);
        byte[] hashBytes = new byte[36];
        Array.Copy(salt, 0, hashBytes, 0, 16);
        Array.Copy(hash, 0, hashBytes, 16, 20);
        string savedPasswordHash = Convert.ToBase64String(hashBytes);
        return savedPasswordHash;
    }

然后我尝试使用此功能将其与用户输入进行比较:

    public static void UnhashPassword(string hashedPassword, string hashedPasswordFromDatabase)
    {
        byte[] hashBytes = Convert.FromBase64String(hashedPasswordFromDatabase);
        byte[] salt = new byte[16];
        Array.Copy(hashBytes, 0, salt, 0, 16);
        var pbkdf2 = new Rfc2898DeriveBytes(hashedPassword, salt, 10000);
        byte[] hash = pbkdf2.GetBytes(20);
        for (int i = 0; i < 20; i++)
            if (hashBytes[i + 16] != hash[i])
                throw new UnauthorizedAccessException();
    }

第二个函数总是抛出异常。不确定是什么原因,因为这个答案似乎对其他人的问题都有效。

1 个答案:

答案 0 :(得分:2)

如果没有能够可靠地再现问题的好Minimal, Complete, and Verifiable code example,就不可能肯定地说出错了。但是,以下代码示例 完全按预期工作(即result的值在trueValidatePassword()调用初始化之后为static void Main(string[] args) { string password = "password"; string hashedPassword = HashPassword(password); bool result = ValidatePassword(password, hashedPassword); } static string HashPassword(string password) { byte[] salt; new RNGCryptoServiceProvider().GetBytes(salt = new byte[16]); var pbkdf2 = new Rfc2898DeriveBytes(password, salt, 10000); byte[] hash = pbkdf2.GetBytes(20); byte[] hashBytes = new byte[36]; Array.Copy(salt, 0, hashBytes, 0, 16); Array.Copy(hash, 0, hashBytes, 16, 20); string savedPasswordHash = Convert.ToBase64String(hashBytes); return savedPasswordHash; } static bool ValidatePassword(string password, string hashedPasswordFromDatabase) { byte[] hashBytes = Convert.FromBase64String(hashedPasswordFromDatabase); byte[] salt = new byte[16]; Array.Copy(hashBytes, 0, salt, 0, 16); var pbkdf2 = new Rfc2898DeriveBytes(password, salt, 10000); byte[] hash = pbkdf2.GetBytes(20); for (int i = 0; i < 20; i++) { if (hashBytes[i + 16] != hash[i]) { return false; } } return true; } }:

HashPassword()

上述内容与原始代码之间的唯一重大变化是password方法使用传入的PasswordTextbox.Password值,而不是PasswordTextbox.Password

基于这种观察,我只能猜测,在你自己的场景中,你并没有像以后验证那样使用相同的密码。这是因为$array = SELECT ...; foreach ($array as $item) { do some SQL with $item } 从来没有使用过正确的密码,或者您之后传递了不同的密码,我无法说出来。

如果上面的代码示例没有充分指出您正确的方向,以便您可以使代码正常工作,请改进您的问题,使其包含一个好的MCVE