Wie prüft man, ob eine Datei unterwegs verändert wurde? Wie speichert ein Server Passwörter, ohne sie zu kennen? Und wie schickt man jemandem ein Geheimnis, ohne vorher ein Passwort auszumachen? In dieser Aktivität probierst du die Bausteine der Kryptographie im Terminal aus: Hashes, Passwörter mit Salz, Verschlüsselung mit einem und mit zwei Schlüsseln und digitale Unterschriften. Am Ende weißt du, was hinter dem Schloss im Browser und hinter deinem SSH-Schlüssel steckt.
Auf der Seite TCP/IP hast du gesehen: Was unverschlüsselt durchs Netz geht, kann jeder Router unterwegs mitlesen, und auch verändern. Kryptographie löst drei verschiedene Probleme, und es hilft, sie auseinanderzuhalten:
| Problem | Frage | Werkzeug |
|---|---|---|
| Unversehrtheit | Ist die Datei noch dieselbe? | Hash |
| Geheimhaltung | Kann nur die richtige Person lesen, was ich schicke? | Verschlüsselung |
| Echtheit | Kommt die Nachricht wirklich von der Person, die sie geschickt haben will? | Unterschrift |
Stelle zuerst sicher, dass du keinen Ordner geöffnet hast. Um sicherzugehen, drücke einfach den Shortcut für »Ordner schließen«: StrgK und dann F. Dein Workspace sollte jetzt ungefähr so aussehen:

Schließe die linke Seitenleiste mit StrgB, um mehr Platz zu haben, und öffne das Terminal mit StrgJ:


Mit dem Symbol rechts oben im Terminal kannst du es maximieren. Die linke Seitenleiste blendest du jederzeit mit StrgB ein und aus.
Lege einen Ordner für diese Aktivität an, wechsle hinein und schreib einen kurzen Brief in eine Datei:
mkdir ~/crypto cd ~/crypto echo "Treffpunkt: Freitag, 15 Uhr, an der Mensa." > letter.txt
sha256sum kennen.
Eine Hashfunktion macht aus beliebig vielen Daten eine kurze Zahl fester Länge, den Hash. SHA-256 ist eine solche Funktion; ihr Hash ist 256 Bit lang und wird als 64 Zeichen in Hexadezimal geschrieben. Berechne den Hash deines Briefs, ändere dann eine einzige Ziffer und berechne ihn noch einmal:
sha256sum letter.txt sed -i "s/15 Uhr/16 Uhr/" letter.txt sha256sum letter.txt
sed -i ersetzt im Brief 15 Uhr durch 16 Uhr.
Im Brief ändert sich nur 15 zu 16. Wie viele der 64 Zeichen des
Hashes ändern sich? Überleg erst, dann probier es aus.

Eine gute Hashfunktion hat drei Eigenschaften:
Darum taugt ein Hash als Fingerabdruck. Wer eine große Datei herunterlädt, zum Beispiel ein Betriebssystem, findet daneben oft ihren SHA-256-Hash. Stimmt der Hash der heruntergeladenen Datei damit überein, ist sie unterwegs nicht verändert worden. Auch Git benennt jeden Commit und jede Datei nach ihrem Hash: Die Commit-IDs wie a4a310c sind der Anfang davon.
Berechne den SHA-256-Hash des Worts Hackschule, ohne Zeilenumbruch.
Gib die ersten acht Zeichen ein.
echo -n Hackschule | sha256sum
echo hängt an seinen Text einen Zeilenumbruch an, und der zählt für den Hash mit. Mit echo -n fehlt er.
Ein Server, bei dem du dich anmeldest, muss prüfen können, ob dein Passwort stimmt. Speichert er die Passwörter selbst, liegen sie nach einem Einbruch alle offen da, und weil viele Menschen dasselbe Passwort für mehrere Dienste benutzen, ist der Schaden dann nicht auf diesen einen Server begrenzt.
Besser: Der Server speichert nur einen Hash des Passworts. Bei der Anmeldung berechnet er den Hash dessen, was du eingibst, und vergleicht. Das Passwort selbst kennt er nicht. Ein einfacher SHA-256-Hash reicht dafür aber nicht, aus zwei Gründen:
123456 sind die Hashes längst in Listen nachzuschlagen.Darum benutzen Server für Passwörter eigene Hashfunktionen wie yescrypt, bcrypt oder Argon2. Linux speichert die Passwörter seiner Benutzer mit yescrypt. mkpasswd zeigt, was dabei herauskommt. Rufe es zweimal mit demselben Passwort auf:
mkpasswd -m yescrypt geheim mkpasswd -m yescrypt geheim
Du rufst mkpasswd -m yescrypt geheim zweimal auf. Was kommt heraus?

