我有以下代码来哈希/存储/检索密码数据,但是我的第一个单元测试失败了。

我相信导致问题的Encoding是因为调用GetBytes时它返回byte[38],当我认为应该为20时返回byte[36]

我必须将其存储在数据库中才能转换为字符串。

有任何想法吗?谢谢

[Fact]
public void EncryptDecryptPasswordShouldMatch()
{
    string password = "password";
    string passwordKey = string.Empty;
    string passwordSalt = string.Empty;

    Helpers.CreatePasswordHash(password, out passwordSalt, out passwordKey);

    Assert.True(Helpers.PasswordsMatch(passwordSalt, passwordKey, password));

}


public static bool PasswordsMatch(string passwordSalt, string passwordKey, string password)
{
    byte[] salt = Encoding.UTF8.GetBytes(passwordSalt);
    byte[] key = Encoding.UTF8.GetBytes(passwordKey);

    using (var deriveBytes = new Rfc2898DeriveBytes(password, salt))
    {
        byte[] newKey = deriveBytes.GetBytes(20);  // derive a 20-byte key

        if (!newKey.SequenceEqual(key))
            return false;
    }

    return true;
}

public static void CreatePasswordHash(string password, out string passwordSalt, out string passwordKey)
{
    // specify that we want to randomly generate a 20-byte salt
    using (var deriveBytes = new Rfc2898DeriveBytes(password, 20))
    {
        byte[] salt = deriveBytes.Salt;
        byte[] key = deriveBytes.GetBytes(20);  // derive a 20-byte key

        passwordSalt = Encoding.UTF8.GetString(salt);
        passwordKey = Encoding.UTF8.GetString(key);
    }
}

最佳答案

使用Base64将二进制值编码为字符串,它可以处理任意字节序列。 UTF-8用于在Unicode文本和字节之间进行转换,并非每个有效的字节序列都适用于UTF-8。使用Utf-8将密码(即文本)转换为字节,但对盐和哈希使用Base64。

Convert.ToBase64StringConvert.FromBase64String应该可以解决问题。



一些附加说明:


您的术语确实很奇怪,不要将哈希称为key,请将其称为hash
我将您的CreatePasswordHash函数中的哈希和盐串联起来,因此调用者不必费心使用两个单独的值。

类似return Base64Encode(salt)+"$"+Base64Encode(hash)的东西,然后在验证功能中使用string.Split
建议使用恒定时间比较来进行验证,但是看来您的时序副信道实际上不可能被利用。
您的迭代计数非常低。我建议将其增加到10000。

10-06 05:24
查看更多