ubuntuusers.de

Hashfunktionen

Dieser Artikel wurde für die folgenden Ubuntu-Versionen getestet:

Dieser Artikel ist größtenteils für alle Ubuntu-Versionen gültig.

Zum Verständnis dieses Artikels sind folgende Seiten hilfreich:

Eine Hashfunktion ist eine mathematische Funktion, die eine beliebig große Menge an Eingabewerten möglichst gleichmäßig auf eine eingeschränkte Ausgabemenge abbildet. Je nach Verwendungszweck muss die Funktion verschiedene Eigenschaften erfüllen. Am bekanntesten sind die kryptografischen Hashfunktionen, z.B. MD5, SHA-1, SHA-2 oder SHA-3. Zum leichteren Verständnis werden hier aber zuerst einfachere Anwendungsmöglichkeiten beschrieben.

MD5 und SHA-1 gelten als nicht mehr sicher und sollten bei sicherheitsrelevanten Anwendungen nicht mehr verwendet werden. Standardmäßig ist aktuell SHA-2 für die meisten Aufgaben im Einsatz. Ubuntu und im Prinzip jede andere aktuelle Linux-Distribution verwenden beispielsweise SHA-512 für die lokale Passwortdatei (/etc/shadow). In letzter Zeit wird allerdings immer mehr der Einsatz von Schlüsselableitungsfunktionen für die Verschlüsselung von Passwörtern gefordert, wie dies z.B. schon für Mac OS X und iOS der Fall ist.

Nicht verwechseln sollte man Hashfunktionen mit dem Datentyp "Hash" verschiedener Programmiersprachen, auch als "Assoziatives Array" bekannt.

Programme

Die Kommandozeilenbefehle md5sum, sha1sum, sha256sum, sha512sum usw. sind im Paket coreutils enthalten, das unter Ubuntu vorinstalliert ist. Bevorzugt man dagegen eine grafische Oberfläche, kann man das Programm GtkHash verwenden.

Programme, die SHA-3 benutzen, sind noch wenig verbreitet. Für sha3sum muss das Paket libdigest-sha3-perl installiert werden.

Gerechte Verteilung

Die einfachsten Hashfunktionen dienen einfach nur dazu, eine unbestimmte Menge von Eingaben möglichst gerecht in eine bestimmte Anzahl Töpfe aufzuteilen. Ein Beispiel, das bestimmt jeder kennt, sind Behörden, in denen die Anfangsbuchstaben der Kundennamen bestimmten Sachbearbeitern zugeordnet werden. Alleine den Anfangsbuchstaben des Namens als Kriterium zu nehmen, wäre allerdings eine ziemlich schlechte Hashfunktion, weil die Namen nicht gleichmäßig über das Alphabet verteilt sind. Deswegen gibt es meistens eine Tabelle, die auf Grund statistischer Auswertungen der Einwohnermeldedaten erstellt wird, und jeweils die ersten drei Buchstaben des Namens berücksichtigt.

Auch Computerprogramme nutzen gelegentlich vergleichbare Funktionen.

Prüfsummen

Bei Übertragungen von Daten treten gelegentlich Fehler auf - unabhängig davon, ob es sich um die elektronische Übertragung riesiger Datenmengen oder bloß um die mündliche Weitergabe einer Telefonnummer handelt. Während man die Telefonnummer noch problemlos komplett wiederholen kann, um sicher zu gehen, wird das bei umfangreicheren Daten schnell ineffizient. Deswegen werden in solchen Fällen oft an beiden Enden der Verbindung nach festgelegten Algorithmen kurze Prüfsummen berechnet. Stimmt die Prüfsumme überein, wird davon ausgegangen, dass die Daten korrekt empfangen wurden. Ein solcher Algorithmus, der in Modemzeiten gängig war und auch heute noch an Stellen verwendet wird, wo es auf Schnelligkeit und Effizienz ankommt, ist z.B. CRC-32.

Die im vorangegangenen Abschnitt beschriebene Methode mit den Anfangsbuchstaben funktioniert hier leider nicht, da Übertragungsfehler im Namen jenseits des dritten Buchstabens den Hashwert nicht modifizieren.