Jedes Ergebnis besteht aus Teilen, getrennt durch $: y steht für yescrypt, j9T für die Einstellungen, dann kommt ein zufälliges Salz und erst danach der eigentliche Hash. Das Salz wird jedes Mal neu ausgewürfelt und mit dem Passwort zusammen gehasht. So hat dasselbe Passwort bei jeder Person einen anderen Hash, und fertige Listen nützen nichts. Das Salz ist nicht geheim, es steht ja mit im Ergebnis; zur Prüfung rechnet der Server mit demselben Salz noch einmal.
Der zweite Unterschied ist die Zeit. Mit -R stellst du ein, wie viel Arbeit yescrypt machen soll, und time misst, wie lange ein Befehl dauert:
time mkpasswd -m yescrypt -R 11 geheim time (echo -n geheim | sha256sum)

-R 11 ist mehr Arbeit, als ein Server sich üblicherweise vornimmt; er wählt die Einstellung so, dass eine Anmeldung kaum merklich länger dauert. Wer aber erbeutete Hashes durchprobieren will, muss für jede einzelne Vermutung diese Arbeit leisten, und das summiert sich. yescrypt braucht dafür außerdem viel Speicher, was spezielle Hardware zum Raten teuer macht.
Wozu dient das Salz in einem gespeicherten Passwort-Hash?
123456 hilft auch die langsamste Hashfunktion nicht viel.
openssl enc kennen.
Ein Hash lässt sich nicht umkehren. Soll jemand den Brief wieder lesen können, brauchst du Verschlüsselung: Mit einem Schlüssel wird aus dem Brief Datensalat, und mit demselben Schlüssel wird daraus wieder der Brief. Weil beide Seiten denselben Schlüssel benutzen, heißt das symmetrische Verschlüsselung. Das bekannteste Verfahren ist AES:
openssl enc -aes-256-cbc -pbkdf2 -in letter.txt -out letter.enc
openssl fragt zweimal nach einem Passwort. -pbkdf2 macht daraus den eigentlichen 256-Bit-Schlüssel, wie bei Passwörtern mit Salz und mit Absicht langsam. Sieh dir an, was in letter.enc steht. cat würde nur Zeichensalat ausgeben; xxd zeigt jedes Byte als zweistellige Hexadezimalzahl und rechts daneben als Zeichen, soweit es eines ist:
xxd letter.enc

Vorn steht Salted__, dahinter das Salz und dann der verschlüsselte Brief, von Zufall nicht zu unterscheiden. Zum Entschlüsseln gibt es -d. Probier es mit dem richtigen Passwort und einmal mit einem falschen:
openssl enc -d -aes-256-cbc -pbkdf2 -in letter.enc

Ein falsches Passwort, und sei es nur ein kleiner Buchstabe, ergibt einen ganz anderen Schlüssel. openssl merkt das meist am Ende der Daten und meldet bad decrypt; was es bis dahin entschlüsselt hat, ist Zeichensalat.
Verschlüssle letter.txt mit openssl enc in die Datei letter.enc.
openssl enc -aes-256-cbc -pbkdf2 -in letter.txt -out letter.enc, im Ordner crypto.
Symmetrische Verschlüsselung ist schnell und sicher, hat aber ein Problem: Beide Seiten brauchen dasselbe Passwort. Wie verabredest du es mit jemandem, ohne dass es unterwegs mitgelesen wird?
Du willst einer Freundin in einer anderen Stadt einen mit AES verschlüsselten Brief schicken. Was ist das Problem?
openssl genpkey und openssl pkeyutl kennen.
Die Lösung sind Verfahren mit zwei Schlüsseln, die zusammengehören: einem öffentlichen Schlüssel, den jeder haben darf, und einem privaten, den nur du hast. Was mit dem öffentlichen Schlüssel verschlüsselt wurde, kann nur der private wieder entschlüsseln. Das heißt asymmetrische Verschlüsselung; das bekannteste Verfahren ist RSA. Erzeuge ein Schlüsselpaar:
openssl genpkey -algorithm RSA -out private.pem openssl pkey -in private.pem -pubout -out public.pem cat public.pem
Die Punkte und Pluszeichen beim ersten Befehl zeigen, wie openssl nach zwei großen Primzahlen sucht; aus ihnen entsteht der Schlüssel. public.pem darfst du jedem zeigen, private.pem niemandem.

Verschlüssle eine kurze Nachricht mit dem öffentlichen Schlüssel und entschlüssle sie mit dem privaten:
echo "Das Codewort ist Seestern." > secret.txt openssl pkeyutl -encrypt -pubin -inkey public.pem -in secret.txt -out secret.enc openssl pkeyutl -decrypt -inkey private.pem -in secret.enc

