2013-05-02 46 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);