Ein einfacheres Beispiel, wie man die Funktionsweise von Prüfsummen verstehen kann, sind die 13-stelligen ISBN- bzw. EAN-Nummern auf Büchern. Diese bestehen in Wahrheit nur aus zwölf signifikanten Ziffern und die dreizehnte ist die Prüfziffer, welche wie folgt berechnet wird:

  • Addiere die Ziffern an den ungeraden Positionen der Nummer.

  • Addiere dazu das dreifache der Ziffern an den geraden Positionen.

  • Nimm nur die letzte Ziffer und ziehe sie von 10 ab.

  • Das Ergebnis ist die Prüfziffer, außer es lautet 10, dann ist die Prüfziffer 0.

Beispiel:

  • Die ISBN lautet 978-3-82732-478-8 - die letzte 8 ist die Prüfziffer.

  • 9+8+8+7+2+7 + 3*(7+3+2+3+4+8) = 122

  • Die letzte Ziffer lautet 2.

  • 10 - 2 = 8

Wenn jetzt bei einer telefonischen Buchbestellung eine Zahl falsch verstanden wird, stimmt die Summe nicht mehr, und die ISBN wird ungültig. So verhindert man, dass aus Versehen ein falsches Buch bestellt wird. Das Verdreifachen jeder zweiten Ziffer dient übrigens dazu, dass das Vertauschen zweier benachbarter Ziffern ebenfalls zu einer veränderten Prüfziffer führt.

Hinweis:

Die alten, 10-stelligen ISBN-Nummern wurden übrigens nach einem leicht abweichenden Algorithmus berechnet und eignen sich deswegen nicht dazu, dieses Beispiel nachzuvollziehen.

Kryptografische Hashs

Die im vorigen Abschnitt beschriebenen Prüfsummenalgorithmen eignen sich, um versehentliche Übertragungsfehler zu entdecken, die durch gekippte Bits, rauschende Leitungen oder undeutliche Sprache entstehen. Gegen absichtliche Verfälschungen übertragener Nachrichten sind sie jedoch so gut wie wirkungslos. Es wäre kein Problem, bei einer Buchbestellung die ISBN durch eine völlig andere mit derselben Prüfsumme zu ersetzen. An dieser Stelle kommen "kryptografische Hashs" ins Spiel.

Eine kryptografische Hashfunktion muss mindestens diese Eigenschaften haben:

  • Es muss eine Einwegfunktion sein, d.h. es darf keine Möglichkeit geben, aus dem Hashwert die Originalnachricht zu extrahieren, außer man probiert alle möglichen Nachrichten aus. (sog. "Brute-Force")

  • Alle Hashwerte müssen gleich wahrscheinlich sein

  • Kleine Abweichungen in den Ausgangsdaten müssen möglichst große, sichtbare Veränderungen im Hashwert erzeugen

  • Das Erzeugen zweier verschiedener Datensätze, die denselben Hashwert haben ("Kollision"), darf ebenfalls nicht einfacher möglich sein als durch die Brute-Force-Methode

Die bekanntesten und verbreitetsten derartigen Funktionen sind MD5 und die SHA-Familie. Code-Bibliotheken, die diese Algorithmen implementieren, sind für alle gängigen Programmiersprachen verfügbar und auch Kommandozeilenprogramme, um solche kryptografischen Prüfsummen zu erzeugen bzw. zu verifizieren, sind unter Ubuntu standardmäßig installiert. Sie heißen md5sum, sha1sum, sha224sum, sha256sum, sha384sum und sha512sum und werden allesamt auf dieselbe Art und Weise bedient [1]. Die SHA-Versionen unterscheiden sich dabei in der Länge des Hashs in Bits. SHA-1-Hashs sind 160 Bit lang, die weiteren Versionen tragen ihre Länge im Namen.

Ohne Optionen werden die Prüfsummen von beliebig vielen Dateien errechnet, oder auch von der Standardeingabe:

sha256sum .bashrc .profile 

6fec775ff07e8424bbd774f8d6659dadfca37fd77ee66e2b9db92e3d045273ba  .bashrc
86512cad76131783f5dae4346ddc3fb39f6f7c0f74b3039bff70ca4015ade034  .profile

echo 'Hallo Welt!' | sha256sum 

1cf0c75265e678c4b9bcc32a798e8d484b8655029df225e7d8a616577c1c878e  -