Aus 27 Bytes sind 256 geworden, so groß wie der Schlüssel. Mehr als gut 200 Bytes passen auf einmal nicht hinein, und RSA ist viel langsamer als AES. Darum arbeiten echte Programme hybrid: Sie würfeln einen zufälligen AES-Schlüssel aus, verschlüsseln damit die eigentlichen Daten und schicken nur diesen kurzen Schlüssel mit RSA oder einem verwandten Verfahren. Genau so beginnt jede Verbindung mit https://.
Du willst Bob eine Nachricht schicken, die nur Bob lesen kann. Womit verschlüsselst du sie?
ifconfig).
Schick deinen öffentlichen Schlüssel über Port 1234, wie auf der Seite TCP/IP. Die empfangende Person wartet und speichert, was ankommt:
nc -l -p 1234 > partner.pem
Du schickst deine Datei. -N beendet die Verbindung, sobald die Datei ganz hinüber ist:
nc -N 172.20.0.12 1234 < public.pem
Mit partner.pem kann die andere Person dir jetzt eine Nachricht verschlüsseln und secret.enc auf demselben Weg zurückschicken. Entschlüsseln kannst nur du, mit deinem privaten Schlüssel. Wer unterwegs mitliest, sieht einen öffentlichen Schlüssel und eine verschlüsselte Nachricht, und mit beiden kann er nichts anfangen.
Eine Frage bleibt: Woher weißt du, dass der öffentliche Schlüssel wirklich von deinem Partner kommt und nicht von jemandem, der sich dazwischengeschaltet hat? Dafür gibt es Unterschriften.
ssh-keygen kennen.
Eine digitale Unterschrift dreht die zwei Schlüssel um: Mit dem privaten Schlüssel unterschreibst du, und mit dem öffentlichen kann jeder prüfen, dass die Unterschrift von dir stammt und die Datei seitdem nicht verändert wurde. Wir nehmen dafür Ed25519, ein modernes Verfahren mit kurzen Schlüsseln, und das Werkzeug ssh-keygen, das auch SSH und Git benutzen:
ssh-keygen -t ed25519 -f key -N "" -C "alice"
-f key legt das Paar in die Dateien key (privat) und key.pub (öffentlich), -N "" verzichtet auf ein Passwort für den privaten Schlüssel, und -C gibt dem Schlüssel einen Namen. Für einen echten Schlüssel solltest du ein Passwort setzen; hier geht es nur ums Ausprobieren. Unterschreibe den Brief:
ssh-keygen -Y sign -f key -n file letter.txt
Die Unterschrift steht danach in letter.txt.sig; -n file sagt, wofür sie gedacht ist, damit niemand eine Unterschrift unter einer Datei als Unterschrift für etwas anderes ausgeben kann.

Zum Prüfen braucht ssh-keygen eine Liste, wem welcher öffentliche Schlüssel gehört. Lege sie an und prüfe den Brief:
echo "alice $(cat key.pub)" > allowed_signers ssh-keygen -Y verify -f allowed_signers -I alice -n file -s letter.txt.sig < letter.txt
Ändere jetzt den Brief und prüfe noch einmal:
sed -i "s/16 Uhr/17 Uhr/" letter.txt ssh-keygen -Y verify -f allowed_signers -I alice -n file -s letter.txt.sig < letter.txt
Du änderst im unterschriebenen Brief 16 Uhr zu 17 Uhr und prüfst die
Unterschrift noch einmal. Was meldet ssh-keygen?

Unterschrieben wird nicht der ganze Brief, sondern sein Hash: Ändert sich eine Ziffer, passt der Hash nicht mehr zur Unterschrift. Die Unterschrift beweist also beides, wer unterschrieben hat und dass der Brief seitdem gleich geblieben ist. Geheim ist der Brief dadurch nicht, er liegt ja offen daneben.
Unterschreibe letter.txt mit deinem Ed25519-Schlüssel.
Die Zeile SHA256:… in der Prüfung ist der Fingerabdruck des Schlüssels, ein Hash des öffentlichen Schlüssels. Du kannst ihn selbst anzeigen:
ssh-keygen -lf key.pub
Fingerabdrücke sind kurz genug, um sie vorzulesen oder zu vergleichen. So prüfst du, ob ein öffentlicher Schlüssel, der über das Netz kam, wirklich der richtige ist: Ihr vergleicht den Fingerabdruck auf einem anderen Weg, zum Beispiel nebeneinander am Bildschirm.
Damit kennst du die Bausteine hinter Werkzeugen, die du jeden Tag benutzt:
git config gpg.format ssh kann Git Commits mit genau so einem SSH-Schlüssel unterschreiben.Was ist der Fingerabdruck eines Schlüssels, zum Beispiel SHA256:UXI/IC…?
| Hash |
sha256sum DATEI: Fingerabdruck einer Datei; gleiche Daten, gleicher Hash |
|---|---|
| Passwort-Hash |
mkpasswd -m yescrypt: mit Salz und mit Absicht langsam |
| Ein Schlüssel |
openssl enc -aes-256-cbc -pbkdf2, mit -d zurück |
| Zwei Schlüssel |
openssl genpkey, openssl pkeyutl -encrypt mit dem öffentlichen, -decrypt mit dem privaten Schlüssel |
| Unterschrift |
ssh-keygen -Y sign mit dem privaten, ssh-keygen -Y verify mit dem öffentlichen Schlüssel |
| Fingerabdruck | ssh-keygen -lf key.pub |
Auf der Seite Git und GitHub sind Commits nach ihrem Hash benannt; jetzt weißt du, warum eine Commit-ID eine Version eindeutig festhält. Wie HTTP über eine TCP-Verbindung läuft, zeigt TCP/IP; bei https:// liegt die Verschlüsselung von hier dazwischen.
