c't 20/2023
S. 130
Wissen
Schlüsselableitungsfunktionen
Bild: Albert Hulm

Schlüsselmacher

Wie Schlüsselableitungsfunktionen funktionieren und was sie mit Passwort-Hashes zu tun haben

Schlüsselableitungsfunktionen schützen zum Beispiel das Passwort, mit dem Sie Ihren Rechner entschlüsseln, und kommen zum Einsatz, wenn Anbieter Ihre Account-Passwörter speichern. Diverse dieser Funktionen buhlen mit unterschiedlichen Vorteilen um die Gunst von Entwicklern, aber nicht jede Variante ist in jeder Situation empfehlenswert.

Von Sylvester Tremmel

Passwörter als Zugangsschutz sind allgegenwärtig – und problematisch. Vor allem, weil Nutzer aus Bequemlichkeit regelmäßig eher schlechte Passwörter verwenden. Und auch wenn bessere Alternativen wie Passkeys bereitstehen [1], werden uns Passwörter noch lange erhalten bleiben.

Umso wichtiger ist, dass man Passwörter möglichst sicher verarbeitet und in einer Form speichert, die Rückschlüsse auf die geschützten Werte verhindert. Dabei helfen Schlüsselableitungsfunktionen (key-derivation functions, KDF) und Passwort-Hashing-Funktionen (PHF). PHFs und KDFs dienen unterschiedlichen Zwecken, sind technisch aber sehr ähnlich angelegt. So sehr, dass der – nicht unwichtige – Unterschied oft ausgeblendet wird und man nur von „KDFs“ spricht.

KDFs und PHFs

Wie ihr Name nahelegt, produzieren Schlüsselableitungsfunktionen einen Schlüssel, also eine Bytefolge einstellbarer Länge, die sich als Schlüssel in einem Verschlüsselungsalgorithmus benutzen lässt. Den Schlüssel leiten sie aus irgendwelchen Eingabedaten ab. In diesem Artikel geht es um KDFs, die den Schlüssel aus einem Passwort ableiten, also um passwortbasierte Schlüsselableitungsfunktionen (PBKDF).

Dieser Anwendungsfall ist so häufig, dass oft vereinfachend von KDFs gesprochen wird, wenn man eigentlich PBKDFs meint. Das vermeidet auch Verwechslungen mit PBKDF2, einer konkreten Schlüsselableitungsfunktion mit einem sehr generischen Namen. Auch in diesem Artikel schreiben wir bloß „KDF“, meinen aber passwortbasierte KDFs.

KDFs kommen beispielsweise dann zum Einsatz, wenn Sie ein Passwort eingeben, um die Festplatte Ihres Rechners oder die Datenbank Ihres Passwortmanagers zu entschlüsseln. Obwohl es sich bei der Wahl der KDF eigentlich um Implementierungsdetails der jeweiligen Software handelt, können Endnutzer gelegentlich aus verschiedenen KDFs wählen. Beispielsweise erlauben der Passwortmanager KeePassXC oder die unter Linux verbreitete Festplattenverschlüsselung nach dem LUKS-Standard [2] eine Wahl der KDF.

Passwort-Hash-Funktionen dienen einem anderen Zweck: Mit ihrer Hilfe will man Passwörter so speichern, dass sie nicht mehr rekonstruierbar sind, man ein eingegebenes Passwort aber dennoch mit dem gespeicherten vergleichen kann. Beispielsweise sollten Webseiten die (Account-)Passwörter ihrer Kunden geschützt durch PHFs speichern. In der Praxis spricht man häufig davon, dass die Passwörter „gehasht und gesalzen“ werden (siehe Kasten „Salz und Pfeffer“).

Die Ausgabe einer PHF ist in der Regel eine Zeichenkette fester Länge. Wie bei einer herkömmlichen kryptografischen Hash-Funktion [3] muss der Hash eines Passworts eindeutig sein und man darf aus dem Hash nicht auf das Passwort schließen können. Kommt einem Anbieter seine Datenbank mit den Hashes der Kundenpasswörter abhanden, nützt sie Angreifern wenig – so die Idee –, weil sie von den Hashes nicht auf die Passwörter schließen können. Wenn sich dagegen im regulären Betrieb ein Kunde anmeldet, wendet der Anbieter die PHF auf das übergebene Passwort an und sieht nach, ob das Ergebnis mit dem gespeicherten Hash übereinstimmt.