Die Ausgabe des Befehls kann man auch in eine Datei umleiten und die Prüfsummen so dem Empfänger zur Prüfung der empfangenen Daten zur Verfügung stellen. Dazu benutzt man die Option -c und übergibt den Dateinamen der Prüfsummendatei. Die Namen der zu prüfenden Dateien sind ja in dieser Liste enthalten. Im folgenden Beispiel wird zuerst eine gefälschte Prüfsumme in eine Prüfsummen-Datei eingeschleust und später enttarnt:

sha256sum .bashrc .profile > SHA256SUMS
echo 'a33a8a8dd47681a5b2ce4f862fc29364bc173d325cef53764e639a02dc343ed8  .bash_history' >> SHA256SUMS
cat SHA256SUMS 

6fec775ff07e8424bbd774f8d6659dadfca37fd77ee66e2b9db92e3d045273ba  .bashrc
86512cad76131783f5dae4346ddc3fb39f6f7c0f74b3039bff70ca4015ade034  .profile
a33a8a8dd47681a5b2ce4f862fc29364bc173d325cef53764e639a02dc343ed8  .bash_history

sha256sum -c SHA256SUMS  

.bashrc: Ok
.profile: Ok
.bash_history: Fehlschlag
sha256sum: WARNING: 1 of 3 computed checksums did NOT match

Hinweis:

Diese Beispiele funktionieren statt mit sha256sum genauso mit den verschiedenen SHA-Befehlen. Nur die erzeugten Hashs unterscheiden sich selbstverständlich.

Message Authentication Codes (MAC)

Das alleinige Anwenden von kryptografischen Hashs wird in der Praxis allerdings nur bei einer einfachen Datenüberprüfung verwendet, z.B. beim Herunterladen von Dateien aus dem Internet (s. Beispiel oben). Kryptografische Hashs werden aber auch innerhalb von Netzwerkprotokollen verwendet. Hier ist es wichtig, neben der Unversehrtheit der Daten auch deren Integrität und Authentizität sicherzustellen:

  • Integrität - Der Hashwert muss nicht nur zu den Daten passen. Es muss auch sichergestellt werden, dass sowohl die Daten als auch der Hashwert nicht beide gleichzeitig manipuliert wurden.

  • Authentizität - Es muss sichergestellt werden, dass die Daten auch wirklich vom erwarteten Absender stammen.

Beides wird über sog. Message Authentication Codes garantiert. Die Hashfunktion wird dabei nicht nur auf die eigentlichen Daten angewendet, sondern außerdem auf einen gemeinsamen geheimen Schlüssel, der nur dem Absender und Empfänger bekannt sind. Ein gültiger Hashwert kann also nur mit Hilfe des geheimen Schlüssels erzeugt werden. Dieser wird zwischen Absender und Empfänger während des initialen Schlüsselaustauschs im Protokoll ausgehandelt.

Die verwendete Hashfunktion wird im Namen des MACs ausgedrückt (HMAC):

  • HMAC-SHA1

  • HMAC-SHA256

  • HMAC-SHA512

  • ...

Beispiele für Protokolle die HMACs einsetzen:

  • SSH

  • TLS

  • SSL-VPN / OpenVPN

  • ...

Neben dem Einsatz in Protokollen werden HMACs auch als eine Sonderform der Passwortanmeldung verwendet (Challenge-Response-Authentifizierung).

Salted Hashs

"Gesalzene Hashs" sind die Antwort auf Rainbow Tables. Wenn es um sehr kurze Eingabedaten geht, wie z.B. um Passwörter die verschlüsselt abgespeichert werden sollen, entsteht das Problem, dass man Brute-Force-Angriffe dadurch wesentlich vereinfachen kann, indem man vorgefertigte, große Tabellen mit allen möglichen Buchstaben- und Zahlenkombinationen und den zugehörigen Hashwerten verwendet. Damit wird das Cracken von Passwörtern teilweise zum Kinderspiel.

Um diesen Angriffen zu begegnen, wurde dazu übergegangen, beim Hashen des Passworts ein zufällig bestimmtes "Salt" (Salz) mit einzuberechnen. Dieses Salt wird dann im Passwort-Hash mit abgespeichert und steht somit bei der Überprüfung immer zur Verfügung. Die nötige Größe der Rainbow Tables multipliziert sich aber dadurch um die Anzahl der möglichen Salts und macht damit ihren Einsatz für Cracker unattraktiv.

