Ratgeber · Kryptografie-Historie

Passwörter sicher hashen: bcrypt, scrypt, Argon2

Passwörter brauchen einen anderen Hash als Dateien. SHA-256 ist absichtlich schnell, eine GPU rechnet Milliarden pro Sekunde. bcrypt, scrypt und Argon2 sind absichtlich langsam und Memory-hart. Welche Funktion wann passt, klärt der Ratgeber.

7 Min Lesezeit 1.521 Wörter 5 FAQs
Jan-Tristan Rudat
Jan-Tristan RudatRedakteur · Kryptografie-Historie & Algorithmen
Geprüft am

Warum SHA-256 für Passwörter falsch ist

SHA-256 ist eine schnelle Hash-Funktion. Das ist im Kontext von Checksums, Signaturen und Integritätsprüfungen ein Feature, im Kontext von Passwort-Speicherung ist es ein Problem. Auf einer modernen GPU rechnet SHA-256 etwa 1 Milliarde Operationen pro Sekunde. Eine Hashcat-Cluster mit 8 RTX 4090 schafft 10 Milliarden, Spezial-ASICs nochmal eine Größenordnung mehr.

Passwörter haben typischerweise wenig Entropie. Ein 8-stelliges Passwort aus Buchstaben (26+26=52 Zeichen) hat 52^8 = 5,3 * 10^13 Möglichkeiten, das sind etwa 2^45,6 Möglichkeiten. Auf einem GPU-Cluster mit 10 Milliarden Hashes pro Sekunde sind das 5.300 Sekunden, also gut 90 Minuten Brute-Force-Zeit. Mit Sonderzeichen (etwa 95 Zeichen) sind es 95^8 = 2^52,6, also etwa 6 Tage.

Das ist keine theoretische Übung. Dumps von kompromittierten Datenbanken (LinkedIn 2012, Yahoo 2013, RockYou 2009 und Dutzende seither) haben hunderte Millionen unsalted oder schlecht gehashed Passwörter publik gemacht. Auf hashes.org, einer öffentlichen Plattform, sind über 99 Prozent der dort hochgeladenen SHA-256-Hashes inzwischen geknackt, nicht weil die Hashes “kaputt” sind, sondern weil die Passwörter es waren.

Passwort-Hashes brauchen also einen ganz anderen Eigenschafts-Mix: Sie müssen absichtlich langsam sein, idealerweise auch Memory-hart, sodass weder GPU-Parallelisierung noch Spezial-ASICs einen drastischen Vorteil gegenüber einer normalen CPU haben.

bcrypt: Niels Provos und David Mazières 1999

Den Anfang machten Niels Provos und David Mazières mit bcrypt, vorgestellt auf der USENIX Annual Technical Conference 1999. Die Idee: Verwende eine bestehende Blockchiffre (Blowfish) und definiere einen iterativen “Schedule”, der pro Hashing tausende Blowfish-Schlüssel-Setups durchläuft. Der entscheidende Trick: Blowfish-Schlüssel-Setup ist absichtlich langsam, weil eine große Schlüssel-Schedule berechnet werden muss.

bcrypt hat einen Cost-Faktor, logarithmisch ausgedrückt. Cost 10 (Default in vielen Frameworks) bedeutet 2^10 = 1024 Setups, Cost 12 bedeutet 4096, Cost 14 bedeutet 16384. Auf einem 2024er Server-Kern liefert Cost 12 etwa 250 bis 300 ms pro Hashing. Eine GPU bringt bei bcrypt überraschend wenig Vorteil, weil der Speicher-Zugriff-Pattern serialisiert ist.

Das bcrypt-Hash-Format ist ein selbst beschreibender String: $2b$12$Y9kP3WaJq...salt...hash.... Die ersten Zeichen kodieren die Variante (2b ist aktuell), den Cost-Faktor (12) und den eingebauten Salt. Bibliotheken wie OpenBSD bcrypt, Python passlib, Node.js bcrypt und Java jBCrypt implementieren das Format konsistent.

Schwäche von bcrypt: Es hat einen kleinen, festen Memory-Footprint (4 KB pro Hashing). Mit Custom-ASICs lässt sich dieser Footprint vervielfachen, und der Algorithmus läuft entsprechend parallelisiert. In der Praxis bleibt bcrypt aber sicher genug, wenn der Cost-Faktor zeitgemäß gewählt wird.

