Hash- und Salt-Passwörter in C #

178

Ich habe gerade einen Artikel von David Hayden über das Hashing von Benutzerkennwörtern durchgesehen .

Ich kann wirklich nicht verstehen, was er erreichen will.

Hier ist sein Code:

private static string CreateSalt(int size)
{
    //Generate a cryptographic random number.
    RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
    byte[] buff = new byte[size];
    rng.GetBytes(buff);

    // Return a Base64 string representation of the random number.
    return Convert.ToBase64String(buff);
}

private static string CreatePasswordHash(string pwd, string salt)
{
    string saltAndPwd = String.Concat(pwd, salt);
    string hashedPwd =
        FormsAuthentication.HashPasswordForStoringInConfigFile(
        saltAndPwd, "sha1");
    return hashedPwd;
}

Gibt es eine andere C # -Methode zum Hashing von Passwörtern und zum Hinzufügen von Salt?

ACP
quelle
Hier ist eine Bibliothek, die das Hashing mit Salt encrypto.codeplex.com
Omu
6
Was sollten Sie für die Größe bei der ersten Methode zur Salzgewinnung eingeben?
Shane LeBlanc
6
Link ist unterbrochen.
Osmanraifgunes
@ShaneLeBlanc Sie sollten mindestens so viele Bits wie die Funktionsausgänge haben. SHA1ist nicht Crypto-Grade, daher sollten Sie mindestens verwenden SHA256, das 256 Bit oder 32 Bytes ausgibt. ABER 256 Bit können NICHT einfach in Basis 64 konvertiert werden, da jedes Base64-Zeichen 6 Bit codiert und 256 nicht vollständig durch 6 teilbar ist. Sie benötigen also einen gemeinsamen Nenner von 6 (für Base64) und 8 (für Bits in einem Byte). über 256 Bit, das sind 264 Bits oder 33 Bytes. TLDR: Verwenden Sie 33.
VSO

Antworten:

248

Eigentlich ist das bei den String-Konvertierungen etwas seltsam - was der Mitgliedschaftsanbieter tut, um sie in Konfigurationsdateien zu speichern. Hashes und Salze sind binäre Blobs. Sie müssen sie nicht in Zeichenfolgen konvertieren, es sei denn, Sie möchten sie in Textdateien ablegen.

In meinem Buch Beginning ASP.NET Security (oh, endlich eine Ausrede, um das Buch zu pimpen) mache ich Folgendes

static byte[] GenerateSaltedHash(byte[] plainText, byte[] salt)
{
  HashAlgorithm algorithm = new SHA256Managed();

  byte[] plainTextWithSaltBytes = 
    new byte[plainText.Length + salt.Length];

  for (int i = 0; i < plainText.Length; i++)
  {
    plainTextWithSaltBytes[i] = plainText[i];
  }
  for (int i = 0; i < salt.Length; i++)
  {
    plainTextWithSaltBytes[plainText.Length + i] = salt[i];
  }

  return algorithm.ComputeHash(plainTextWithSaltBytes);            
}

Die Salzbildung ist als Beispiel in der Frage. Sie können Text mit in Byte-Arrays konvertieren Encoding.UTF8.GetBytes(string). Wenn Sie einen Hash in seine Zeichenfolgendarstellung konvertieren müssen, können Sie Convert.ToBase64Stringund verwendenConvert.FromBase64String zurückkonvertieren.

Sie sollten beachten, dass Sie den Gleichheitsoperator nicht für Byte-Arrays verwenden können. Er überprüft Referenzen und sollte daher einfach beide Arrays durchlaufen, um jedes Byte auf diese Weise zu überprüfen

public static bool CompareByteArrays(byte[] array1, byte[] array2)
{
  if (array1.Length != array2.Length)
  {
    return false;
  }

  for (int i = 0; i < array1.Length; i++)
  {
    if (array1[i] != array2[i])
    {
      return false;
    }
  }

  return true;
}

