wake-up-neo.net

Hash-Passwort in C #? Bcrypt/PBKDF2

Ich habe in Msdn und anderen Ressourcen nachgesehen, wie das geht, aber ich habe keine klaren Lösungen gefunden. Dies ist das Beste, was ich gefunden habe http://blogs.msdn.com/b/shawnfa/archive/2004/04/14/generating-a-key-from-a-password.aspx?Redirected=true

Ich möchte Kennwörter in C # unter Verwendung von bcrypt oder PBKDF2 (das anscheinend bcrypt-bezogen ist) hashieren. Ich experimentiere gerne mit der Anzahl der Runden, die mein Computer benötigt, um ein Passwort einzugeben. Es scheint jedoch alles um das Verschlüsseln zu gehen, während alle über Hashing sprechen. Ich kann es nicht verstehen. Wie kann ich ein Passwort eingeben? Es sieht eher aus, als wäre PBKDF2 (Rfc2898?) Ein Zufallszahlengenerator, und ich verwende GetBytes (Anzahl), um zu bestimmen, wie groß meine Hashgröße ist.

Ich bin verwirrt. Wie genau kann ich ein Passwort mit bcrypt/PBKDF eingeben?

33
user34537

PBKDF2

Du warst wirklich nah dran. Der von Ihnen angegebene Link zeigt Ihnen, wie Sie die Funktion Rfc2898DeriveBytes aufrufen können, um PBKDF2-Hash-Ergebnisse zu erhalten. Sie wurden jedoch von der Tatsache abgewiesen, dass das Beispiel den abgeleiteten Schlüssel für Verschlüsselungszwecke verwendete (die ursprüngliche Motivation für PBKDF1 und 2 bestand darin, "Schlüssel" -Derivierungsfunktionen zu erstellen, die als Verschlüsselungsschlüssel geeignet sind). Natürlich möchten wir die Ausgabe nicht zur Verschlüsselung verwenden, sondern als eigenständigen Hash.

Sie können die Bibliothek " SimpleCrypto.Net " verwenden, die genau für diesen Zweck geschrieben wurde, wenn Sie PBKDF2 möchten. Wenn Sie auf die Implementierung schauen, können Sie sehen, dass es sich eigentlich nur um einen dünnen Wrapper handelt (Sie haben es erraten) Rfc2898DeriveBytes .

BCrypt

Sie können die C # -Implementierung mit dem Namen (was sonst) BCrypt.NET ausprobieren, wenn Sie mit dieser Variante experimentieren möchten.

Disclaimer: Ich habe keine der Bibliotheken verwendet oder getestet, mit denen ich verlinkt habe ... YMMV

32
paracycle

Ich brauchte für immer (Tage, die es Tage dauerte), um zu finden, was eigentlich Code ist , um gehashte Passwörter zu erhalten !! also habe ich es hier der Einfachheit halber gesetzt. 

Sie müssen die Dokumentation und Theorie1Theorie2 und dann einige oder Sie könnten für Sicherheitslücken offen sein. Sicherheit ist ein sehr großes Thema! Käufer Vorsicht!

Fügen Sie der Lösung das NuGet-Paket BCrypt.Net hinzu

const int WorkFactor = 14;
var HashedPassword = BCrypt.Net.BCrypt.HashPassword(Password, WorkFactor); 

Sie sollten WorkFactor entsprechend anpassen, siehe Diskussionen . Es ist ein log2 Funktion

Msgstr "Die Nummer ist log2, so dass jedes Mal, wenn sich die Computer doppelt so schnell sind, der Standardnummer 1 hinzufügt."

Dann speichern Sie das gehashte Passwort in Ihrer Datenbank als passwordFromLocalDB und testen eine eingehende password wie folgt: 

if (BCrypt.Net.BCrypt.Verify(password, passwordFromLocalDB) == true)

Viel Glück!

8
JPK