Ein Beispiel für diese Vorgehensweise ist die Datei /etc/shadow, in der Ubuntu die Passwörter der lokalen Benutzerkonten ablegt. Allerdings wird dafür kein einfacher SHA512-Algorithmus verwendet, sondern dieser wird mehrfach in Kombination mit dem Salt angewendet (per Voreinstellung 5000-mal). Auch wird der Hash nicht wie üblich in Hexadezimalzahlen abgespeichert, sondern Base64-kodiert. Ein fertiger Hash sieht dann bspw. wie folgt aus:

$6$uJinzljS$ycwfOD4QLCrOvNAev6tbL5n.T/Ntht9m6urA306KkkdMuM2yIZRGc5S6YgF0DgZhmVr8qE.cMQQ1bIwLxypg90

Einzelne Felder sind durch das $-Zeichen getrennt. Die 6 bestimmt die Verwendung des gesalzenen SHA512-Algorithmus, uJinzljS ist in diesem Beispiel der Salt, und der Rest ist der Hashwert.

Um den Hashwert noch weiter gegen Brute-Force-Angriffe zu schützen, kann man in /etc/pam.d/common-password dem PAM-Modul pam_unix die Option "rounds=n" hinzufügen [2]. Der SHA512-Algorithmus wird dann n-mal auf das Passwort angewendet.

password        [success=1 default=ignore]      pam_unix.so obscure sha512 rounds=2000000

Anschließend muss man sein Passwort neu generieren. Der dazugehörige Hash ändert sich wie folgt:

$6$rounds=2000000$x8m7PLDH$kd8N88s6qd4g6Pvd1lgNhZM.r2LyuJmr0ruVUQZptdS4cP2EwEpodW5qlHJvydf/oNYr9J4/LU0HsFU/kDm3B.

Es ist an 2. Stelle ein neues Feld mit der Anzahl an Runden hinzugekommen. Die max. Anzahl an Runden ist auf 9999999 begrenzt. Je größer der Wert, desto länger dauert allerdings auch ein Login-Vorgang bei dem das Passwort geprüft wird (abhängig von der Leistungsfähigkeit der jeweiligen Hardware).

Schlüsselableitungsfunktionen

Obwohl nicht für diesen Einsatzzweck konzipiert, eignen sich Schlüsselableitungsfunktionen (Key Derivation Functions, KDF) ebenfalls zum Hashen von Passwörtern. Auch sie verwenden "Salted Hashs", und unterstützen eine variable Anzahl an Wiederholungen, wie oft die KDF auf das Passwort angewendet wird. KDFs haben aber zusätzlich den Vorteil, dass sie resistenter gegen Brute-Force-Angriffe sind, da die Berechnung des Hashwerts mehr Hauptspeicher und Rechenleistung erfordert. Gängige Schlüsselableitungsfunktionen sind:

  • PBKDF2 - erfordert von allen aufgelisteten KDFs am wenigsten Rechenleistung und Hauptspeicher

  • bcrypt - nicht standardisiert, basiert auf Blowfish

  • scrypt - nicht standardisiert, höhere Speicheranforderungen als bcrypt

  • Argon2 - Gewinner der Password Hashing Competition in 2015

Wer die Wahl hat, sollte Argon2 wählen. Einige Passwortmanager (z.B. KeePass Version 2, KeePassXC) und Programmiersprachen wie C, Python, Perl und PHP ab Version 7.2 unterstützen bereits Argon2. Allerdings hat noch keine der Schlüsselableitungsfunktionen den Weg in die Linux-Bibliothek glibc gefunden 🇬🇧, so dass solche auch noch nicht als Verschlüsselungsmethode für Passwörter von lokalen Benutzerkonten verwendet werden können (/etc/shadow). Für OpenLDAP muss das Modul pw-pbkdf2.so 🇬🇧 unter Ubuntu manuell installiert werden. Die Integration eines Argon2-Moduls in OpenLDAP ist geplant 🇬🇧.

Um einen Passwort-Hash mit Argon2 auf der Kommandozeile [1] zu erstellen, installiert man das gleichnamige Paket argon2 (seit Ubuntu 17.10).

  • argon2 (universe)

Paketliste zum Kopieren:

sudo apt-get install argon2 

Oder mit apturl installieren, Link: apt://argon2

Das Passwort sollte nicht in derselben Zeile wie der Befehl selbst eingegeben werden, da es sonst in der History gespeichert wird, sondern wie folgt:

