Caesar mit Python
Lernziele
- Sie können Buchstaben mithilfe der ASCII-Tabelle kodieren (nicht auswendig lernen!).
- Sie haben die komplette Caesar-Verschlüsselung als Funktion
caesar_encryptin Python umgesetzt und verstehen den Code. Insbesondere:
- wie wir mit einer for-Schleife Buchstabe für Buchstaben durch ein Wort iteriert sind und das Ergebnis ebenfalls Buchstabe für Buchstabe konstruiert haben,
- wie wir einen Buchstaben in seine ASCII-Zahl (
ord()) und wieder zurück verwandelt haben (chr()),- wie wir die Verschiebung auf druckbare Zeichen (ASCII 32-126) eingeschränkt haben,
- und wie wir Funktionen mit Parametern und dem return-Statement verwendet haben.
- Sie verstehen den Modulo mathematisch und können den Modulooperator
%in Python anwenden.
Was sind Wörter für einen Computer?
ASCII / Unicode
Es wird Sie kaum überraschen, dass Texte in Computern letztlich eine Serie von Binärzahlen sind. Die Kodierung ist denkbar einfach: Es ist letztlich einfach eine Tabelle, die jeder Zahl einen Buchstaben zuordnet.
Heute verwenden wir dafür weiterhin die sogenannte ASCII-Tabelle, die in den 1960ern standardisiert wurde. Dieser Zeichensatz wurde für die Übertragung so klein wie möglich gehalten, nämlich 7 Bit oder 128 Zeichen.
Beispiel:
Ahat den ASCII-Code 65.ahat den ASCII-Code 97.
ASCII deckt hauptsächlich die englische Sprache ab und hat somit enorme Einschränkungen für andere Sprachen, Symbole und Emojis (z.B. € — © ™ ∆ Ω 你好 Привіт 😊 🎉)
Als Reaktion auf die Beschränkungen von ASCII wurde Unicode entwickelt, um alle Schriftzeichen aller Sprachen darzustellen. Unicode kann über 1 Million Zeichen kodieren, von denen bisher über 143'000 definiert sind.
Von Zeichen zu Zahl zu Hex
Das Prinzip bleibt dasselbe wie bei ASCII: Jedes Zeichen bekommt eine eindeutige Ganzzahl, den sogenannten Code Point. Diese Zahl wird konventionell in Hexadezimal geschrieben, mit dem Präfix U+ und mindestens vier Stellen:
| Zeichen | Dezimal | Hexadezimal | Code Point |
|---|---|---|---|
A | 65 | 41 | U+0041 |
é | 233 | E9 | U+00E9 |
你 | 20'320 | 4F60 | U+4F60 |
Die U+-Schreibweise ist also nur eine kompakte Darstellung der Ganzzahl — die eigentliche Kodierung in Bytes ist ein separater Schritt.
Binäre Kodierung: UTF-8Binär wurde nun eine Kodierung gesucht, die Rückwärtskompatibel zu ASCII bleibt, aber den Zeichensatz trotzdem erweitern kann. Weitverbreitet heute das "Unicode Transformation Format" UTF-8. Es nutzt den Umstand, dass die ASCII-Tabelle nur 7 Bit benötigt, also dass ein "normales" ASCII-Byte mit
0beginnen würde. UTF-8 signalisiert mit1am Anfang des ersten Byte, wie viele Bytes das Zeichen umfasst, und mit10am Anfang der Folgebytes, dass sie Teil desselben Symbols sind.Die
x-Stellen in den Formaten werden mit den Bits des Code Points aufgefüllt. Am Beispiel voné(U+00E9):
- Code Point hexadezimal: E9 → binär: 11101001
- Passt in das 2-Byte-Format:
110xxxxx 10xxxxxx(11 freie Stellen)- Bits von rechts einfüllen:
1100001110101001Die vier Formate im Überblick:
- 1 Byte (U+0000 bis U+007F):
- Format:
0xxxxxxx- Beispiel:
A(U+0041) →01000001- 2 Bytes (U+0080 bis U+07FF):
- Format:
110xxxxx 10xxxxxx- Beispiel:
é(U+00E9) →11000011 10101001- 3 Bytes (U+0800 bis U+FFFF):
- Format:
1110xxxx 10xxxxxx 10xxxxxx- Beispiel:
你(U+4F60) →11100100 10111101 10100000- 4 Bytes (U+10000 bis U+10FFFF):
- Format:
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx- Beispiel:
𐍈(U+10348) →11110000 10010000 10001101 10001000Unter dem Strich bleibt das Prinzip das Gleiche: Eine riesige Tabelle weist jedem Zeichen eine Ganzzahl (Integer) zu — UTF-8 bestimmt nur, wie diese Zahl in Bytes verpackt wird.
Wörter sind Listen von Unicode-Symbolen in Python
Beim Erstellen einer Verschlüsselungsfunktion hilft Ihnen der Umstand, dass man in Python Zeichenketten weitgehend wie Listen behandeln kann. Sie können also mit einer for-Schleife über ein Wort iterieren.
Zudem können Sie mit der Funktion ord() den Unicode des Buchstabens auslesen und chr() macht aus einem Unicode wieder den Buchstaben.
Caesar in Python implementieren
1️⃣ Die Grundlogik programmieren
Sie haben nun alle Zutaten, um die Grundlogik der Caesar-Verschlüsselung zu programmieren: Verschieben Sie die Buchstaben der Variabel satz um drei Stellen im Alphabet. Tipp: Gehen Sie Schritt für Schritt vor.
2️⃣ Lösung zu einem Wort zusammensetzen
Wenn Sie die Grundlogik soweit programmiert haben, dass Sie die richtigen Buchstaben in der Ausgabe ausdrucken können, überlegen Sie sich, wie Sie diese Buchstaben vorzu zu einem Wort zusammensetzen könnten. Hierzu folgender Tipp:
3️⃣ Einfache Caesar-Verschlüsselung als Funktion
Schreiben Sie eine Funktion caesar_encrypt mit zwei Parametern: die Nachricht, die verschlüsselt werden soll, und wie weit verschoben werden soll. Man soll die Funktion zum Beispiel so aufrufen können, um die Nachricht um vier Stellen zu verrücken:
caesar_encrypt("Wir treffen uns um 17 Uhr im Cipher Cafe", 4)Die Ausgabe davon wäre: [mv$xvijjir$yrw$yq$5;$Ylv$mq$Gmtliv$Geji
Einfache Caesar-Verschlüsselung mit Videoerklärung 📺️Hier ein Erklärvideo der einfachen Caesar-Verschlüsselung:
def caesar_encrypt(klartext, verschiebung): # Initialisiere den verschlüsselten Text als leere Zeichenkette ciphertext = "" # Gehe jeden Buchstaben im Eingabetext durch for buchstabe in klartext: # Berechne die neue Position neue_position = ord(buchstabe) + verschiebung # Füge den verschlüsselten Buchstaben zum verschlüsselten Text hinzu ciphertext = ciphertext + chr(neue_position) # Gebe den verschlüsselten Text zurück return ciphertext def caesar_decrypt(ciphertext, verschiebung): return caesar_encrypt(ciphertext, -verschiebung) ciphertext = caesar_encrypt("Wir treffen uns um 17 Uhr im Cipher Cafe", 4) print("Unser Ciphertext ist:", ciphertext) entschluesselt = caesar_decrypt(ciphertext, 4) print("Entschlüsselte Nachricht:", entschluesselt)
Das Problem mit der einfachen Caesar-Verschlüsselung
Das Problem mit unserer Verschlüsselung bislang ist, dass die Verschiebung unsere Buchstaben teils so weit nach oben oder unten verschiebt, dass wir bei unsichtbaren Steuerzeichen landen. Wenn Menschen die verschlüsselten Nachrichten lesen können sollen, ist das schlecht.
Wir müssen unseren Code also so erweitern, dass er nur druckbare Zeichen nutzt und bei einem Überlauf wieder am Anfang der druckbaren Zeichen beginnt – ähnlich wie bei einer Uhr, die nach 23:59 wieder bei 00:00 beginnt.
Der Modulo-Operator
Erklärvideo zu diesem Teil 📺️
Was ist Modulo?
Heutzutage würden Sie wohl sagen gibt , , oder . Aber in der Primarschule haben Sie dividieren zuerst anders gelernt: Wenn Sie 7 Äpfel auf 5 Personen aufteilen müssten, hätten Sie gesagt, dass jede Person einen Apfel erhält und zwei Äpfel übrig bleiben. Kurz: .
In der Mathematik gibt es eine Operation, die diesen Rest einer Divison produziert: den Modulo. Einige Beispiele:
In der Mathematik sehen Sie das vielleicht auch ohne Klammern geschrieben. Wichtig für die Informatik: In Python ist der "Modulo"-Operator %. Drücken Sie "Run" bei diesem Editor.
Überlegen wir uns, wie sich der Modulo verhält. Stellen wir uns hierzu eine Funktion vor, also eine Funktion, die für alle den Rest der Division durch berechnet. Was für Zahlen kommen da raus?
Das Ganze grafisch gezeigt:
Warum ist Modulo für die Kryptografie wichtig?Bei der Caesar-Verschlüsselung verschieben wir Buchstaben. Aber was passiert, wenn wir 'z' um 10 vorwärts verschieben? Dann verlassen wir den Bereich der lesbaren Zeichen und müssten wieder von Vorne beginnen!
Die Lösung: Mit Modulo können wir einen Bereich zyklisch wiederholen. Wenn wir etwas hinten rausschieben, beginnt es wieder von vorne.
Die komplette Caesar-Verschlüsselung mit Modulo
Erklärvideo zu diesem Teil 📺️
Druckbare ASCII-Zeichen
Glücklicherweise sind alle druckbaren ASCII-Zeichen in einem zusammenhängenden Block definiert: von Position 32 bis 126. Das sind genau 95 verschiedene Zeichen.
Schauen wir uns diese Zeichen einmal an:
Sie sehen in der Ausgabe: Das erste Zeichen (Position 32) ist das Leerzeichen, gefolgt von Satzzeichen, Ziffern, Gross- und Kleinbuchstaben und weiteren Symbolen. Das letzte Zeichen (Position 126) ist die Tilde ~.
4️⃣ Modulo-Rechnung für druckbare Zeichen
Jetzt können wir die Modulo-Operation für unsere Verschlüsselung nutzen. Die Idee ist dieselbe wie bei der Uhr: Nach dem letzten Zeichen kommt wieder das erste.
Die Umsetzung: Wir verschieben nicht einfach die ASCII-Nummer, sondern packen die Berechnung kompakt in eine einzige Zeile. Die mathematische Formel für die neue Position eines Buchstabens lautet:
(ord(buchstabe) - 32 + verschiebung) % 95 + 32Was passiert hier im Detail?
ord(buchstabe) - 32: Verringert den ASCII-Code, damit das erste druckbare Zeichen (Leerzeichen) bei der Null beginnt.+ verschiebung: Addiert die gewünschte Verschiebung.% 95: Verwendet den Modulo, um sicherzustellen, dass wir im gültigen Bereich von 95 Zeichen (0 bis 94) bleiben. Ein Überlauf überschreitet somit die 94 nicht, sondern beginnt wieder bei 0.+ 32: Addiert am Schluss wieder 32, um nach der Modulo-Rechnung zurück in den echten ASCII-Bereich der druckbaren Zeichen zu gelangen.
Verstehen Sie diesen Code?
5️⃣ Ein einzelnes Zeichen verschlüsseln
Schreiben Sie eine Funktion verschiebe_buchstabe(buchstabe, verschiebung), die einen einzelnen Buchstaben um die angegebene Anzahl Stellen verschiebt. Nutzen Sie dafür die kompakte Einzeiler-Logik, damit das Zeichen immer im druckbaren Bereich (32-126) bleibt.
Testen Sie Ihre Funktion mit:
verschiebe_buchstabe('A', 5)→ sollte'F'ergebenverschiebe_buchstabe('Z', 10)→ sollte'd'ergebenverschiebe_buchstabe('~', 2)→ sollte'!'ergeben (Überlauf!)
Lösung für einzelnes Zeichendef verschiebe_buchstabe(buchstabe, verschiebung): # Alles in einer kompakteren Zeile zusammengefasst neue_position = (ord(buchstabe) - 32 + verschiebung) % 95 + 32 return chr(neue_position)
6️⃣ Komplette Caesar-Verschlüsselung
Nun können Sie die komplette Caesar-Verschlüsselung implementieren! Schreiben Sie eine Funktion caesar_encrypt(klartext, verschiebung), die:
- Jeden Buchstaben im Text durchgeht
- Den Buchstaben gemäss der neuen Einzeiler-Logik verschiebt und dem neuen Text hinzufügt
- Am Ende den kompletten verschlüsselten Text zurückgibt
Schreiben Sie auch eine caesar_decrypt-Funktion!
Komplette Caesar-Verschlüsselung (Lösung)def caesar_encrypt(klartext, verschiebung): # Initialisiere den verschlüsselten Text als leere Zeichenkette ciphertext = "" # Gehe jeden Buchstaben im Eingabetext durch for buchstabe in klartext: # Berechne die neue Position und verhindere, dass sie die druckbaren Zeichen verlässt neue_position = (ord(buchstabe) - 32 + verschiebung) % 95 + 32 # Füge den verschlüsselten Buchstaben zum verschlüsselten Text hinzu ciphertext = ciphertext + chr(neue_position) # Gebe den verschlüsselten Text zurück return ciphertext def caesar_decrypt(ciphertext, verschiebung): return caesar_encrypt(ciphertext, -verschiebung) ciphertext = caesar_encrypt("Wir treffen uns um 17 Uhr im Cipher Cafe", 4) print("Unser Ciphertext ist:", ciphertext) entschluesselt = caesar_decrypt(ciphertext, 4) print("Entschlüsselte Nachricht:", entschluesselt)