Anfang dieses Jahres habe ich mich mit dem Erstellen von Hashes für unser ASP.NET-Web Forms-Projekt befasst. Ich wollte es auf die gleiche Weise tun, wie es MVC-Projekte normalerweise tun.

Ich stolperte über diese Frage => ASP.NET Standardidentität Kennwort Hasher, wie funktioniert es und ist es sicher? Dann fand ich die Quelle mit der Methode ByteArraysEqual hier => http://www.symbolsource.org/MyGet/Metadata/aspnetwebstacknightly/Project/Microsoft.AspNet.Identity.Core/2.0.0-rtm -140327/Release/Default/Microsoft.AspNet.Identity.Core/Microsoft.AspNet.Identity.Core/Crypto.cs? ImageName = Microsoft.AspNet.Identity.Core

2
Luke T O'Brien

Zunächst fordere ich alle auf, einen kryptografisch verifizierten Referenzalgorithmus zu verwenden, der in der Plattform selbst enthalten ist.

Verwenden Sie keine Pakete von Drittanbietern und nicht verifizierten OSS-Komponenten oder anderen Code, den Sie gerade aus dem Internet kopiert haben.

Verwenden Sie für .NET PBKDF2 und nicht bCrypt , da es keine zertifizierte Implementierung von gibt bCrypt für .NET

Ich meine keine Respektlosigkeit gegenüber edlen Open-Source-Entwicklern (selbst einer), aber Sie können nie sicher sein, dass ihre Website in 10 Jahren nicht gehackt wird und Sie erhalten ein Malware-Paket von Nuget/npm oder einem anderen Paketmanager.

Weitere Informationen zur Bestätigung finden Sie in this SO answer

Zurück zu PBKDF2, hier ist der einfache Code

public static byte[] PBKDF2Hash(string input, byte[] salt)
{
    // Generate the hash
    Rfc2898DeriveBytes pbkdf2 = new Rfc2898DeriveBytes(input, salt, iterations: 5000);
    return pbkdf2.GetBytes(20); //20 bytes length is 160 bits
}

Wenn Sie eine Zeichenfolgendarstellung des Hash benötigen (kein Byte-Array), können Sie diese superschnelle Konvertierungsklasse aus dieser Antwort verwenden http://stackoverflow.com/a/624379/7147

2
Alex

PBKDF2 verwendet HMACSHA1. Wenn Sie eine modernere und anpassbare Lösung wünschen, sollten Sie sich diese API mit HMACSHA256 oder 512 mit Schlüsseldehnung genau wie PBKDF2 anschauen

https://sourceforge.net/projects/pwdtknet/

Eine im Quellcode enthaltene Beispiel-GUI demonstrierte, wie ein Hash aus einem Kennwort abgerufen wird, einschließlich der Erstellung von zufälligem Krypto-Salz. 

1
thashiznets

Microsoft hat eine Seite mit Beispielcode mit PBKDF2 für alle, die .Net Core verwenden:

Hash-Passwörter in ASP.NET Core

Aus dem Artikel:

using System;
using System.Security.Cryptography;
using Microsoft.AspNetCore.Cryptography.KeyDerivation;

public class Program
{
    public static void Main(string[] args)
    {
        Console.Write("Enter a password: ");
        string password = Console.ReadLine();

        // generate a 128-bit salt using a secure PRNG
        byte[] salt = new byte[128 / 8];
        using (var rng = RandomNumberGenerator.Create())
        {
            rng.GetBytes(salt);
        }
        Console.WriteLine($"Salt: {Convert.ToBase64String(salt)}");

        // derive a 256-bit subkey (use HMACSHA1 with 10,000 iterations)
        string hashed = Convert.ToBase64String(KeyDerivation.Pbkdf2(
            password: password,
            salt: salt,
            prf: KeyDerivationPrf.HMACSHA1,
            iterationCount: 10000,
            numBytesRequested: 256 / 8));
        Console.WriteLine($"Hashed: {hashed}");
    }
}