Verwenden Sie immer ein neues Salz pro Passwort. Salze müssen nicht geheim gehalten werden und können neben dem Hash selbst aufbewahrt werden.

Blasrohrpfeil
quelle
3
Vielen Dank für diesen Rat - hat mir wirklich geholfen, loszulegen. Ich bin auch auf diesen Link < dijksterhuis.org/creating-salted-hash-values-in-c > gestoßen, der meiner Meinung nach gute praktische Ratschläge war und viel von dem widerspiegelt, was in diesem Beitrag gesagt wurde
Alex P
18
raffinierter LINQ-Anweisungsrefaktor für CompareByteArraysreturn array1.Length == array2.Length && !array1.Where((t, i) => t != array2[i]).Any();
Jäger
6
@Brettski Technisch gesehen ja, aber ein eindeutiges Salz für jeden Benutzer macht Rainbow Tables (allgemein als die effizienteste Methode zum Knacken von Hash-Passwörtern anerkannt) praktisch nutzlos. Dies ist eine kurze Übersicht, die einen detaillierten, aber nicht überwältigenden Überblick darüber gibt, wie Passwörter sicher gespeichert werden und warum / wie alles funktioniert.
Ranger
3
@hunter: Sie sollten eine .ToList () hinzufügen, um die Zeit konstant zu halten. Beispiel: return array1.Length == array2.Length &&! array1.Where ((t, i) => t! = array2 [i]). ToList (). Any (); Andernfalls wird LINQ zurückgegeben, sobald ein nicht gleiches Byte gefunden wird.
Alex Rouillard
17
-1 für die Verwendung einer schnellen Hash-Funktion. Verwenden Sie eine langsame Konstruktion wie PBKDF2, bcrypt oder scrypt.
CodesInChaos
48

Was Blowdart gesagt hat, aber mit etwas weniger Code. Verwenden Sie Linq oder, CopyToum Arrays zu verketten.

public static byte[] Hash(string value, byte[] salt)
{
    return Hash(Encoding.UTF8.GetBytes(value), salt);
}

public static byte[] Hash(byte[] value, byte[] salt)
{
    byte[] saltedValue = value.Concat(salt).ToArray();
    // Alternatively use CopyTo.
    //var saltedValue = new byte[value.Length + salt.Length];
    //value.CopyTo(saltedValue, 0);
    //salt.CopyTo(saltedValue, value.Length);

    return new SHA256Managed().ComputeHash(saltedValue);
}

Mit Linq können Sie auch Ihre Byte-Arrays auf einfache Weise vergleichen.

public bool ConfirmPassword(string password)
{
    byte[] passwordHash = Hash(password, _passwordSalt);

    return _passwordHash.SequenceEqual(passwordHash);
}

Bevor Sie dies jedoch implementieren, sollten Sie dies überprüfen diesen Beitrag . Für das Passwort-Hashing möchten Sie möglicherweise einen langsamen Hash-Algorithmus, keinen schnellen.

Zu diesem Zweck gibt es die Rfc2898DeriveBytesKlasse, die langsam ist (und langsamer gemacht werden kann) und den zweiten Teil der ursprünglichen Frage dahingehend beantworten kann, dass sie ein Passwort und Salt nehmen und einen Hash zurückgeben kann. Weitere Informationen finden Sie in dieser Frage . Hinweis: Stack Exchange verwendet dasRfc2898DeriveBytes Kennwort-Hashing (Quellcode hier ).

Adam Boddington
quelle
6
@MushinNoShin SHA256 ist ein schneller Hash. Passwort-Hashing benötigt einen langsamen Hash wie PBKDF2, bcrypt oder scrypt. Siehe So sichern Sie Passwörter sicher? auf security.se für Details.
CodesInChaos
32

Ich habe gelesen, dass Hashing-Funktionen wie SHA256 nicht wirklich zum Speichern von Passwörtern gedacht sind: https://patrickmn.com/security/storing-passwords-securely/#notpasswordhashes