scrypt: Colin Percival 2009

Colin Percival, damals Tarsnap-Gründer, veröffentlichte 2009 scrypt als Antwort auf die bcrypt-ASIC-Schwäche. scrypt ist explizit “memory-hard”: Es braucht pro Hashing eine konfigurierbare Menge Arbeitsspeicher (typisch 16 bis 256 MByte), in dem es Pseudo-Zufallszahlen erzeugt und dann pseudozufällig ausliest. Ein ASIC, der scrypt parallelisieren will, muss diesen Speicher mitbringen, was die Hardware drastisch verteuert.

scrypt hat drei Parameter: N (CPU/Memory-Cost, üblich 2^15 = 32768), r (Block-Size, üblich 8), p (Parallelization, üblich 1). Eine Standard-Konfiguration N=32768, r=8, p=1 braucht 32 MByte Memory und etwa 100 ms Rechenzeit auf einem modernen CPU-Kern.

scrypt ist die Basis von Litecoin (als Mining-Algorithmus) und einigen Backup-Tools (Tarsnap selbst). Im Web-Authentifikations-Bereich hat scrypt nie so weite Verbreitung bekommen wie bcrypt, weil die Bibliotheks-Unterstützung längere Zeit lückenhaft war. Heute (2026) ist scrypt in Node.js Kern eingebaut (crypto.scrypt), in Python passlib, in OpenSSL.

scrypt war ein wichtiger konzeptioneller Schritt: “Memory-Hardness” wurde damit zum etablierten Designziel. Argon2 baut darauf auf und perfektioniert die Idee.

Argon2: Password Hashing Competition 2015

Die Password Hashing Competition (PHC) lief von 2013 bis 2015 und sollte einen modernen Standard für Passwort-Hashing finden. 24 Entwürfe wurden eingereicht, 9 in die Finalrunde, im Juli 2015 erklärte das Auswahlkomitee Argon2 von Alex Biryukov, Daniel Dinu und Dmitry Khovratovich (Universität Luxemburg) zum Gewinner.

Argon2 kommt in drei Varianten:

  • Argon2d: data-dependent memory access. Maximal resistent gegen GPU/ASIC, aber potenziell anfällig für Side-Channel-Angriffe (Timing).
  • Argon2i: data-independent memory access. Robust gegen Side-Channel, etwas weniger GPU-resistent.
  • Argon2id: Hybrid, erste Hälfte i, zweite Hälfte d. Empfohlen für Passwort-Hashing.

Die OWASP-Empfehlung 2024 ist: Argon2id mit 19 MiB Memory, t=2 (Iterationen), p=1 (Parallelismus). Auf einem aktuellen Server-Kern braucht das etwa 100 ms. Wer mehr Sicherheits-Budget hat, geht auf 46 MiB Memory oder t=3. Wer weniger Server-Last verkraftet, geht auf 12 MiB.

Argon2 wurde 2021 als RFC 9106 standardisiert. Sprach-Bibliotheken existieren für alle gängigen Plattformen: argon2-cffi (Python), node-argon2 (Node.js), argon2-jvm (Java), passport-local-mongoose mit argon2-Plugin (Express.js).

Passwort-Hash-Funktionen im Vergleich bcrypt Provos/Mazières 1999 Blowfish-basiert Cost-Faktor logarithmisch 4 KB Memory Cost 12 = 250 ms scrypt Percival 2009 Memory-hard N, r, p Parameter 16-256 MByte Memory N=32768 = 100 ms Argon2id Biryukov et al. 2015 PHC-Gewinner m, t, p Parameter 19 MiB Memory OWASP-Default 2024
Drei Generationen Passwort-Hashes. Argon2id ist der aktuelle Standard, bcrypt und scrypt bleiben tragfähig.

Salt und Pepper: warum beides Sinn macht

Salt ist ein pro-Passwort zufälliger Wert, der vor dem Hashen mit dem Passwort konkateniert wird und zusammen mit dem Hash in der Datenbank gespeichert wird. Salt erfüllt zwei Aufgaben: Erstens verhindert es Rainbow-Tables (vorberechnete Hash-Wert-Tabellen für häufige Passwörter), zweitens macht es jeden Hash einmalig, sodass identische Passwörter verschiedener Nutzer verschiedene Hashes haben.

