====== Cäsar «Verschlüsselung» (Verschleierung) ====== Idee: Ein Text wird verschleiert, indem jeder Buchstabe $k$ Positionen weiter im Alphabet geschoben wird (wobei nach 'Z' wieder 'A' folgt). Es gibt also nur 25 mögliche Schlüssel, was die Entschlüsselung auch von Hand trivial macht. ===== Pseudocode für die Verschleierung ===== Im Pseudocode verwenden wir **Variablen**. Diese können im Laufe des Programms Ihre **Werte wechseln** (was in der Mathematik unüblich ist). Z.B. wird der Buchstabe $b$ u.U. mehrmals geändert, bevor er dem Resultat $r$ hinzugefügt wird (das sich auch in jeder Wiederholung ändert). * **Input**: Text $t$, Schlüssel $k$ (Ganzzahl zwischen $-25$ und $25$). * **Output**: Verschleierter Text * $r=$"" (leerer Text) * Für jeden Buchstaben $b$ im Text $t$: * Wenn $b$ ein Grossbuchstabe ist, sei $b$ der entsprechende Kleinbuchstabe * Wenn $b$ ein Kleinbuchstabe ist: * Verschiebe $b$ um $k$ Positionen im Alphabet * Hänge $b$ hinten an $r$ an. * Das Resultat ist $r$. Was kommt als Resultat mit dem Input $t=$"Hey You!" und $k=3$ heraus? ==== Pseudocode allgemein ==== Pseudocode ist eine Beschreibung eines Algorithmus (Rechenvorschrift, z.B. ein Computerprogramm), die von Menschen gelesen werden soll. Ein Pseudocode richtet sich an ein bestimmtes Publikum und kann mehr oder weniger viele Elemente aus einer bestimmten Programmiersprache enthalten. Für das Zielpublikum müssen alle Anweisungen unmissverständlich klar sein und alle müssen für den gleichen Input das gleiche Resultat produzieren (von Flüchtigkeitsfehlern mal absgesehen). Zwingende Elemente sind: * Genaue Beschreibung vom **Input** (Art und womöglich Umfang). * Genaue Beschreibung vom **Output** (Art und womöglich Umfang). * Eigentlicher **Algorithmus** Typische Elemente sind: * **Variablen**, um beliebige Dinge zu speichern (meist Zahlen oder Text). Variablen können ihren Inhalt im Laufe des Programms mehrmals ändern. * **Wiederholungen** ganzer Programmteile * Bedingte **Verzweigungen** (wenn das, dann das, sonst jenes) * **Anweisungen**, was mit welchen Variablen zu tun ist. * Evtl. Unterprogramme und/oder Funktionen, um einen Algorithmus in mehrere Algorithmen zu zerlegen. ===== Python-Code ===== ==== Einfachste Version ==== Der Text und der Schlüssel werden direkt im Programm festgelegt. Die Ausgabe erfolgt auf der Konsole. * Die Funktion ''ord'' liefert den ASCII-Code (eine Zahl) für ein gegebenes Symbol (Buchstabe), d.h. die dem Symbol zuordnete Nummer. * Z.B. liefert ''ord('A')'' die Zahl 65, oder ''ord(' ')'' Die Zahl 32 (Code vom Leerschlag). * Die Funktion ''chr'' liefert das Symbol (als Text) für den gegebenen ASCII-Code (Zahl). * Z.B. liefert ''chr(65)'' den Text '' 'A' '', ''chr(97)'' den Text '' 'a' ''. * In Python (und fast allen Programmiersprachen) werden Texte und Zahlen streng unterschieden. So ist ''3'' und '' '3' '' nicht das Gleiche. ''3'' steht für die Zahl 3 (womit auch gerechnet werden kann) und '' '3' '' steht für das Symbol (mit ASCII Code 51). text = "Hey You!" key = 3 result = "" for symbol in text: if symbol>='A' and symbol<='Z': symbol = chr(ord(symbol)+ord('a')-ord('A')) if symbol>='a' and symbol<='z': nummer = ord(symbol)+key if nummerord('z'): nummer = nummer-26 symbol = chr(nummer) result = result + symbol print(result) Gehen Sie in ein geeignetes Verzeichnis (eventuell neu anlegen) und öffnen Sie eine neue Datei in VSCode: mkdir caesar cd caesar code caesar.py Wenn der Code dann kopiert und gespeichert ist, kann er wie folgt ausgeführt werden: python caesar.py ==== In- und Output mit Dateien ==== Es werden direkt im Programmcode zwei Dateien und der Schlüssel festgelegt: input_datei = "input.txt" key = 3 output_datei = "output.txt" # Datei öffnen und einlesen (r für read) with open(input_datei, "r") as f: text = f.read() print(text) result = "" for symbol in text: if symbol>='A' and symbol<='Z': symbol = chr(ord(symbol)+ord('a')-ord('A')) if symbol>='a' and symbol<='z': nummer = ord(symbol)+key if nummerord('z'): nummer = nummer-26 symbol = chr(nummer) result = result + symbol print(result) # Datei überschreiben und ausgeben (w für write) with open(output_datei,"w") as f: f.write(result) Legen Sie eine Datei ''input.txt'' mit einem Text drin an. Verschleiern Sie diese. Kopieren Sie dann wie folgt die Datei ''output.txt'' auf die Datei ''input.txt'': cp input.txt output.txt Passen Sie dann im Programm den Schlüssel entsprechend an und überprüfen Sie, ob auch der Originaltext wieder erzeugt wird (bis auf Gross-/Kleinschreibung). ==== Flexiblere Variante mit Kommandozeilenargumenten ==== Diese Variante liest entweder direkt von der Konsole oder von einer Datei, und schreibt ebenfalls direkt auf die Konsole oder in eine Datei. Der Schlüssel wird ebenfalls auf der Kommandozeile angegeben. Starten Sie das Programm mit python caesar3.py -h um die Hilfe angezeigt zu bekommen. import argparse import sys import os # Kommandozeilenoptionen festlegen parser = argparse.ArgumentParser(description='Einfache Caesar-Verschleierung') parser.add_argument('-k', '--key', nargs=1, type=int, help="Schlüssel, zwischen -25 und 25", required=True) parser.add_argument('-i', '--infile', type=str, help="Optional: Datei, wovon gelesen werden soll.") parser.add_argument('-o', '--outfile', type=str, help="Optional: Datei, wohin das Resultat geschrieben werden soll.") parser.add_argument('-f', '--force', action="store_true", help="Output-Datei wird überschrieben, falls sie schon existiert"); # Auswerten args = parser.parse_args() # Schlüssel bestimmen key = args.key[0] if (key<-25 or key>25): sys.stderr.write("Der Schlüssel muss zwischen -25 und 25 liegen\n") exit(-1) # Programm mit Fehlerstatus beenden # Text von Datei oder Standardinput lesen text = "" # Input Datei gegeben? if args.infile: # Datei öffnen und einlesen (r für read) if not os.path.exists(args.infile): sys.stderr.write(f"Input Datei {args.infile} nicht gefunden\n") exit(-1) with open(args.infile, "r") as f: text = f.read() else: # sonst vom Standard-Input lesen text = sys.stdin.read() # Verschleierung result = "" for symbol in text: if symbol>='A' and symbol<='Z': symbol = chr(ord(symbol)+ord('a')-ord('A')) if symbol>='a' and symbol<='z': nummer = ord(symbol)+key if nummerord('z'): nummer = nummer-26 symbol = chr(nummer) result = result + symbol # Resultat in Datei oder Standard Output ausgeben if args.outfile: if (os.path.exists(args.outfile)) and (not args.force): sys.stderr.write(f"Die Datei {args.outfile} existiert bereits. Benutzen Sie -f um diese zu überschreiben\n") exit(-1) # Datei überschreiben und ausgeben (w für write) with open(args.outfile, "w") as f: f.write(result) else: # Sonst ausgabe auf Standard Ouput sys.stdout.write(result) # Fast das gleiche wie print(result), ausser dass print immer einen Zeilenumbruch hinzufügt. Probieren Sie das Programm auf alle Varianten aus (mit/ohne Input-Datei, mit/ohne Output-Datei). Verschleiern Sie einen kleinen Text mit einem «geheimen» Schlüssel. Tauschen Sie die Text-Dateien (kein Word bitte!) mit Ihrem Banknachbar aus. Entschleiern Sie dann den Text. Können Sie den richtigen Schlüssel auf Anhieb erraten? Knacken Sie folgenden Text: bliqvkvokvfyevrsjkrveuvjzeujtynzvizxviqlviirkve \ In diesem Beispiel ist der verschlüsselte Text in der Datei ''humpfdidumpf.txt'' gespeichert. for a in `seq 1 25`; do echo $a; python caesar3.py -k $a -i humpfdidumpf.txt; done **Anspruchsvolle Aufgabe** Die hier programmierte Verschleierungsmethode ist insofern unschön, dass beim Entschlüsseln nicht unbedingt wieder der Originaltext herauskommt, weil Grossbuchstaben zu Kleinbuchstaben konvertiert werden. Erweitern Sie das Programm so, dass Grossbuchstaben auch in Grossbuchstaben verschleiert werden. Dazu müssen Sie die 2 Fälle gross/klein separat verschleiern. Ersetzen Sie dazu den ''if''-Block, wo Gross- zu Kleinbuchstaben ersetzt werden mit einem entsprechenden Block, der die Verschleierung von Grossbuchstaben vornimmt (analog zur Verschleierung der Kleinbuchstaben). **Sehr anspruchsvolle Aufgabe** Entwerfen Sie eine Methode (erst mal als Pseudocode), das beliebige deutsche verschleierte Texte automatisch entschlüsselt (bzw. den wahrscheinlichsten Schlüssel findet). * https://de.wikipedia.org/wiki/Buchstabenh%C3%A4ufigkeit * http://www.mathe.tu-freiberg.de/~hebisch/cafe/kryptographie/bigramme.html ==== Entschlüsseln ==== Laden Sie beide Dateien herunter: {{lehrkraefte:blc:informatik:glf22:decryptor.py}} {{lehrkraefte:blc:informatik:glf22:bigramme.py}} Verwenden Sie das Programm wie folgt: python decryptor.py secret.txt Wobei der zu entschlüsselnde Text in der Datei ''secret.txt'' gespeichert ist (kann natürlich auch anders heissen).