Stattdessen wurden adaptive Schlüsselableitungsfunktionen wie PBKDF2, bcrypt oder scrypt verwendet. Hier ist eine PBKDF2-basierte Version, die Microsoft für PasswordHasher in der Microsoft.AspNet.Identity-Bibliothek geschrieben hat:

/* =======================
 * HASHED PASSWORD FORMATS
 * =======================
 * 
 * Version 3:
 * PBKDF2 with HMAC-SHA256, 128-bit salt, 256-bit subkey, 10000 iterations.
 * Format: { 0x01, prf (UInt32), iter count (UInt32), salt length (UInt32), salt, subkey }
 * (All UInt32s are stored big-endian.)
 */

public string HashPassword(string password)
{
    var prf = KeyDerivationPrf.HMACSHA256;
    var rng = RandomNumberGenerator.Create();
    const int iterCount = 10000;
    const int saltSize = 128 / 8;
    const int numBytesRequested = 256 / 8;

    // Produce a version 3 (see comment above) text hash.
    var salt = new byte[saltSize];
    rng.GetBytes(salt);
    var subkey = KeyDerivation.Pbkdf2(password, salt, prf, iterCount, numBytesRequested);

    var outputBytes = new byte[13 + salt.Length + subkey.Length];
    outputBytes[0] = 0x01; // format marker
    WriteNetworkByteOrder(outputBytes, 1, (uint)prf);
    WriteNetworkByteOrder(outputBytes, 5, iterCount);
    WriteNetworkByteOrder(outputBytes, 9, saltSize);
    Buffer.BlockCopy(salt, 0, outputBytes, 13, salt.Length);
    Buffer.BlockCopy(subkey, 0, outputBytes, 13 + saltSize, subkey.Length);
    return Convert.ToBase64String(outputBytes);
}

public bool VerifyHashedPassword(string hashedPassword, string providedPassword)
{
    var decodedHashedPassword = Convert.FromBase64String(hashedPassword);

    // Wrong version
    if (decodedHashedPassword[0] != 0x01)
        return false;

    // Read header information
    var prf = (KeyDerivationPrf)ReadNetworkByteOrder(decodedHashedPassword, 1);
    var iterCount = (int)ReadNetworkByteOrder(decodedHashedPassword, 5);
    var saltLength = (int)ReadNetworkByteOrder(decodedHashedPassword, 9);

    // Read the salt: must be >= 128 bits
    if (saltLength < 128 / 8)
    {
        return false;
    }
    var salt = new byte[saltLength];
    Buffer.BlockCopy(decodedHashedPassword, 13, salt, 0, salt.Length);

    // Read the subkey (the rest of the payload): must be >= 128 bits
    var subkeyLength = decodedHashedPassword.Length - 13 - salt.Length;
    if (subkeyLength < 128 / 8)
    {
        return false;
    }
    var expectedSubkey = new byte[subkeyLength];
    Buffer.BlockCopy(decodedHashedPassword, 13 + salt.Length, expectedSubkey, 0, expectedSubkey.Length);

    // Hash the incoming password and verify it
    var actualSubkey = KeyDerivation.Pbkdf2(providedPassword, salt, prf, iterCount, subkeyLength);
    return actualSubkey.SequenceEqual(expectedSubkey);
}

private static void WriteNetworkByteOrder(byte[] buffer, int offset, uint value)
{
    buffer[offset + 0] = (byte)(value >> 24);
    buffer[offset + 1] = (byte)(value >> 16);
    buffer[offset + 2] = (byte)(value >> 8);
    buffer[offset + 3] = (byte)(value >> 0);
}

private static uint ReadNetworkByteOrder(byte[] buffer, int offset)
{
    return ((uint)(buffer[offset + 0]) << 24)
        | ((uint)(buffer[offset + 1]) << 16)
        | ((uint)(buffer[offset + 2]) << 8)
        | ((uint)(buffer[offset + 3]));
}