Grundsätzlich kann man jede KDF als PHF verwenden, indem man vom Passwort einen „Schlüssel“ in der gewünschten Länge ableitet und als Zeichenfolge kodiert, beispielsweise per Base64 – fertig ist der Hash. Von diesem Umstand rührt die häufige Gleichsetzung von PHFs mit KDFs her. Allerdings ist dieses Vorgehen nicht unproblematisch, wie wir weiter unten erklären werden. KDFs geben nicht immer gute PHFs ab.

Rohe Gewalt

Während der Nutzen von PHFs relativ offensichtlich ist – Anbieter sollten Passwörter nicht im Klartext speichern –, kann man sich bei KDFs die Frage stellen, warum nicht einfach ein Passwort direkt als Schlüssel verwendet wird.

Das hat zum einen praktische Gründe: Verschlüsselungsalgorithmen haben in der Regel Anforderungen an die Länge eines Schlüssels, der außerdem als binärer Wert vorliegen soll. Passwörter bestehen dagegen aus tippbaren Zeichen und sie auf eine feste Länge zu beschränken, ist kontraproduktiv.

Noch wichtiger: Insbesondere schlechte Passwörter haben – kryptografisch ausgedrückt – (zu) wenig Entropie. Statt einer zufällig anmutenden Folge von Bytes ist ein Passwort eine häufig überhaupt nicht zufällige Zeichenfolge. Schlimmstenfalls folgt auf „1“ das Zeichen „2“, dann „3“, „4“, „5“ und das wars.

Beide Probleme behebt jede beliebige kryptografische Hash-Funktion, etwa SHA-256: Aus einem Passwort machen sie eine praktisch eindeutige, zufällig anmutende Bytefolge fester Länge. Allerdings sind typische kryptografische Hashfunktionen unter anderem auf Geschwindigkeit und Effizienz optimiert. Diese oft gewünschte und nötige Eigenschaft ist bei einer Verwendung als KDF schlecht, denn sie räumt eine Angriffsmöglichkeit nicht aus: Das massenhafte Ausprobieren von Passwörtern mit Wörterbüchern oder Brute Forcing.

Dem von „12345“ abgeleiteten Schlüssel kann man nicht ansehen, von welch schwachem Passwort er stammt, aber ein Angreifer kann einfach „12345“ und Millionen andere schwache Passwörter ausprobieren und testen, ob die so entstandenen Schlüssel funktionieren. Am besten unterbindet man solche Angriffe, indem man nicht beliebig viele Passwort-Versuche zulässt. Das ist allerdings schwierig, wenn Angreifern die Hardware an sich in die Hände fällt. Hardware-Sicherheitsmodule helfen hier (siehe Kasten „Salz und Pfeffer“), aber man muss ihnen vertrauen und sie sind nicht in jedem Anwendungsszenario verfügbar.

Einen Ausweg bieten planvoll ineffiziente Funktionen. Die Grundidee ist simpel: Eine KDF, die zur Ableitung des Schlüssels aus einem Passwort eine oder zwei Sekunden benötigt, ist in vielen Anwendungsfällen vollkommen akzeptabel. Beispielsweise booten Computer ohnehin einige Sekunden (oder auch länger) und wenn sich der Bootvorgang um zwei Sekunden verlängert, weil der Rechner erst noch den Festplattenschlüssel aus dem Passwort ableiten muss, stört das kaum.

Für Angreifer stellt so eine KDF allerdings ein herbes Hindernis dar: Massenhaft Passwörter ausprobieren gerät zur vollkommen impraktikablen Ewigkeitsaufgabe, wenn man auf jedes Passwort zwei Sekunden warten muss. Essenziell ist, dass so eine KDF nicht nur irgendwie ineffizient programmiert ist, sondern sich grundsätzlich nicht effizienter implementieren lässt. Gäbe es so eine Abkürzung, wäre der Effekt perdu.

Compute-hard

In genau diese Kerbe schlägt PBKDF2, die „Password-Based Key Derivation Function 2“. Vereinfacht gesagt wendet PBKDF2 eine effiziente pseudozufällige Funktion – häufig eine HMAC-Konstruktion auf Basis von SHA-2 – immer wieder an. Der Trick ist, dass man einstellen kann, wie viele solcher „Runden“ das Verfahren drehen soll, um den Schlüssel abzuleiten. Wenn eine einzelne Anwendung von PBKDF2 mehrere hunderttausend Mal die interne Funktion ausführt, dann braucht dieses Gesamtkonstrukt Zeit, auch wenn sich die zugrundeliegende Funktion sehr schnell berechnen lässt.

