Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 哈希和GetString/GetBytes问题_C#_.net_Encryption_Hash_Salt - Fatal编程技术网

C# 哈希和GetString/GetBytes问题

C# 哈希和GetString/GetBytes问题,c#,.net,encryption,hash,salt,C#,.net,Encryption,Hash,Salt,我有下面的代码来散列/存储/检索密码数据,但我的第一个单元测试失败了 我认为是编码导致了这个问题,因为当调用GetBytes时,它会返回字节[38],字节[36],我认为应该是20 在数据库中存储字符串时,我必须将其转换为字符串 有什么想法吗?谢谢 [Fact] public void EncryptDecryptPasswordShouldMatch() { string password = "password"; string passwordKey = string.Em

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

我认为是编码导致了这个问题,因为当调用GetBytes时,它会返回
字节[38]
字节[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);
    }
}

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

而且应该做到这一点


一些补充说明:

  • 你的术语真的很奇怪,不要叫hash
    key
    ,叫它
    hash
  • 我将在
    CreatePasswordHash
    函数中连接hash和salt,这样调用者就不必为拥有两个单独的值而烦恼了

    类似于
    returnbase64encode(salt)+“$”+Base64Encode(hash)
    的内容,然后在验证函数中使用
    string.Split

  • 建议使用恒定时间比较进行验证,但似乎不太可能利用您的定时侧通道

  • 您的迭代次数非常少。我建议增加到10000

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

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

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

byte[] salt = Convert.FromBase64String(passwordSalt);
byte[] key = Convert.FromBase64String(passwordKey);
passwordSalt = Convert.ToBase64String(salt);
passwordKey = Convert.ToBase64String(key);
不是将任何随机字节转换为字符串的方法。它用于编码文本;并非所有字节都是有效的UTF8编码值。您可以使用Base64和转换。请注意,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);

使用Base64将二进制值编码为字符串,它可以处理任意字节序列。UTF-8用于在unicode文本和字节之间进行转换,并不是每个有效的字节序列都对UTF-8有效。您能可靠地在$上拆分吗?如果该字符在there@Jon哈希和salt都是Base64编码器的输出。Base64从不生成
$
,因此只有一个
$
可以作为分隔符。@Jon:然后请一名加密专业人员。这很容易出错,并建立一个不安全的系统。“我对密码系统了解得够多了,知道自己没有能力做好工作,所以我不去尝试。@EricLippert因为密码散列是一个非常常见的问题,如果微软雇佣密码学家为BCL添加易于使用和安全的类,那就太好了。”。甚至php也做对了。