Beachten Sie, dass hierfür das Nuget-Paket Microsoft.AspNetCore.Cryptography.KeyDerivation installiert sein muss, für das .NET Standard 2.0 (.NET 4.6.1 oder höher) erforderlich ist. Frühere Versionen von .NET finden Sie in der Crypto- Klasse aus der System.Web.Helpers-Bibliothek von Microsoft.

Update Nov 2015
Aktualisierte Antwort zur Verwendung einer Implementierung aus einer anderen Microsoft-Bibliothek, die PBKDF2-HMAC-SHA256-Hashing anstelle von PBKDF2-HMAC-SHA1 verwendet (Hinweis PBKDF2-HMAC-SHA1 ist immer noch sicher, wenn iterCount hoch genug ist). Sie können die Quelle überprüfen, aus der der vereinfachte Code kopiert wurde, da er tatsächlich die Validierung und Aktualisierung von Hashes übernimmt, die aus der vorherigen Antwort implementiert wurden. Dies ist nützlich, wenn Sie iterCount in Zukunft erhöhen müssen.

Michael
quelle
1
Beachten Sie, dass es sich möglicherweise lohnt, PBKDF2IterCount auf eine höhere Zahl zu erhöhen. Weitere Informationen finden Sie unter security.stackexchange.com/q/3959 .
Michael
2
1) Auf PBKDF2SubkeyLength20 Bytes reduzieren . Das ist die natürliche Größe von SHA1 und eine Erhöhung darüber hinaus verlangsamt den Verteidiger, ohne den Angreifer zu verlangsamen. 2) Ich empfehle, die Anzahl der Iterationen zu erhöhen. Ich empfehle 10.000 bis 100.000, abhängig von Ihrem Leistungsbudget. 3) Ein konstanter Zeitvergleich würde auch nicht schaden, hat aber keine großen praktischen Auswirkungen.
CodesInChaos
KeyDerivationPrf, KeyDerivation und BlockCopy sind undefiniert. Welche Klassen haben sie?
Mrbengi
@mrbengi Haben Sie das erwähnte Microsoft.AspNet.Cryptography.KeyDerivation-Nuget-Paket installiert? Wenn das nicht geeignet ist, ist hier eine Version, die das Nuget-Paket nicht benötigt. Buffer.BlockCopy sollte existieren und Teil des Systems sein.
Michael
1
Das Nuget-Paket ist jetzt Microsoft.AspNetCore.Cryptography.KeyDerivation.
James Blake
25

Salz wird verwendet, um dem Hash eine zusätzliche Komplexität zu verleihen und das Brute-Force-Cracken zu erschweren.

Aus einem Artikel über Sitepoint :

Ein Hacker kann weiterhin einen sogenannten Wörterbuchangriff ausführen. Böswillige Parteien können einen Wörterbuchangriff ausführen, indem sie beispielsweise 100.000 Kennwörter verwenden, von denen sie wissen, dass sie häufig verwendet werden (z. B. Städtenamen, Sportmannschaften usw.), sie hashen und dann jeden Eintrag im Wörterbuch mit jeder Zeile in der Datenbank vergleichen Tabelle. Wenn die Hacker eine Übereinstimmung finden, Bingo! Sie haben Ihr Passwort. Um dieses Problem zu lösen, brauchen wir jedoch nur den Hash zu salzen.

Um einen Hash zu salzen, erstellen wir einfach eine zufällig aussehende Textzeichenfolge, verketten sie mit dem vom Benutzer angegebenen Kennwort und hashen dann sowohl die zufällig generierte Zeichenfolge als auch das Kennwort zusammen als einen Wert. Wir speichern dann sowohl den Hash als auch das Salt als separate Felder in der Users-Tabelle.

In diesem Szenario müsste ein Hacker nicht nur das Passwort erraten, sondern auch das Salz. Das Hinzufügen von Salt zum Klartext verbessert die Sicherheit: Wenn ein Hacker jetzt einen Wörterbuchangriff versucht, muss er seine 100.000 Einträge mit dem Salt jeder Benutzerzeile hashen. Obwohl es immer noch möglich ist, verringern sich die Chancen auf einen Hackerfolg radikal.