PBKDF2 ist eine weit verbreitete Schlüsselableitungsfunktion und ein typisches Beispiel einer „rechen-harten“ (compute-hard) KDF: Die Ausführungsgeschwindigkeit von PBKDF2 ist im Wesentlichen davon begrenzt, wie schnell die genutzte CPU arbeitet. Allerdings gehen mit dem Ansatz einer solchen Funktion zwei praktische Probleme einher, begründet in der – nach wie vor beachtlichen – Performance-Steigerung immer neuer Hardware-Generationen.

Zum einen bedeutet dieser Fortschritt, dass man die Rundenzahl von PBKDF2 relativ häufig neu einstellen muss, damit die Funktion auch auf brandneuer Hardware ausreichend Verzögerung erzielt. Das ist nicht nur lästig, sondern stellt auch Anwender vor Probleme, die selbst noch ältere Hardware einsetzen: Sie müssen mit deutlichen Wartezeiten leben oder eine eigentlich nicht mehr angemessen kleine Rundenzahl bei PBKDF2 einstellen.

Noch schwerer wiegt, dass Angreifer keineswegs dieselbe Hardware einsetzen müssen wie reguläre Nutzer, und gerade bei der Rechenperformance gibt es massive Unterschiede. Finanziell ausreichend ausgestattete Angreifer können anwendungsspezifische integrierte Schaltungen (application-specific integrated circuit, ASIC) anfertigen lassen, die Hashes hocheffizient und brachial schnell berechnen. Seit dem Bitcoin-Boom sind solche ASICs sogar sehr verbreitet, denn auch beim Mining vieler Kryptowährungen kommt es darauf an, möglichst schnell und effizient Hashes zu berechnen. Und auch FPGAs (Field Programmable Gate Array) erreichen zwar nicht die Taktraten moderner CPUs, können Hashes aber trotzdem kosten- und energieeffizienter als diese berechnen.

Spezialisierte Schaltungen, die Hash-Funktionen schnell und effizient berechnen, sind spätestens seit dem Bitcoin-Boom leicht verfügbar.
Spezialisierte Schaltungen, die Hash-Funktionen schnell und effizient berechnen, sind spätestens seit dem Bitcoin-Boom leicht verfügbar.

Angreifer müssen aber nicht unbedingt zu Spezialhardware greifen, um einen Vorteil bei der Hash-Berechnung zu erlangen. Auch GPUs von der Stange bringen Rechenpower mit, die bei der Hash-Berechnung jede CPU in den Schatten stellt – sowohl hinsichtlich der Geschwindigkeit als auch in Bezug auf die Kosten- und Energieeffizienz.

Eine gute KDF muss also auch bei Anwendern mit eher schwachbrüstiger Hardware noch ausreichend schnell sein und darf dennoch bei einem Angreifer mit teurer oder spezialisierter Hardware nicht zu schnell sein. Die enorme Spannbreite verfügbarer Rechenperformance stellt daher ein Problem für den rechen-harten Ansatz dar.

Memory-hard

Abhilfe schafft eine andere Klasse von Schlüsselableitungsfunktionen, nämlich solche, die „Speicher-hart“ (memory-hard) sind. Im Unterschied zu PBKDF2 & Co. spannen solche KDFs für die Berechnung relevante Mengen Arbeitsspeicher ein. Wie viel Speicher in Beschlag genommen werden soll, ist einstellbar.

Speicher statt Rechenkapazität klingt nach Jacke wie Hose? Schließlich wachsen auch die Speicherkapazitäten moderner Hardware kontinuierlich? Das stimmt, aber trotzdem ist der Ansatz effektiv. Denn auch wenn moderne Grafikkarten 12 oder 24 Gigabyte RAM mitbringen: Diese Karten haben Tausende oder sogar Zehntausende Rechenkerne, die nicht alle gleichzeitig im RAM lesen und schreiben können. Speicher-harte KDFs lassen sich also mit GPUs viel weniger gut beschleunigen als rechen-harte. Der Arbeitsspeicher und insbesondere seine Anbindung wird dabei zum Flaschenhals, lange bevor eine GPU all ihre Rechenkerne einspannen kann.

Auch gegen FPGAs und ASICs bieten Speicher-harte Ableitungsfunktionen einigen Schutz: schlicht, weil es auch bei Spezialhardware teuer und schwierig ist, sie mit so viel RAM auszustatten, der so breitbandig und schnell angeschlossen ist, dass man viele Rechenkerne auslasten kann.

