Labor (Bash)2 DoppelstundenIm Handbuch: Workspace: Grundlagen
image: teaser.webp:0:50 kind: labor language: Bash duration: 2 Doppelstunden requires: [tcpip]

Kryptographie im Terminal

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

1. Vorbereitung

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:

Ein leerer Workspace ohne geöffneten Ordner.

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

Der Workspace mit geöffnetem Terminal im unteren Bereich.

Das Symbol zum Maximieren rechts oben im Terminal.

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

2. Fingerabdrücke: Hashes

In diesem Abschnitt lernst du den Befehl 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.

Vermutung 1Eine Ziffer anders

Im Brief ändert sich nur 15 zu 16. Wie viele der 64 Zeichen des Hashes ändern sich? Überleg erst, dann probier es aus.

Eine Ziffer anders

Zweimal sha256sum letter.txt, dazwischen sed: Die beiden Hashes aus je 64 Zeichen haben nichts gemeinsam, obwohl sich nur eine Ziffer im Brief geändert hat.

Eine gute Hashfunktion hat drei Eigenschaften:

  • Gleiche Daten, gleicher Hash. Wer denselben Brief hat, berechnet denselben Hash, auf jedem Rechner der Welt.
  • Kleine Änderung, ganz anderer Hash. Eine Ziffer, ein Leerzeichen, ein Bit: Der Hash ist danach nicht ähnlich, sondern ein völlig anderer.
  • Kein Weg zurück. Aus dem Hash lässt sich der Brief nicht berechnen, und niemand findet mit vertretbarem Aufwand zwei verschiedene Dateien mit demselben Hash.

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.

Aufgabe 2Ein Hash von Hand

Berechne den SHA-256-Hash des Worts Hackschule, ohne Zeilenumbruch. Gib die ersten acht Zeichen ein.

Tipp

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.

3. Passwörter speichern

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:

  • Gleiche Passwörter haben gleiche Hashes. Wer die gespeicherten Hashes sieht, erkennt sofort, wer dasselbe Passwort benutzt, und für häufige Passwörter wie 123456 sind die Hashes längst in Listen nachzuschlagen.
  • SHA-256 ist schnell. Das ist bei Dateien gewollt, bei Passwörtern ein Nachteil: Wer die Hashes erbeutet hat, kann sehr viele Vermutungen pro Sekunde ausprobieren.

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
Vermutung 3Zweimal dasselbe Passwort

Du rufst mkpasswd -m yescrypt geheim zweimal auf. Was kommt heraus?

Zweimal dasselbe Passwort

Zweimal mkpasswd -m yescrypt geheim mit zwei völlig verschiedenen Ergebnissen; beide beginnen mit $y$j9T$, danach unterscheiden sie sich.

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)

time misst für mkpasswd -m yescrypt -R 11 knapp 0,8 Sekunden, für sha256sum dagegen 6 Millisekunden, und das meiste davon ist der Start des Programms.

-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.

Aufgabe 4Wozu das Salz?

Wozu dient das Salz in einem gespeicherten Passwort-Hash?

Wozu das Salz?
Den besten Schutz hat trotzdem das Passwort selbst: lang, nirgends sonst benutzt, am besten aus einem Passwort-Manager. Gegen ein Passwort wie 123456 hilft auch die langsamste Hashfunktion nicht viel.

4. Verschlüsseln mit einem Passwort

In diesem Abschnitt lernst du den Befehl 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

openssl enc fragt nach dem Passwort und seiner Bestätigung. xxd letter.enc zeigt danach vier Zeilen mit je 16 Bytes, links als Hexadezimalzahlen, rechts als Zeichen: vorn das Wort Salted__, danach nur noch zufällig wirkende Bytes.

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

Mit dem richtigen Passwort gibt openssl den Brief aus: Treffpunkt: Freitag, 16 Uhr, an der Mensa. Mit dem falschen meldet es bad decrypt mit einer Fehlermeldung, danach stehen ein paar unleserliche Zeichen da.

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.

Aufgabe 5Ein verschlüsselter Brief

Verschlüssle letter.txt mit openssl enc in die Datei letter.enc.

Tipp

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?

Aufgabe 6Das Passwort verabreden

Du willst einer Freundin in einer anderen Stadt einen mit AES verschlüsselten Brief schicken. Was ist das Problem?

Das Passwort verabreden

5. Zwei Schlüssel

In diesem Abschnitt lernst du 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.

cat public.pem zeigt den öffentlichen Schlüssel: zwischen BEGIN PUBLIC KEY und END PUBLIC KEY sieben Zeilen aus Buchstaben, Ziffern, Plus und Schrägstrich.

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

Die Nachricht secret.txt hat 27 Bytes, verschlüsselt sind es 256. openssl pkeyutl -decrypt mit dem privaten Schlüssel gibt wieder »Das Codewort ist Seestern.« aus.

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://.

Aufgabe 7Nur für Bob

Du willst Bob eine Nachricht schicken, die nur Bob lesen kann. Womit verschlüsselst du sie?

Nur für Bob

Ein Geheimnis für jemand anderen

Hierfür brauchst du eine zweite Person mit einem eigenen Workspace. Ihr braucht beide ein Schlüsselpaar wie oben und eure IP-Adressen (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.

6. Unterschreiben

In diesem Abschnitt lernst du 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.

ssh-keygen -Y sign meldet »Signing file letter.txt« und »Write signature to letter.txt.sig«; cat zeigt die Unterschrift zwischen BEGIN SSH SIGNATURE und END SSH SIGNATURE.

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
Vermutung 8Nach der Unterschrift geändert

Du änderst im unterschriebenen Brief 16 Uhr zu 17 Uhr und prüfst die Unterschrift noch einmal. Was meldet ssh-keygen?

Nach der Unterschrift geändert

Die erste Prüfung meldet Good "file" signature for alice with ED25519 key und den Fingerabdruck des Schlüssels. Nach der Änderung von 16 auf 17 Uhr meldet die zweite Prüfung Signature verification failed: incorrect signature.

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.

Aufgabe 9Dein unterschriebener Brief

Unterschreibe letter.txt mit deinem Ed25519-Schlüssel.

7. Was hinter SSH, Git und HTTPS steckt

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:

  • SSH: Bei GitHub und vielen Servern kannst du statt eines Passworts deinen öffentlichen Schlüssel hinterlegen. Beim Anmelden beweist dein Rechner mit einer Unterschrift, dass er den privaten Schlüssel hat, ohne ihn zu verschicken. Beim ersten Kontakt mit einem Server zeigt SSH dessen Fingerabdruck.
  • Git: Commits sind nach ihrem Hash benannt, und mit git config gpg.format ssh kann Git Commits mit genau so einem SSH-Schlüssel unterschreiben.
  • HTTPS: Der Server schickt ein Zertifikat, seinen öffentlichen Schlüssel mit der Unterschrift einer Stelle, der dein Browser vertraut. Dann handeln beide einen AES-Schlüssel aus, und alles Weitere ist symmetrisch verschlüsselt.
Aufgabe 10Der Fingerabdruck

Was ist der Fingerabdruck eines Schlüssels, zum Beispiel SHA256:UXI/IC…?

Der Fingerabdruck

8. Zusammenfassung

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

9. Wie geht es weiter?

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.