/*
 * SAMPLE OUTPUT
 *
 * Enter a password: Xtw9NMgx
 * Salt: NZsP6NnmfBuYeJrrAKNuVQ==
 * Hashed: /OOoOer10+tGwTRDTrQSoeCxVTFr6dtYly7d0cPxIak=
 */
1
pcdev

Für PBKDF2 können Sie möglicherweise System.Security.Cryptography.Rfc2898DeriveBytes verwenden.

Siehe MSDN hier: http://msdn.Microsoft.com/de-de/library/system.security.cryptography.rfc2898derivebytes.aspx

1
Jay S

ich war an Antworten interessiert, die keine Bibliotheken enthielten.

Ich habe diesen Artikel https://crackstation.net/hashing-security.htm gelesen, der eine Implementierung in verschiedenen Sprachen C # verlinkt, die ich hier auch verlinken werde

https://github.com/defuse/password-hashing/blob/master/PasswordStorage.cs

interessanterweise verwendet es Rfc2898DeriveBytes, wie hier schon einige Male erwähnt.

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

PBKDF2

In dem Beispiel in http://msdn.Microsoft.com/en-us/library/system.security.cryptography.rfc2898derivebytes.aspx , wenn Sie zur Zeile "Rfc2898DeriveBytes k1 = new Rfc2898DeriveBytes (pwd1, salt1) gelangen , myIterations); ", k1 ist der Hash. Der Grund für die Verschlüsselung liegt darin, dass Rfc2898DeriveBytes ursprünglich zum Erstellen von Verschlüsselungsschlüsseln entwickelt wurde.

Wenn Sie kein Salt angeben, erstellt Rfc2898DeriveBytes sein eigenes, aber ich weiß nicht, ob RNGCryptoServiceProvider besser kryptografisch zufällig ist.

Laut OWASP ( https://www.owasp.org/index.php/Using_Rfc2898DeriveBytes_for_PBKDF2 ) bedeutet die zugrunde liegende Verwendung von SHA1 durch Rfc2898DeriveBytes, dass es nur für Hashes mit einer Länge von bis zu 160 Bit geeignet ist. Wenn Sie einen längeren Hash erstellen, muss sich ein Angreifer nur noch um die ersten 160 Bits kümmern, aber Sie haben das Passwort-Hashing/die Authentifizierung für sich selbst ohne zusätzlichen Gewinn verteuert.

Hier ist ein Beispielcode für Rfc2898DeriveBytes-Passwort-Hashing (Speichern von Hash, Salt und Iterationen in der Datenbank):

public class Rfc2898PasswordEncoder
{
    private int _byteLength = 160 / 8; // 160 bit hash length

    public class EncodedPassword
    {
        public byte[] Hash { get; set; }
        public byte[] Salt { get; set; }
        public int Iterations { get; set; }
    }

    public EncodedPassword EncodePassword(string password, int iterations)
    {
        var populatedPassword = new EncodedPassword
        {
            Salt = CreateSalt(),
            Iterations = iterations
        };

        // Add Hash
        populatedPassword.Hash = CreateHash(password, populatedPassword.Salt, iterations);

        return populatedPassword;
    }

    public bool ValidatePassword(string password, EncodedPassword encodedPassword)
    {
        // Create Hash
        var testHash = CreateHash(password, encodedPassword.Salt, encodedPassword.Iterations);

        return testHash == encodedPassword.Hash;
    }

    public byte[] CreateSalt()
    {
        var salt = new byte[_byteLength]; // Salt should be same length as hash

        using (var saltGenerator = new RNGCryptoServiceProvider())
        {
            saltGenerator.GetBytes(salt);
        }

        return salt;
    }

    private byte[] CreateHash(string password, byte[] salt, long iterations)
    {
        byte[] hash;
        using (var hashGenerator = new Rfc2898DeriveBytes(password, salt, (int)iterations))
        {
            hash = hashGenerator.GetBytes(_byteLength);
        }

        return hash;
    }
} 
0
Phil