2017-06-11 127 views
0

我正在創建一個小的C#WinForms應用程序,但在驗證/驗證散列密碼時遇到了問題。驗證散列密碼

當用戶被創建時,他們的密碼被散列並存儲在數據庫中。我不知道如何將輸入的密碼(當用戶登錄時)與數據庫中的散列密碼進行比較。

代碼來創建哈希低於:

private static string CreateHashedPassword(string username, string plainTextPassword) 
    { 
     byte[] salt; 
     new System.Security.Cryptography.RNGCryptoServiceProvider().GetBytes(salt = new byte[16]); 
     System.Security.Cryptography.Rfc2898DeriveBytes pbkdf2 = new System.Security.Cryptography.Rfc2898DeriveBytes(plainTextPassword, salt, 3000); 
     byte[] hash = pbkdf2.GetBytes(20); 

     byte[] hashBytes = new byte[36]; 
     Array.Copy(salt, 0, hashBytes, 0, 16); 
     Array.Copy(hash, 0, hashBytes, 16, 20); 
     return Convert.ToBase64String(hashBytes); 
    } 

當用戶試圖登錄,我再次調用此方法來獲取哈希密碼進行比較的數據庫,但它永遠不會匹配。

我敢肯定,這是因爲新的鹽是每個方法運行時創建的,所以我敢肯定的方式來解決它(但我不知道如何)是兩種:

  1. 保存在數據庫中的鹽或

  2. 使用類似的用戶名來創建鹽。這是首選的方法,但我不知道如何從預先確定的字符串(如用戶名)中派生鹽。

任何想法/指針?謝謝!

+0

你在做從頭定製認證/授權或您使用的一些圖書館爲此目的? –

+0

那麼你實施了哪一個,你遇到了什麼問題? –

+0

下面是一個鏈接,以便我使用pbkdf2爲密碼散列/比較器創建完整解決方案:[使用Pbkdf2的完整密碼散列解決方案](https://stackoverflow.com/documentation/c%23/2774/哈希函數/ 15470 /完整密碼哈希解決方案使用pbkdf2#t = 20170611103527142945) – Igor

回答

1

這是因爲你的哈希方式使用隨機方法來生成它。

RNGCryptoServiceProvider使用由加密服務提供商(CSP)提供的實現實現加密Random Number Generator(RNG)。這個類不能被繼承。

您可以使用此方法以哈希:

public static string GenerateKeyHash(string Password) 
{ 
    if (string.IsNullOrEmpty(Password)) return null; 
    if (Password.Length < 1) return null; 

    byte[] salt = new byte[20]; 
    byte[] key = new byte[20]; 
    byte[] ret = new byte[40]; 

    try 
    { 
     using (RNGCryptoServiceProvider randomBytes = new RNGCryptoServiceProvider()) 
     { 
      randomBytes.GetBytes(salt); 

      using (var hashBytes = new Rfc2898DeriveBytes(Password, salt, 10000)) 
      { 
       key = hashBytes.GetBytes(20); 
       Buffer.BlockCopy(salt, 0, ret, 0, 20); 
       Buffer.BlockCopy(key, 0, ret, 20, 20); 
      } 
     } 
     // returns salt/key pair 
     return Convert.ToBase64String(ret); 
    } 
    finally 
    { 
     if (salt != null) 
      Array.Clear(salt, 0, salt.Length); 
     if (key != null) 
      Array.Clear(key, 0, key.Length); 
     if (ret != null) 
      Array.Clear(ret, 0, ret.Length); 
    } 
} 

而且這種方法來比較你的密碼:

public static bool ComparePasswords(string PasswordHash, string Password) 
{ 
    if (string.IsNullOrEmpty(PasswordHash) || string.IsNullOrEmpty(Password)) return false; 
    if (PasswordHash.Length < 40 || Password.Length < 1) return false; 

    byte[] salt = new byte[20]; 
    byte[] key = new byte[20]; 
    byte[] hash = Convert.FromBase64String(PasswordHash); 

    try 
    { 
     Buffer.BlockCopy(hash, 0, salt, 0, 20); 
     Buffer.BlockCopy(hash, 20, key, 0, 20); 

     using (var hashBytes = new Rfc2898DeriveBytes(Password, salt, 10000)) 
     { 
      byte[] newKey = hashBytes.GetBytes(20); 

      if (newKey != null) 
       if (newKey.SequenceEqual(key)) 
        return true; 
     } 
     return false; 
    } 
    finally 
    { 
     if (salt != null) 
      Array.Clear(salt, 0, salt.Length); 
     if (key != null) 
      Array.Clear(key, 0, key.Length); 
     if (hash != null) 
      Array.Clear(hash, 0, hash.Length); 
    } 
} 
+0

@Benny你測試過它嗎? –