Salt-Länge: 16 Byte (128 Bit) ist Standard. bcrypt verlangt 16 Byte und produziert den Salt automatisch. Argon2 erlaubt frei wählbare Salt-Länge, 16 Byte ist Default.

Pepper ist ein zusätzlicher geheimer Wert, der außerhalb der Datenbank liegt (in der Anwendungs-Konfiguration, in einer HSM, in einem Secret-Manager). Pepper wird mit jedem Passwort verkettet, aber nie in der Datenbank gespeichert. Wenn ein Angreifer nur die Datenbank kompromittiert (was häufig vorkommt), nicht aber den Anwendungs-Code, sind die Passwort-Hashes ohne Pepper nicht angreifbar.

Pepper-Realisierung: Vor dem Hashen wird das Passwort mit dem Pepper konkateniert (password || pepper), oder, eleganter, mit HMAC-SHA-256 unter Pepper als Schlüssel “vorverdaut”. Die Pepper-Länge sollte mindestens 32 Byte (256 Bit) sein. Pepper wird selten rotiert, weil eine Pepper-Änderung alle Passwort-Hashes invalidieren würde.

OWASP empfiehlt: Salt ist zwingend, Pepper ist optional aber sinnvoll für hochsensible Systeme (Banking, Healthcare, behördliche Dienste).

Cost-Tuning in der Praxis

Faustregel: Ein Passwort-Hash sollte 250 bis 500 ms auf der eigenen Server-Hardware brauchen. Weniger ist ein zu schwacher Bremsfaktor gegen Brute-Force, mehr eine zu große Server-Last bei vielen gleichzeitigen Login-Versuchen.

Konkret für Argon2id auf einem 2024er-Server (Xeon Silver mit 64 GB RAM):

  • 12 MiB Memory, t=2, p=1: ca. 50 ms (zu wenig)
  • 19 MiB Memory, t=2, p=1: ca. 80 ms (OWASP-Default)
  • 46 MiB Memory, t=2, p=1: ca. 200 ms (gut für sensible Bereiche)
  • 64 MiB Memory, t=3, p=1: ca. 400 ms (Bank-Niveau)

Für bcrypt auf demselben Server:

  • Cost 10: ca. 60 ms (zu wenig)
  • Cost 12: ca. 250 ms (Standard)
  • Cost 14: ca. 1000 ms (sensible Bereiche)

Cost-Anpassung sollte automatisch passieren: Bei jedem Login prüft die Anwendung, ob der Hash mit dem aktuellen Cost-Faktor erstellt wurde. Falls nicht, wird das eingegebene Passwort erneut gehashed (jetzt mit neuem Cost) und in der DB ersetzt. So wandert die User-Base ohne Massen-Migration auf höhere Cost-Stufen. Frameworks wie Spring Security, Django, Rails machen das automatisch.

Was Sie nicht tun sollten

Drei wiederkehrende Anti-Patterns aus Code-Reviews:

Anti-Pattern 1: SHA-256 mit Salt für Passwörter. Funktioniert, ist aber kein Schutz gegen GPU-Bruteforce. Wer SHA-256 mit Salt sieht, sollte auf bcrypt oder Argon2 migrieren.

Anti-Pattern 2: Eigene Salt-Implementierung. “Wir nehmen die ersten 8 Zeichen des Usernamens als Salt.” Falsch, weil Username-Salts vorhersagbar sind. Salt muss kryptografisch zufällig sein (CSPRNG, z.B. crypto.randomBytes(16) in Node.js).

Anti-Pattern 3: Mehrfaches SHA-256. “Wir hashen einfach 1000 Mal SHA-256, das ist langsam genug.” Funktioniert prinzipiell (PBKDF2 macht das standardisiert), aber bcrypt und Argon2 sind besser, weil sie zusätzlich Memory-hart sind.

Die Methodik-Seite und die Autorenseite Jan-Tristan gehen auf den Hintergrund der Empfehlung ein. hash-generieren.de selbst macht ausdrücklich keine Passwort-Hashes, weil das ein anderes Tool wäre (mit Salt-Generierung und Argon2-Integration), nicht ein einfacher Online-Hash-Rechner. Korrekturhinweise gehen wie immer an die Korrekturen-Adresse.

Was hängenbleibt

