lehrkraefte:blc:informatik:glf22:caesar

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.

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

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).
caesar1.py
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 nummer<ord('a'):
            nummer = nummer+26
        if nummer>ord('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

Es werden direkt im Programmcode zwei Dateien und der Schlüssel festgelegt:

caesar2.py
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 nummer<ord('a'):
            nummer = nummer+26
        if nummer>ord('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).

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.

caesar3.py
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 nummer<ord('a'):
            nummer = nummer+26
        if nummer>ord('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

Lösung auf der Kommandozeile

Lösung auf der Kommandozeile

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

Laden Sie beide Dateien herunter: decryptor.py 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).

  • lehrkraefte/blc/informatik/glf22/caesar.txt
  • Last modified: 2022/11/04 09:10
  • by Ivo Blöchliger