Der bekannteste Vertreter dieser Art von KDF ist Argon2, eine Schlüsselableitungsfunktion, von der es drei verschiedene Varianten gibt: Argon2d, Argon2i und Argon2id. Alle drei erlauben festzulegen, wie viel Speicher und Rechenzeit für eine Schlüsselableitung in Anspruch genommen werden. Sie sind also nicht nur Speicher-, sondern auch rechen-hart. Argon2d greift auf den genutzten Speicher in einer Art und Weise zu, die vom eingegebenen Passwort abhängt. Das behindert eventuelle Vorausberechnungen und erschwert es Angreifern, Time-Memory-Tradeoffs zu finden, also Modifikationen des Algorithmus, die mehr (billige) Rechenzeit aber weniger (teuren) Speicher benötigen.

Der Nachteil solcher passwortabhängiger Speicherzugriffe sind potenzielle Seitenkanalangriffe. Es besteht das Risiko, dass ein Angreifer, der die Speicherzugriffe bei der Schlüsselableitung beobachten kann, daraus Rückschlüsse auf das Passwort zieht. Argon2i vermeidet diese Gefahr durch passwortunabhängige Speichernutzung. Argon2id, in der Regel die empfohlene Variante, stellt den Kompromiss dar, der teilweise passwortabhängig und teilweise davon unabhängig auf den Speicher zugreift.

Cache-hard

Argon2id ist eine gute, verbreitete und empfehlenswerte Schlüsselableitungsfunktion. Einen großen Teil ihrer Bekanntheit verdankt diese KDF allerdings dem Umstand, dass sie 2015 zur Sieger-PHF der „Password Hashing Competition“ gekürt wurde – eine Entscheidung, die zumindest einige Jurymitglieder für falsch halten. Eines davon ist Jeremi Gosney, der das Resultat auf Twitter so zusammenfasst: „Im Grunde genommen haben wir komplett versagt. Wir wollten die eine wahre PHF identifizieren und haben stattdessen nur eine weitere KDF gekürt.“

Den Knackpunkt erklärt Gosney gegenüber c’t so: In der Praxis darf IT-Security nicht zu teuer oder aufwendig geraten, darf also nicht beliebig Hardware und Rechenzeit kosten. Eine KDF läuft eher selten und in Situationen, in denen eine gewisse Wartezeit akzeptabel ist. Eine Passwort-Hashing-Funktion läuft dagegen auf einem möglicherweise gut ausgelasteten Server und kann daher nicht gigabyteweise RAM belegen und sekundenlang herumrechnen. Sie muss mit so wenig Ressourcen auskommen, dass auch mehrere fast gleichzeitige Log-in-Anfragen bearbeitet werden können, und sie muss so schnell fertig sein, dass Nutzer die Wartezeit nicht als lahmenden Server wahrnehmen.

Gosney zufolge werden PHFs oft nur ein paar hundert Millisekunden Laufzeit eingeräumt, wenn überhaupt. Nun lassen sich die Argon2-Funktionen (und auch andere Speicher-harte Funktionen wie beispielsweise scrypt) mit ihren Parametern so konfigurieren, dass sie auf der gegebenen Hardware diese Rahmenbedingungen einhalten. Dann allerdings können Argon2 & Co. ihre Flaschenhälse nicht ideal zur Geltung bringen. Dafür bräuchten sie mehr Zeit und müssten mehr RAM belegen.

In solchen Situationen schlägt sich überraschenderweise bcrypt besser als Argon2 und andere typische Kandidaten. Der Speicherbedarf dieser über 20 Jahre alten PHF ist gering und nicht einstellbar, bcrypt ist also nicht Speicher-hart. Die Funktion hat aber – unbeabsichtigterweise – eine Eigenschaft, die Gosney „Cache-hart“ nennt: bcrypts Speicherzugriffe werden aus dem (L1-)Cache einer modernen CPU bedient und geschehen so häufig, dass sie die Antwortgeschwindigkeit des Cache ausreizen. GPUs mit mehr Kernen oder besserem RAM können bcrypt also nicht gut beschleunigen, sie bräuchten schnellere Caches.

Noch besser als das alternde bcrypt sind Funktionen wie pufferfish2 und bscrypt, die explizit als Cache-harte PHFs entworfen wurden. Sie vermeiden einige Fallstricke von bcrypt – etwa die Limitierung des Passworts auf 72 Byte – und nutzen etwas mehr Speicher, um die L2- oder L3-Caches auszulasten. Das behindert auch Hardware-Spezialanfertigungen wie ASICs und FPGAs, die für gute Beschleunigung viele dieser relativ großen Caches bräuchten.