In .NET gibt es keine Methode, die dies automatisch ausführt. Sie müssen sich also für die oben beschriebene Lösung entscheiden.

Seb Nilsson
quelle
Salze werden verwendet, um sich gegen Dinge wie Regenbogentische zu verteidigen. Um sich gegen Wörterbuchangriffe zu verteidigen, ist wie bei jedem guten KDF ein Arbeitsfaktor (auch als Key Stretching bezeichnet) erforderlich: en.wikipedia.org/wiki/Key_stretching
Erwan Legrand
11

Ich habe eine Klasse mit der folgenden Methode erstellt:

  1. Salz schaffen
  2. Hash-Eingabe
  3. Eingabe validieren

    public class CryptographyProcessor
    {
        public string CreateSalt(int size)
        {
            //Generate a cryptographic random number.
              RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
             byte[] buff = new byte[size];
             rng.GetBytes(buff);
             return Convert.ToBase64String(buff);
        }
    
    
          public string GenerateHash(string input, string salt)
          { 
             byte[] bytes = Encoding.UTF8.GetBytes(input + salt);
             SHA256Managed sHA256ManagedString = new SHA256Managed();
             byte[] hash = sHA256ManagedString.ComputeHash(bytes);
             return Convert.ToBase64String(hash);
          }
    
          public bool AreEqual(string plainTextInput, string hashedInput, string salt)
          {
               string newHashedPin = GenerateHash(plainTextInput, salt);
               return newHashedPin.Equals(hashedInput); 
          }
     }

    `

Bamidele Alegbe
quelle
3

Ich habe eine Bibliothek SimpleHashing.Net erstellt , um das Hashing mit den von Microsoft bereitgestellten zu vereinfachen. Gewöhnliche SHA reichen nicht mehr aus, um Passwörter sicher zu speichern.

Die Bibliothek verwendet die Idee des Hash-Formats von Bcrypt, aber da es keine offizielle MS-Implementierung gibt, bevorzuge ich die Verwendung der im Framework verfügbaren Elemente (dh PBKDF2), aber es ist ein bisschen zu schwierig.

Dies ist ein kurzes Beispiel für die Verwendung der Bibliothek:

ISimpleHash simpleHash = new SimpleHash();

// Creating a user hash, hashedPassword can be stored in a database
// hashedPassword contains the number of iterations and salt inside it similar to bcrypt format
string hashedPassword = simpleHash.Compute("Password123");

// Validating user's password by first loading it from database by username
string storedHash = _repository.GetUserPasswordHash(username);
isPasswordValid = simpleHash.Verify("Password123", storedHash);
Ilya Chernomordik
quelle
2

So mache ich das .. Ich erstelle den Hash und speichere ihn mit der ProtectedDataAPI:

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

    public static byte[] DecryptData(string Data, byte[] Salt)
    {
        if (string.IsNullOrEmpty(Data)) return null;

        byte[] btData = Convert.FromBase64String(Data);

        try
        {
            return ProtectedData.Unprotect(btData, Salt, DataProtectionScope.CurrentUser);
        }
        finally
        {
            if (btData != null)
                Array.Clear(btData, 0, btData.Length);
        }
    }

    public static string EncryptData(byte[] Data, byte[] Salt)
    {
        if (Data == null) return null;
        if (Data.Length < 1) return null;

        byte[] buffer = new byte[Data.Length];

        try
        {
            Buffer.BlockCopy(Data, 0, buffer, 0, Data.Length);
            return System.Convert.ToBase64String(ProtectedData.Protect(buffer, Salt, DataProtectionScope.CurrentUser));
        }
        finally
        {
            if (buffer != null)
                Array.Clear(buffer, 0, buffer.Length);
        }
    }
JGU
quelle
Wie rufe ich es beim Speichern und beim späteren Vergleichen auf?
SearchForKnowledge
2

Ich habe alle Antworten gelesen und denke, dass diese genug sind, insbesondere @ Michael- Artikel mit langsamem Hashing und guten @ CodesInChaos- Kommentaren, aber ich habe beschlossen, mein Code-Snippet zum Hashing / Validieren freizugeben, das möglicherweise nützlich ist und keine [ Microsoft.AspNet.Cryptography] erfordert .KeyDerivation ].

    private static bool SlowEquals(byte[] a, byte[] b)
            {
                uint diff = (uint)a.Length ^ (uint)b.Length;
                for (int i = 0; i < a.Length && i < b.Length; i++)
                    diff |= (uint)(a[i] ^ b[i]);
                return diff == 0;
            }

    private static byte[] PBKDF2(string password, byte[] salt, int iterations, int outputBytes)
            {
                Rfc2898DeriveBytes pbkdf2 = new Rfc2898DeriveBytes(password, salt);
                pbkdf2.IterationCount = iterations;
                return pbkdf2.GetBytes(outputBytes);
            }

    private static string CreateHash(string value, int salt_bytes, int hash_bytes, int pbkdf2_iterations)
            {
                // Generate a random salt
                RNGCryptoServiceProvider csprng = new RNGCryptoServiceProvider();
                byte[] salt = new byte[salt_bytes];
                csprng.GetBytes(salt);

                // Hash the value and encode the parameters
                byte[] hash = PBKDF2(value, salt, pbkdf2_iterations, hash_bytes);

                //You need to return the salt value too for the validation process
                return Convert.ToBase64String(hash) + ":" + 
                       Convert.ToBase64String(hash);
            }

    private static bool ValidateHash(string pureVal, string saltVal, string hashVal, int pbkdf2_iterations)
            {
                try
                {
                    byte[] salt = Convert.FromBase64String(saltVal);
                    byte[] hash = Convert.FromBase64String(hashVal);

                    byte[] testHash = PBKDF2(pureVal, salt, pbkdf2_iterations, hash.Length);
                    return SlowEquals(hash, testHash);
                }
                catch (Exception ex)
                {
                    return false;
                }
            }

Bitte achten Sie auf die SlowEquals-Funktion, die so wichtig ist. Schließlich hoffe ich auf diese Hilfe und bitte zögern Sie nicht, mich über bessere Ansätze zu beraten.

QMaster
quelle
Anstatt eine Besetztschleife zu erstellen, sollten Sie eine künstliche Nicht-Besetzt-Verzögerung verwenden. zB mit Task.Delay. Dies verzögert einen Brute-Force-Versuch, blockiert jedoch nicht den aktiven Thread.
Gburton
@gburton Danke für deinen Rat. Ich werde es prüfen.
QMaster
In CreateHash gibt es einen Tippfehler: Sie konvertieren Convert.ToBase64String (Hash) anstelle des Salt zu sich selbst. Davon abgesehen ist dies eine nette Antwort, die so ziemlich jedes Problem anspricht, das in Kommentaren zu anderen Antworten angesprochen wird.
ZeRemz
2

Verwenden Sie die System.Web.Helpers.Crypto NuGet-Paket von Microsoft. Es fügt dem Hash automatisch Salz hinzu.

Sie haben ein Passwort wie folgt: var hash = Crypto.HashPassword("foo");

Sie überprüfen ein Passwort wie folgt: var verified = Crypto.VerifyHashedPassword(hash, "foo");

Kai Hartmann
quelle
0

Wenn Sie keinen asp.net- oder .net-Kern verwenden, gibt es auch eine einfache Möglichkeit in> = .Net Standard 2.0-Projekten.

Zuerst können Sie die gewünschte Größe der Hash-, Salt- und Iterationsnummer festlegen, die sich auf die Dauer der Hash-Generierung bezieht:

private const int SaltSize = 32;
private const int HashSize = 32;
private const int IterationCount = 10000;

Um das Passwort Hash und Salt zu generieren, können Sie Folgendes verwenden:

public static string GeneratePasswordHash(string password, out string salt)
{
    using (Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes(password, SaltSize))
    {
        rfc2898DeriveBytes.IterationCount = IterationCount;
        byte[] hashData = rfc2898DeriveBytes.GetBytes(HashSize);
        byte[] saltData = rfc2898DeriveBytes.Salt;
        salt = Convert.ToBase64String(saltData);
        return Convert.ToBase64String(hashData);
    }
}

Um zu überprüfen, ob das vom Benutzer eingegebene Kennwort gültig ist, können Sie anhand der Werte in Ihrer Datenbank Folgendes überprüfen:

public static bool VerifyPassword(string password, string passwordHash, string salt)
{
    using (Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes(password, SaltSize))
    {
        rfc2898DeriveBytes.IterationCount = IterationCount;
        rfc2898DeriveBytes.Salt = Convert.FromBase64String(salt);
        byte[] hashData = rfc2898DeriveBytes.GetBytes(HashSize);
        return Convert.ToBase64String(hashData) == passwordHash;
    }
}

Der folgende Komponententest zeigt die Verwendung:

string password = "MySecret";

string passwordHash = PasswordHasher.GeneratePasswordHash(password, out string salt);

Assert.True(PasswordHasher.VerifyPassword(password, passwordHash, salt));
Assert.False(PasswordHasher.VerifyPassword(password.ToUpper(), passwordHash, salt));

Microsoft Rfc2898DeriveBytes-Quelle

Eugstman
quelle
-1

Als Antwort auf diesen Teil der ursprünglichen Frage "Gibt es eine andere C # -Methode zum Hashing von Kennwörtern" können Sie dies mit ASP.NET Identity v3.0 https://www.nuget.org/packages/Microsoft.AspNet.Identity erreichen. EntityFramework / 3.0.0-rc1-final

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNet.Identity;
using System.Security.Principal;

namespace HashTest{


    class Program
    {
        static void Main(string[] args)
        {

            WindowsIdentity wi = WindowsIdentity.GetCurrent();

            var ph = new PasswordHasher<WindowsIdentity>();

            Console.WriteLine(ph.HashPassword(wi,"test"));

            Console.WriteLine(ph.VerifyHashedPassword(wi,"AQAAAAEAACcQAAAAEA5S5X7dmbx/NzTk6ixCX+bi8zbKqBUjBhID3Dg1teh+TRZMkAy3CZC5yIfbLqwk2A==","test"));

        }
    }


}
Dave Cornall
quelle
-1
 protected void m_GenerateSHA256_Button1_Click(objectSender, EventArgs e)
{
string salt =createSalt(10);
string hashedPassword=GenerateSHA256Hash(m_UserInput_TextBox.Text,Salt);
m_SaltHash_TextBox.Text=Salt;
 m_SaltSHA256Hash_TextBox.Text=hashedPassword;

}
 public string createSalt(int size)
{
 var rng= new System.Security.Cyptography.RNGCyptoServiceProvider();
 var buff= new byte[size];
rng.GetBytes(buff);
 return Convert.ToBase64String(buff);
}


 public string GenerateSHA256Hash(string input,string salt)
{
 byte[]bytes=System.Text.Encoding.UTF8.GetBytes(input+salt);
 new System.Security.Cyptography.SHA256Managed();
 byte[]hash=sha256hashString.ComputedHash(bytes);
 return bytesArrayToHexString(hash);
  }
Ankush Shukla
quelle
andere Methode ist string password = HashPasswordForStoringInConfigFile (TextBox1.Text, SHA1)
ankush shukla
-6
create proc [dbo].[hash_pass] @family nvarchar(50), @username nvarchar(50), @pass nvarchar(Max),``` @semat nvarchar(50), @tell nvarchar(50)

as insert into tbl_karbar values (@family,@username,(select HASHBYTES('SHA1' ,@pass)),@semat,@tell)
ehsan
quelle