哈希和GetString/GetBytes问题

本文关键字:GetBytes 问题 GetString 哈希 | 更新日期: 2023-09-27 18:11:46

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

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

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

任何想法?由于

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

哈希和GetString/GetBytes问题

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

Convert.ToBase64StringConvert.FromBase64String应该能起作用。


附加说明:

  • 你的术语真的很奇怪,不要叫它key,叫它hash
  • 我会在你的CreatePasswordHash函数中连接哈希和盐,所以调用者不必为有两个单独的值而烦恼。

    return Base64Encode(salt)+"$"+Base64Encode(hash),则在验证函数中使用string.Split

  • 建议使用常数时间比较来验证,但似乎不太可能实际利用您的时序侧信道

  • 你的迭代次数很低。我建议增加到10000。

修改代码以使用Convert.FromBase64String方法:

byte[] salt = Convert.FromBase64String(passwordSalt);
byte[] key = Convert.FromBase64String(passwordKey);

修改代码以使用Convert.ToBase64String方法:

passwordSalt = Convert.ToBase64String(salt);
passwordKey = Convert.ToBase64String(key);

UTF8不是将任何随机字节转换为字符串的方法。用于对文本进行编码;并非所有字节都是有效的UTF8编码值。您可以使用Base64的to和from转换。请注意,base64编码的字符串将占用原始字节字符的4/3倍。下面是一个例子:

byte[] salt = deriveBytes.Salt;
byte[] key = deriveBytes.GetBytes(20);  // derive a 20-byte key
passwordSalt = Convert.ToBase64String(salt);
passwordKey = Convert.ToBase64String(key);

,后来:

byte[] salt = Convert.FromBase64String(passwordSalt);
byte[] key = Convert.FromBase64String(passwordKey);