2013-05-02 22 views
2

我有下面的代码以哈希/存储/检索的密码数据,但我的第一个单元测试,它失败。散列和GetString/GetBytes会发出

我相信它的编码引起的问题,因为当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); 
    } 
} 
+3

使用的Base64编码字符串二进制值,它可以处理任意字节序列。 UTF-8用于在unicode文本和字节之间进行转换,而不是每个有效的字节序列对于UTF-8都有效。 – CodesInChaos 2013-05-02 15:51:27

+0

谢谢你做到了 – Jon 2013-05-02 15:54:57

回答

3

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

Convert.ToBase64StringConvert.FromBase64String应该做的伎俩。


一些其他注意事项:

  • 你的术语是很奇怪的,不叫散key,称之为hash
  • 我串连的散列和盐在CreatePasswordHash功能,使主叫方没有与具有两个单独的值来打扰。

    return Base64Encode(salt)+"$"+Base64Encode(hash)东西然后在验证功能使用string.Split

  • 我们推荐使用恒定时间比较来验证,但似乎不太可能你的正时侧通道实际上可以被利用。

  • 您的迭代计数很低。我建议提高到10000
+0

你可以可靠地在$上分割 - 如果那个字符在那里怎么办 – Jon 2013-05-02 15:59:01

+0

@Jon hash和salt都是Base64编码器的输出。 Base64从不产生'$',所以只有那个单独的'$'作为分隔符。 – CodesInChaos 2013-05-02 15:59:33

+0

它的一切都超出了我的小脑子 – Jon 2013-05-02 16:01:51

3

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

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

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

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

UTF8不是办法将任何随机字节转换为字符串。它用于编码文本;不只是任何字节都是有效的UTF8编码值。您可以使用Base64 tofrom转换。请注意,base64编码的字符串将占用原始字节字符的3/4倍。这里有一个例子:

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