ROM-hard

Ebenfalls Ansprüche an die Caches stellt yescrypt, eine KDF, die mittlerweile einige Linux-Distributionen für Passwort-Hashes nutzen. Yescrypt ist eine eierlegende Wollmilchsau: Die Funktion ist Cache-hart, Speicher-hart, rechen-hart – und auf Wunsch sogar Festwertspeicher-hart (ROM-hard). Das bedeutet, die Funktion beansprucht optional giga- oder sogar terabyteweise Massenspeicher für ihre Berechnungen, den man einmalig initialisieren muss.

Gedacht ist die Eigenschaft für große Authentication-Provider, die so schnell so viele Login-Vorgänge bearbeiten müssen, dass sie dedizierte Systeme zum Hashen nutzen. Die stellen mit der Massenspeichernutzung Botnetz-Betreiber vor ernste Probleme: Botnetze bieten viel RAM, CPU- und GPU-Power – noch dazu kostenfrei für die kriminellen Betreiber –, aber sie haben keinen großen gemeinsamen Speicher. ROM-hart konfigurierte yescrypt-Hashes lassen sich daher nicht gut mit Botnetzen knacken.

Allerdings greift yescrypt (wie bcrypt, scrypt und Argon2d) passwortabhängig auf Speicher zu und ist damit anfällig für die erwähnten Seitenkanalangriffe. Zudem geht mit der Rundumversorgung auch eine erhebliche Komplexität einher, die Raum für Fehlkonfigurationen lässt.

Was tun?

Wenn Sie vor der Wahl einer Schlüsselableitungsfunktion stehen, machen Sie mit Argon2id nichts falsch. Wenn Seitenkanalangriffe keine Gefahr darstellen, bietet Argon2d sogar noch ein bisschen mehr Schutz. Wichtig ist, dass Sie individuelle Salts verwenden und der Funktion ausreichend Speichernutzung und Laufzeit einräumen, denn nur dann kann sie ihren Effekt voll ausspielen. Die genauen Werte hängen von Ihrer Hardware ab, ein, zwei Sekunden sollte die Schlüsselableitung schon dauern dürfen.

Schwieriger ist eine Empfehlung für Passwort-Hashing-Funktionen. Das Open Worldwide Application Security Project (OWASP) nennt Minimalkonfigurationen und empfiehlt Argon2id, scrypt, bcrypt und PBKDF2 in absteigender Präferenz (Links unter ct.de/yt51). Steve Thomas, ebenfalls Jurymitglied der Password-Hashing-Competition, veröffentlicht auf seiner Website dagegen empirisch ermittelte Werte, die bscrypt und bcrypt vor Argon2 sehen.

Das US-amerikanische NIST nennt einerseits explizit PBKDF2 und die (hier nicht erklärte) Balloon-Konstruktion als geeignete Funktionen, empfiehlt aber andererseits auch, Speicher-harte Funktionen zu nutzen, wozu PBKDF2 nicht zählt. Das Bundesamt für Sicherheit in der Informationstechnik (BSI) empfiehlt gar keine konkrete PHF. Auf Nachfrage von c’t gab man als Grund an, dass „Ein-Faktor-Authentisierung über ein Passwort grundsätzlich nicht empfehlenswert ist“.

Einig sind sich die meisten Akteure darin, dass man PBKDF2 wo möglich vermeiden sollte. Wer sich aufgrund rechtlicher Regularien oder zu erfüllender Standards zur Nutzung von PBKDF2 gezwungen sieht, kann die Anforderungen möglicherweise erfüllen, indem er scrypt oder yesscrypt einsetzt, denn diese Funktionen nutzen PBKDF2 als einen ihrer Bestandteile.

Vergessen darf man bei all dem auch nicht, dass KDFs und PHFs vornehmlich Passwörter in einem Graubereich schützen können: Wirklich gute Passwörter sind auch als herkömmlicher kryptografischer Hash nicht zu knacken und wirklich schlechte Passwörter kann auch die beste KDF oder PHF nicht schützen. Neben der Wahl einer vernünftigen Funktion und der regelmäßigen Kontrolle, ob ihre Parameter noch angemessen sind, sollten sich Entwickler daher darauf konzentrieren, Passwörter abzuschaffen [4]. Nutzer müssen einstweilen darauf achten, dass ihre Passwörter exzellent sind – auch wenns lästig ist. (syt@ct.de)

Konfigurationsempfehlungen: ct.de/yt51

Kommentieren