Bryan Albrecht

Salted Hash C#

Das fast unumkehrbare Verschlüsseln eines Geheimtextes nennt man hashing. Aus einem zuvor meist lesbaren Text wird also durch einen bestimmten Algorithmus ein Hash erzeugt.

Salted Hash

Wenn bekannt ist, mit welchem Hash Algorithmus ein Hash erzeugt wurde, ist es sehr einfach mit der Brute-Force-Methode das Passwort herauszufinden. Die Brute-Force Methode ist nichts Anderes als automatisiertes Ausprobieren und Vergleichen. Um es demjenigen, welcher den Geheimtext zu entschlüsseln versucht, nicht alt zu einfach zu machen, wird noch ein zufällig generierter Text vor den Geheimtext gestellt. Dieser zufällig generierte Text nennt sich Salt. Der Geheimtext zusammen mit dem zufälligen Text ist nach dem hashing nun ein Salted Hash.

Umsetzung

Um sinnvoll mit Saltet Hashs arbeiten zu können, braucht es verschiedene Methoden. Jede dieser Methoden übernimmt eine andere wichtige Aufgabe.

Zufälliger Salt erstellen

Da bei jedem Hash ein neuer Salt erstellt werden soll ist es sinnvoll dafür eine eigene Methode zu erstellen. Diese Methode sieht wie folgt aus:

  1. public static byte[] GetRandomSalt()
  2. {
  3. var salt = new byte[8];
  4. using (var csp = new RNGCryptoServiceProvider())
  5. {
  6. csp.GetBytes(salt);
  7. }
  8. return salt;
  9. }

Hash erstellen

Zusätzlich zur Salt Methode braucht es noch eine Methode, welche den Geheimtext verschlüsselt.

  1. public static string GetPbkdf2Hash(string password)
  2. {
  3. var salt = GetRandomSalt();
  4. var pbkdf2 = new Rfc2898DeriveBytes(password, salt, 150000);
  5. var hash = pbkdf2.GetBytes(16);
  6. var result = new byte[hash.Length + salt.Length];
  7. Array.Copy(salt, 0, result, 0, salt.Length);
  8. Array.Copy(hash, 0, result, salt.Length, hash.Length);
  9. return Convert.ToBase64String(result);
  10. }

Validieren

Als dritte und letzte Methode wird eine Funktion benötigt, welche überprüft, ob der eingegebene Text dem zuvor Verschlüsselten Geheimtext entspricht. Diese Funktion sieht wie folgt aus:

  1. public static bool IsPasswordValide(string password, string hashedPassword)
  2. {
  3. var salt = Convert.FromBase64String(hashedPassword).Take(8).ToArray();
  4. var pbkdf2 = new Rfc2898DeriveBytes(password, salt, 150000);
  5. var hash = pbkdf2.GetBytes(16);
  6. var result = new byte[hash.Length + salt.Length];
  7. Array.Copy(salt, 0, result, 0, salt.Length);
  8. Array.Copy(hash, 0, result, salt.Length, hash.Length);
  9. return String.Equals(Convert.ToBase64String(result), hashedPassword);
  10. }

Quelle

Die Logik, welche hier verwendet wurde, stammt grösstenteils von Michael Schuler.