Passwörter brauchen einen anderen Hash als Dateien. SHA-256 ist zu schnell, eine GPU rechnet Milliarden pro Sekunde durch. bcrypt (1999, Cost-Faktor), scrypt (2009, Memory-hard) und Argon2 (2015, PHC-Gewinner) sind die drei tragfähigen Alternativen. Aktuelle OWASP-Empfehlung ist Argon2id mit 19 MiB Memory, t=2, p=1. Salt ist zwingend (pro Passwort, 16 Byte zufällig), Pepper sinnvoll für sensible Systeme. Cost-Faktor regelmäßig prüfen und beim nächsten Login automatisch anheben, wenn die Hardware schneller geworden ist.

FAQ

Häufige Fragen

Warum reicht SHA-256 nicht für Passwörter?

Weil SHA-256 schnell ist und Passwörter typisch wenig Entropie haben. Eine moderne GPU rechnet etwa 1 Milliarde SHA-256-Hashes pro Sekunde, eine Cluster-Konfiguration noch deutlich mehr. Bei einem 8-stelligen Passwort mit Buchstaben und Zahlen sind das 62^8 = 218 Billionen Möglichkeiten, durchgerechnet in wenigen Stunden. Spezialisierte Passwort-Hashes wie bcrypt sind 10.000 Mal langsamer pro Operation und damit pro Bruteforce-Versuch 10.000 Mal teurer.

Was ist der Unterschied zwischen Salt und Pepper?

Salt ist ein pro-Passwort zufälliger Wert (16 Byte typisch), der zusammen mit dem Passwort gehashed und mit dem Hash zusammen in der Datenbank gespeichert wird. Salt verhindert Rainbow-Tables und macht jeden Hash einmalig. Pepper ist ein zusätzliches Geheimnis außerhalb der Datenbank (typisch im Anwendungs-Code oder in einer HSM), das mit jedem Passwort verkettet wird. Pepper schützt zusätzlich, wenn nur die Datenbank kompromittiert wird, nicht der Anwendungs-Code. Salt ist Pflicht, Pepper ein Plus.

bcrypt, scrypt oder Argon2: was wählen?

Argon2id ist die aktuelle Default-Empfehlung der OWASP (Stand 2024). Es ist der Gewinner der Password Hashing Competition von 2015, hybride aus Argon2i und Argon2d, also resistent gegen Side-Channel und gegen GPU/ASIC. Wenn Argon2 nicht verfügbar ist (Legacy-Systeme), ist scrypt die zweite Wahl, bcrypt die dritte. bcrypt funktioniert weiterhin sicher, hat aber einen kleinen Memory-Footprint, was es weniger ASIC-resistent macht als die jüngeren Funktionen.

Was bedeutet 'Cost-Faktor' bei bcrypt?

Der Cost-Faktor (manchmal Work-Faktor genannt) bestimmt, wie viele interne Iterationen die Hash-Funktion macht. Bei bcrypt ist der Cost-Faktor logarithmisch: Cost 10 bedeutet 2^10 = 1024 Iterationen, Cost 12 bedeutet 2^12 = 4096 Iterationen, also viermal so langsam. Üblich ist heute Cost 12 oder 13, das ergibt etwa 250 bis 500 Millisekunden Rechenzeit auf einem Server-Kern. Cost 14 (1 bis 2 Sekunden) ist für hochsensible Bereiche möglich, kostet aber Server-Last.

Wann muss ich den Cost-Faktor erhöhen?

Wenn die Hardware deutlich schneller geworden ist und das Ziel-Hash-Zeit-Budget unterschritten wird. Faustregel: Eine Hash-Berechnung sollte 250 bis 500 ms auf der eigenen Server-Hardware brauchen. Wenn ein Cost-Faktor in zwei Jahren nur noch 50 ms braucht, ist es Zeit, ihn zu erhöhen. Beim nächsten Login wird der Hash mit neuem Cost rehashed und in der DB ersetzt. So wandert die User-Base ohne Massen-Migration auf höhere Cost-Stufen. Ein guter Code-Pattern hat diese Cost-Anpassung eingebaut.

Anzeige

Quellen

Worauf dieser Ratgeber sich stützt

Veröffentlicht · zuletzt geprüft
Verantwortlich: Jan-Tristan Rudat
Anzeige
Anzeige
Anzeige
Anzeige