SALT=$(cat /dev/urandom | tr -dc './a-zA-Z0-9' | fold -w 16 | head -n 1)
echo "$(cat)" | argon2 ${SALT} -t 100 -m 14 -p 2
passwort12345
^D 

Type:           Argon2i
Iterations:     100 
Memory:         16384 KiB
Parallelism:    2 
Hash:           e64442b438cbe91a08586abd6cbdbb0e414dba7b9c835856dbcd0f98fd170ed6
Encoded:        $argon2i$v=19$m=16384,t=100,p=2$M3ByeyZKLjFRREJqQi87WQ$5kRCtDjL6RoIWGq9bL27DkFNunucg1hW280PmP0XDtY
2.058 seconds
Verification ok

Anmerkungen:

  • Der Salt sollte für jede Verschlüsselung neu generiert werden.

  • Argon2 unterscheidet 3 verschiedene Typen/Varianten:

    • Argon2i - Resistent gegen Seitenkanalangriffe; sollte für Passwörter verwendet werden

    • Argon2d - Resistent gegen GPU-Cracking; sollte für Crypto-Währungen verwendet werden

    • Argon2id - Kombination aus den beiden vorherigen Varianten

  • Das Feld "v=19" in der Ausgabe ist die Versionsnummer der verwendeten Argon2-Bibliothek (hartkodiert im Quellcode).

Sicherheit

Vertrauen

Über eines muss man sich im Klaren sein: Ein korrekter SHA-2-Wert einer Datei bedeutet zwar, dass die Datei exakt in dem Zustand vorliegt, wie zum Zeitpunkt als der Hash errechnet wurde, das heißt aber noch lange nicht, dass der Inhalt vertrauenswürdig ist. Wenn ein Angreifer in einen Server einbricht und ein Programmpaket durch eine manipulierte Version ersetzt, ist es ihm ein leichtes, die SHA-2-Datei ebenfalls zu ersetzen. Davor schützen kann man sich als Anbieter nur, wenn man die SHA-2-Datei bspw. mit GnuPG digital signiert. Für das Überprüfen der ISO-Dateien von Ubuntu mit Hilfe von GPG-signierten Hash-Summen gibt es ein eigenes Howto. Anwender können einfache SHA-2-Summen aber trotzdem nützlich finden, wenn man diese z.B. über eine verschlüsselte HTTPS-Verbindung vom vertrauenswürdigen Hauptserver des Projekts herunter lädt, und das Paket selber aus einer weniger zuverlässigen Quelle wie einem Mirror oder P2P-Netz.

Angriffe gegen MD5 und SHA-1

In den letzten Jahren erregten erfolgreiche Angriffe gegen die verbreiteten Algorithmen MD5 und SHA-1 die Fachwelt (siehe Konsequenzen der erfolgreichen Angriffe auf MD5 🇩🇪 und Warum SHAttered wichtig ist 🇩🇪). Hierbei handelte es sich jedoch "nur" um Kollisionsattacken, also die erfolgreiche Erzeugung zweier verschiedener Datensätze mit gleichem Hashwert. Das kann in Zukunft relevant werden, wenn digitale Signaturen im Alltag Einzug halten, um rechtlich verbindliche Verträge abzuschließen. Verbreitete Dateiformate bieten genug Möglichkeiten, Fülldaten unterzubringen, die im Dokument nicht sichtbar sind. Es wäre also denkbar, dass man die MD5-Summe eines Kaufvertrags digital signiert ohne zu wissen, dass der Geschäftspartner, der diesen Vertrag entworfen hat, heimlich eine fast identische Version besitzt, die sich aber trotz gleicher Prüfsumme in der Höhe des Kaufpreises (und im unsichtbaren Füllstoff) unterscheidet.

Um so etwas zu verhindern, sollte man deshalb nach Möglichkeit MD5 und SHA-1 meiden und die längeren, zur Zeit als sicher geltenden Versionen SHA-256 oder größer verwenden.

Da bei HMACs neben den eigentlichen Daten auch ein geheimer Schlüssel verwendet wird (s. Kapitel Message Authentication Codes), ist hier die Kollision ein weniger wichtiges Problem. HMAC-SHA1 gilt daher aktuell als sicher.

Diese Revision wurde am 2. September 2018 02:55 von rolands11 erstellt.
Die folgenden Schlagworte wurden dem Artikel zugewiesen: Prüfsumme, Checksumme, Shell, Sicherheit