2017-06-11 3 views
0

Ich erstelle eine kleine C# WinForms-Anwendung, habe aber Probleme mit der Verifizierung/Authentifizierung eines Hash-Passworts.Authenticate Hash Password

Wenn der Benutzer erstellt wird, wird sein Kennwort gehasht und in der Datenbank gespeichert. Ich weiß nicht, wie man das eingegebene Passwort (wenn sich der Benutzer anmeldet) mit dem Hash-Passwort in der Datenbank vergleicht.

Der Code den Hash zu erstellen, ist unten:

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

Wenn der Benutzer anmelden möchte, habe ich diese Methode aufrufen, erneut das Hash-Passwort zu bekommen für die Datenbank zu vergleichen, aber es passt nicht.

Ich bin ich ziemlich sicher, das ist, weil ein neues Salz jedes Mal erstellt wird das Verfahren ausgeführt wird, so dass ich bin mir ziemlich sicher, dass die Art und Weise, es zu beheben (aber ich weiß nicht, wie) ist entweder:

  1. Speichern Sie das Salz in der Datenbank oder

  2. Verwendung so etwas wie den Benutzernamen, das Salz zu erstellen. Dies ist die bevorzugte Methode, aber ich weiß nicht, wie man ein Salz aus einer vorgegebenen Zeichenfolge wie einem Benutzernamen ableitet.

Irgendwelche Gedanken/Hinweise? Vielen Dank!

+0

Sie sind eine eigene Authentifizierung/Autorisierung von Grund auf neu zu machen oder verwenden Sie einige Bibliothek für diesen Zweck? –

+0

Also welchen hast du implementiert und mit welchem ​​Problem warst du konfrontiert? –

+0

Hier ist ein Link zu der Dokumentation, wo ich eine vollständige Lösung für ein Passwort hashher/comparer mit pbkdf2 erstellt hatte: [Komplette Passwort-Hashing-Lösung mit Pbkdf2] (https://stackoverflow.com/documentation/c%23/2774/ Hash-Funktionen/15470/Complete-Passwort-Hashing-Lösung-mit-pbkdf2 # t = 20170611103527142945) – Igor

Antwort

1

Es ist passiert, weil Ihre Hash-Methode eine zufällige Methode verwendet, um es zu generieren.

RNGCryptoServiceProvider Implementiert eine kryptographische Random Number Generator (RNG) unter Verwendung der von den kryptographischen Dienstanbietern bereitgestellt Implementierung (CSP). Diese Klasse kann nicht vererbt werden.

können Sie diese Methode verwenden, um Hash:

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

und diese Methode, um Ihre Passwörter zu vergleichen:

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 hast du es getestet? –