Allgemein,  Programmieren,  Studium

Semesterprogrammierprojekt: Caesar- und Vigenère-Verschlüsselung in Python

Für mein Semesterprojekt 2021/2022 habe ich eine Caesar-Verschlüsselung und eine Vigenère-Verschlüsselung in Python implementiert. Hier erkläre ich alle nötigen Schritte auf dem Weg zu einem fertigen Semesterprojekt, meinen Code und meine Ideen und Gedanken dahinter.

Projektplanung

Bei der Projektplanung setzt man sich zunächst mit der Aufgabenstellung auseinander, also damit, was das Ziel des Projektes ist. Was muss der Code nachher machen können?

In meinem Fall war das Ziel, das erreicht werden muss, eine funktionierende Cäsar-Verschlüsselung und eine Entschlüsselung mit einem bekannten Schlüssel. Zudem soll mindestens versucht werden, eine selbstständige Entschlüsselung des Computers umzusetzen, also das Brechen des Codes, wenn für die Entschlüsselung der Schlüssel nicht bekannt ist. Zusätzlich kann eine weitere Chiffre implementiert werden, wie zum Beispiel die Vigenère-Chiffre.

Diese vorgegebene Hierarchie legt bereits die Reihenfolge der Bearbeitung fest. Logischerweise beginnt man mit den Pflichtaufgaben und geht dann am Schluss, wenn die Zeit ausreicht zu den optionalen Aufgaben über.

Daraus ergaben sich auch meine Reihenfolge und folgenden Überlegungen (genauere Ausführung später):

  1. Caesar-Verschlüsselung implementieren
    • Text aus Input entnehmen
    • Sonderzeichen (ä, ö, ü und ß) umschreiben
    • nach der Zahl für die Verschiebung (Schlüssel) fragen
    • pro Buchstabe die Verschiebung in Ascii vornehmen → andere Zeichen werden übersprungen
    • darauf achten, dass die verschobenen Zeichen auch Buchstaben sind
    • den verschlüsselten Text ausgeben
  2. Entschlüsselung mit Schlüssel implementieren
    • verschlüsselten Text aus Input entnehmen
    • nach dem Schlüssel fragen
    • pro Buchstabe die Verschiebung rückwärts in Ascii vornehmen → andere Zeichen werden übersprungen
    • darauf achten, dass die verschobenen Zeichen auch Buchstaben sind
    • den entschlüsselten Text ausgeben
  3. Brechen des Codes (Entschlüsselung ohne Schlüssel) implementieren
    • verschlüsselten Text aus Input entnehmen
    • pro Buchstabe die Verschiebung rückwärts in Ascii vornehmen → andere Zeichen werden übersprungen
    • bei der Verschiebung werden alle Zahlen zwischen 0 und 26 als Schlüssel durchgegangen
    • überprüfen, ob der erzeugte Text sinnvoll ist
    • den entschlüsselten Text (oder eine Fehlermeldung) ausgeben
  4. Menü
    • Angabe, ob ein Text ver- oder entschlüsselt werden soll
      • bei der Entschlüsselung fragen, ob ein Schlüssel gegeben ist, oder nicht
    • wiederholte Ver- oder Entschlüsselung ermöglichen
  5. Zusätzliche Chiffre implementieren: Vigenère-Chiffre
    • Recherche über die genaue Funktion der Chiffre
    • Implementierung
    • Erweiterung des Menüs um die Frage, welche Chiffre (Caesar oder Vigenère) angewendet werden soll

Wie man sieht, fällt je nach Vorwissen die Projektplanung sehr präzise oder wage aus. Dabei kommt es darauf an, was man für ein “Typ” ist und wie ausführlich diese Planung zur besten Umsetzung und vor allem zum effizienten Implementieren notwendig sind. Zudem muss gegebenenfalls darauf geachtet werden, dass alles ausführlich und verständlich genug aufgeschrieben wird, sodass andere die Planung auch verstehen, also zum Beispiel der Professor oder Tutor.

Die Projektplanung hilft dabei, die Aufgabenstellung möglichst strukturiert und damit möglichst zügig erfüllen zu können. Man kann sich während des gesamten Projekts an der Planung entlang hangeln und kennt somit auch immer grob den aktuellen Stand.

Nach der Planung kann man direkt mit dem Projekt starten, meist zuerst mit etwas Recherche.

Die Caesar-Chiffre

Kurz zur Geschichte …

Die Caesar-Chiffre wurde das erste mal, wie der Name schon vermuten lässt, von (Gaius) Julius Caesar, dem römischen Feldherr, verwendet. Damit verschlüsselte er Nachrichten zur geheimen Übermittlung im Gallischen Krieg. Unter anderem verfasste Caesar verschlüsselte Nachrichten an Quintus Cicero.

Wie funktioniert die Caesar-Chiffre?

Die Caesar-Chiffre gehört zu den Substitutions-Chiffren. Das heißt, dass jeder Buchstabe des Klartextes gegen den Buchstaben, der eine bestimmte Anzahl an Stellen weiter im Alphabet steht, getauscht wird. Die gesamte Nachricht wird also gewissermaßen im Alphabet verschoben.

Zum Beispiel:

Klartext: Hallo

Verschiebung: 3

Verschlüsselter Text: Kdoor

abcdefghijklmnopqrstuvwxyz
defghijklmnopqrstuvwxyzabc

Die Verschlüsselung ist also recht einfach. Das ist vorteilhaft für die Implementierung der Ver- und Entschlüsselung. Allerdings ist es daher aber nicht empfehlenswert die Verschlüsselung ernsthaft anzuwenden.

Die Entschlüsselung gestaltet sich nämlich genauso einfach. Selbst wenn die Verschiebung nicht bekannt ist, kann der Text nach maximal 25 Versuchen (da es 26 Buchstaben im Alphabet gibt) entschlüsselt werden. Dafür müssen lediglich alle Verschiebungen ausprobiert werden.

Die Caesar-Chiffre implementieren

Zuerst muss der Klartext des Benutzers aus dem Input entgegengenommen werden. Das habe ich in der main()-Funktion gemacht. Dafür habe ich die Funktion input() der Standard-Bibliothek verwendet und den Klartext in der Variable text gespeichert.

def main():

    text = input("Gib einen Text ein: ")

if __name__ == '__main__':
    main()

Für die eigentliche Verschiebung gibt es nun zwei Möglichkeiten:

  1. Das Anlegen zweier Arrays (ein kleines und ein großes Alphabet)
  2. Die Verschiebung mithilfe von Ascii-Code

Ich habe mich für die Verschiebung mit Ascii-Code entschieden.

Damit der Text nachher verschlüsselt werden kann, müssen Sonderzeichen umgeschrieben werden, also: ä=ae, ö=oe, ü=ue und ß=ss. Das hat den Grund, dass Sonderzeichen nicht im Ascii-Code enthalten sind.

Hinweis: Dieser Schritt muss nicht zwangsläufig gemacht werden, wenn man zwei Arrays zur Verschiebung anlegt. Wenn man in den Arrays auch die Sonderzeichen aufführt, können diese mit verschoben werden, obwohl das wahrscheinlich nicht ganz dem Sinne der “klassischen” Caesar-Chiffre entspricht.

Für die Umschreibung habe ich hier die Funktion specials geschrieben, an die der Klartext übergeben wird. Anschließend wird der Text buchstabenweise durchgegangen. Dabei wird überprüft, ob der Buchstabe ein ä, ö, ü oder ß ist und wird gegebenenfalls dementsprechend umgeschrieben, oder genauso abgeschrieben und in der neuen Variable text_without_special gespeichert. Zuletzt wird der umgeschriebene Text an die main()-Funktion zurückgegeben.

def specials(text):
    
    text_without_special = ""
    
    for letter in text:
        if (letter == "ä"):
            text_without_special += "ae"
        elif (letter == "ö"):
            text_without_special += "oe"
        elif (letter == "ü"):
            text_without_special += "ue"
        elif (letter == "ß"):
            text_without_special += "ss"
        else:
            text_without_special += letter
            
    return text_without_special

Nun kann diese Funktion in die main()-Funktion integriert werden. Dabei wird auch direkt der Input für die Zahl der Verschiebung entgegengenommen und in der Variable caesar gespeichert. Zudem wird eine neue Variable für den später verschlüsselten Text angelegt, text_new. Außerdem wissen wir schon, dass alle drei Variablen (der umgeschriebene Klartext text_without_special, der neue Text new_text und die Verschiebung caesar) an die Funktion encode() für die Verschlüsselung übergeben werden müssen.

def specials(text):
    
    text_without_special = ""
    
    for letter in text:
        if (letter == "ä"):
            text_without_special += "ae"
        elif (letter == "ö"):
            text_without_special += "oe"
        elif (letter == "ü"):
            text_without_special += "ue"
        elif (letter == "ß"):
            text_without_special += "ss"
        else:
            text_without_special += letter
            
    return text_without_special

def main():

    text = input("Gib einen Text ein: ")
    caesar = input("Um wie viele Stellen soll der Text verschoben werden ?? ")
    text_without_special = specials(text)
    text_new = ""
    encode(text_without_special, text_new, caesar)

if __name__ == '__main__':
    main()

Als nächstes kommt die Struktur für die encode()-Funktion. Zunächst wird überprüft, ob die Variable caesar für die Anzahl der Schritte für die Verschiebung gültig ist, sich also zwischen -26 und 26 befindet. Wenn dies nicht der Fall ist, muss eine andere Zahl eingegeben werden. Für die Verschiebung muss der umgeschriebene Text text_without_special buchstabenweise durchgegangen und verschoben werden. Allerdings gibt es hierfür eine neue Funktion shift(). Danach wird der fertige verschlüsselte Text ausgegeben.

def encode(text, text_new, caesar):
    
    while(int(caesar) < -26 or int(caesar) > 26):
        print("Verschiebung nicht möglich, da der Parameter ungültig ist.")
        caesar = input("Um wie viele Stellen soll der Text verschoben werden ?? ")
    
    text_new = shift(text, caesar)
    print("\nVerschlüsselter Text: ")
    print(text_new)

Die Funktion shift() soll nun die eigentliche Verschiebung vornehmen. Hier wird der Text buchstabenweise durchgegangen. Zunächst wird der Buchstabe in Ascii-Code umgeschrieben.

Anschließend wird überprüft, ob die Zahl kleiner als 65 oder größer als 90 ist und kleiner als 97 oder größer als 122 ist. Damit wird überprüft, ob sich der Ascii-Code außerhalb des großen Alphabets (65-90, da A=65 und Z=90) und außerhalb des kleinen Alphabets (97-122, da a=97 und z=122). Wenn also das Zeichen kein Buchstabe ist, dann wird er genauso beibehalten und an den neuen Text text_new angehängt.

Wenn das aktuelle Zeichen ein Buchstabe ist, muss erstmal gerechnet werden: Da der Buchstabe verschoben werden soll, wird zu dem Buchstaben die Zahl der Verschiebung caesar addiert. Nun muss sichergestellt werden, dass es sich bei dem neuen Zeichen noch um einen Buchstaben handelt und es immer noch zu dem Selben Alphabet (klein bleibt klein und groß bleibt groß) gehört. Dabei gibt es 4 Fälle:

  1. Der “neue Buchstabe” ist kleiner als 65 (A). Dann muss rest mit 65-Ascii gerechnet werden, sodass man weiß, wir groß der Abstand zum “A” ist. Dann fängt das Alphabet sozusagen wieder von hinten an und der neue Buchstabe wird mit 91 (eins größer als 90=Z) minus rest berechnet, um den korrekten Buchstaben zu finden. Zum Beispiel: Klartext = “A”, Verschiebung = -3, der neue Buchstabe ist also “A”-3 = 65-3 = 62, rest = 65-62 = 3, der richtige neue Buchstabe ist dann 91-3=88=”X”
  2. Der “neue Buchstabe” ist größer als 90 (Z) und der ursprüngliche Buchstabe ist groß. Dann wird der rest mit Ascii-90 berechnet. Dann fängt das Alphabet wieder von vorne an. Also ist der richtige neue Buchstabe 64 (eins kleiner als 65=A) plus rest. Zum Beispiel: Klartext = “Z”, Verschiebung = 3, der neue Buchstabe ist also “Z”+3 = 90+3 = 93, rest = 93-90 = 3, der richtige neue Buchstabe ist dann 64+3 = 67 = “C”
  3. Der “neue Buchstabe” ist kleiner als 97 (a) und der ursprüngliche Buchstabe ist klein. Dann wird der rest mit 97-Ascii berechnet. Dann fängt das Alphabet sozusagen wieder von hinten an. Der neue Buchstabe wird mit 123 (eins größer als 122=z) minus rest berechnet. Zum Beispiel: Klartext = “a”, Verschiebung = -3, der neue Buchstabe ist also “a”-3 = 97-3 = 94, rest = 97-94 = 3, der richtige neue Buchstabe ist dann 123-3 = 120 = “x”
  4. Der “neue Buchstabe” ist größer als 122 (z). Dann muss rest mit Ascii-122 berechnet werden. Dann fängt das Alphabet wieder von vorne an. Der neue Buchstabe wird mit 96 (eins kleiner als 97=a) plus rest berechnet. Zum Beispiel: Klartext = “z”, Verschiebung = 3, der neue Buchstabe ist also “z”+3 = 122+3 = 125, rest = 125-122 = 3, der richtige neue Buchstabe ist dann 96+3 = 99 = “c”

Nach der Berechnung wird der richtige neue Buchstabe an den neuen Text angehängt.

Wenn keiner dieser Fälle zutrifft, ist das Zwischenergebnis des neuen Buchstabens bereits ein Buchstabe und kann direkt an den neuen Text angehängt werden.

Zu guter letzt wird der neue Text an die aufrufende Funktion zurückgegeben.

def shift(text, caesar):
    
    text_new = ""
    
    for i in text:
        ascii = ord(i)
        if(ascii < 65 or ascii > 90 and ascii < 97 or ascii > 122):
            text_new = text_new + chr(ascii)
        else:
            character_new = int(ascii) + int(caesar)
            if(character_new < 65):                     # Buchstabe kleiner als A = 65
                rest = 65 - character_new
                text_new += chr(91 - rest)
            elif(character_new > 90 and ascii <= 90):   # Buchstabe ist zwischen Z = 90 und a = 97, aber groß
                rest = character_new - 90
                text_new += chr(64 + rest)
            elif(character_new < 97 and ascii >= 97):   # Buchstabe ist zwischen Z = 90 und a = 97, aber klein
                rest = 97 - character_new
                text_new += chr(123 - rest)
            elif(character_new > 122):                    # Buchstabe größer als z = 122
                rest = character_new - 122
                text_new += chr(96 + rest)
            else:
                text_new += chr(character_new)
        
    return (text_new)

Nun kann dieser Teilcode zum bereits vorhandenen Code hinzugefügt werden:

def specials(text):
    
    text_without_special = ""
    
    for letter in text:
        if (letter == "ä"):
            text_without_special += "ae"
        elif (letter == "ö"):
            text_without_special += "oe"
        elif (letter == "ü"):
            text_without_special += "ue"
        elif (letter == "ß"):
            text_without_special += "ss"
        else:
            text_without_special += letter
            
    return text_without_special

def encode(text, text_new, caesar):
    
    while(int(caesar) < -26 or int(caesar) > 26):
        print("Verschiebung nicht möglich, da der Parameter ungültig ist.")
        caesar = input("Um wie viele Stellen soll der Text verschoben werden ?? ")
    
    text_new = shift(text, caesar)
    print("\nVerschlüsselter Text: ")
    print(text_new)

def shift(text, caesar):
    
    text_new = ""
    
    for i in text:
        ascii = ord(i)
        if(ascii < 65 or ascii > 90 and ascii < 97 or ascii > 122):
            text_new = text_new + chr(ascii)
        else:
            character_new = int(ascii) + int(caesar)
            if(character_new < 65):                     # Buchstabe kleiner als A = 65
                rest = 65 - character_new
                text_new += chr(91 - rest)
            elif(character_new > 90 and ascii <= 90):   # Buchstabe ist zwischen Z = 90 und a = 97, aber groß
                rest = character_new - 90
                text_new += chr(64 + rest)
            elif(character_new < 97 and ascii >= 97):   # Buchstabe ist zwischen Z = 90 und a = 97, aber klein
                rest = 97 - character_new
                text_new += chr(123 - rest)
            elif(character_new > 122):                    # Buchstabe größer als z = 122
                rest = character_new - 122
                text_new += chr(96 + rest)
            else:
                text_new += chr(character_new)
        
    return (text_new)

def main():

    text = input("Gib einen Text ein: ")
    caesar = input("Um wie viele Stellen soll der Text verschoben werden ?? ")
    text_without_special = specials(text)
    text_new = ""
    encode(text_without_special, text_new, caesar)

if __name__ == '__main__':
    main()

Dies ist nun bereits eine komplett funktionsfähige Caesar-Verschlüsselung.

Die Entschlüsselung der Caesar-Chiffre implementieren

Entschlüsselung der Caesar-Chiffre mit Schlüssel

def main():

    code = input("Soll dein Text verschlüsselt werden (ja/nein) ?? ")
    text = input("Gib einen Text ein: ")
    text_new = ""

    if (code == "Ja" or code == "ja"):
        caesar = input("Um wie viele Stellen soll der Text verschoben werden ?? ")
        text_without_special = specials(text)
        encode(text_without_special, text_new, caesar)

    elif (code == "Nein" or code == "nein"):
        caesar = input("Bitte gib den Schlüssel ein: ")
        decode_with_key(text, text_new, caesar)

    else:
        print("Die Eingabe ist ungültig")

if __name__ == '__main__':
    main()

Die Funktion decode_with_key() überprüft zunächst die Eingabe des Schlüssels. Der Schlüssel muss zwischen 1 und 26 liegen, ansonsten muss die Eingabe wiederholt werden.

Da der Text bei der Entschlüsselung rückwärts verschoben werden muss, wird der Schlüssel caesar umgerechnet mit caesar = 26-caesar, sodass man die shift()-Funktion von oben nochmals verwenden kann. Nach der Verschiebung wird der entschlüsselte Text ausgegeben.

def decode_with_key(text, text_new, caesar):
    
    while(int(caesar) <= 0 or int(caesar) > 26):
        print("Verschiebung nicht möglich, da der Parameter ungültig ist.")
        caesar = input("Um wie viele Stellen soll der Text verschoben werden ?? ")
        
    caesar = 26 - int(caesar)
    text_new = shift(text, caesar)
    print("\nEntschlüsselter Text: ")
    print(text_new)

Zuletzt die Einbindung in den bisherigen Code:

def specials(text):
    
    text_without_special = ""
    
    for letter in text:
        if (letter == "ä"):
            text_without_special += "ae"
        elif (letter == "ö"):
            text_without_special += "oe"
        elif (letter == "ü"):
            text_without_special += "ue"
        elif (letter == "ß"):
            text_without_special += "ss"
        else:
            text_without_special += letter
            
    return text_without_special

def encode(text, text_new, caesar):
    
    while(int(caesar) < -26 or int(caesar) > 26):
        print("Verschiebung nicht möglich, da der Parameter ungültig ist.")
        caesar = input("Um wie viele Stellen soll der Text verschoben werden ?? ")
    
    text_new = shift(text, caesar)
    print("\nVerschlüsselter Text: ")
    print(text_new)

def decode_with_key(text, text_new, caesar):
    
    while(int(caesar) <= 0 or int(caesar) > 26):
        print("Verschiebung nicht möglich, da der Parameter ungültig ist.")
        caesar = input("Um wie viele Stellen soll der Text verschoben werden ?? ")
        
    caesar = 26 - int(caesar)
    text_new = shift(text, caesar)
    print("\nEntschlüsselter Text: ")
    print(text_new)

def shift(text, caesar):
    
    text_new = ""
    
    for i in text:
        ascii = ord(i)
        if(ascii < 65 or ascii > 90 and ascii < 97 or ascii > 122):
            text_new = text_new + chr(ascii)
        else:
            character_new = int(ascii) + int(caesar)
            if(character_new < 65):                     # Buchstabe kleiner als A = 65
                rest = 65 - character_new
                text_new += chr(91 - rest)
            elif(character_new > 90 and ascii <= 90):   # Buchstabe ist zwischen Z = 90 und a = 97, aber groß
                rest = character_new - 90
                text_new += chr(64 + rest)
            elif(character_new < 97 and ascii >= 97):   # Buchstabe ist zwischen Z = 90 und a = 97, aber klein
                rest = 97 - character_new
                text_new += chr(123 - rest)
            elif(character_new > 122):                    # Buchstabe größer als z = 122
                rest = character_new - 122
                text_new += chr(96 + rest)
            else:
                text_new += chr(character_new)
        
    return (text_new)

def main():

    code = input("Soll dein Text verschlüsselt werden (ja/nein) ?? ")
    text = input("Gib einen Text ein: ")
    text_new = ""

    if (code == "Ja" or code == "ja"):
        caesar = input("Um wie viele Stellen soll der Text verschoben werden ?? ")
        text_without_special = specials(text)
        encode(text_without_special, text_new, caesar)

    elif (code == "Nein" or code == "nein"):
        caesar = input("Bitte gib den Schlüssel ein: ")
        decode_with_key(text, text_new, caesar)

    else:
        print("Die Eingabe ist ungültig")

if __name__ == '__main__':
    main()

Nun haben wir eine Caesar-Chiffre, die ver- und entschlüsseln kann.

Brechen der Caesar-Chiffre (Entschlüsselung der Caesar-Chiffre ohne Schlüssel)

def main():

    code = input("Soll dein Text verschlüsselt werden (ja/nein) ?? ")
    text = input("Gib einen Text ein: ")
    text_new = ""

    if (code == "Ja" or code == "ja"):
        caesar = input("Um wie viele Stellen soll der Text verschoben werden ?? ")
        text_without_special = specials(text)
        encode(text_without_special, text_new, caesar)

    elif (code == "Nein" or code == "nein"):
        known_key = input("Ist der Schlüssel bekannt (ja/nein) ?? ")     # Herausfinden, ob der Schlüssel bekannt ist
        if (known_key == "Ja" or known_key == "ja"):
            caesar = input("Bitte gib den Schlüssel ein: ")
            decode_with_key(text, text_new, caesar)
        elif (known_key == "Nein" or known_key == "nein"):
            caesar = 0
            decode(text, text_new, caesar)
        else:
            print("Die Eingabe ist ungültig")
    else:
        print("Die Eingabe ist ungültig.")

if __name__ == '__main__':
    main()

Wie bereits in der Erklärung beschrieben, ist das Brechen der Caesar-Chiffre nicht besonders kompliziert, sondern beruht auf dem Ausprobieren verschiedener Schlüssel. Daher wurde caesar in der main()-Funktion in diesem Fall automatisch auf 0 gesetzt.

Die decode()-Funktion ist rekursiv implementiert, das heißt, dass sich die Funktion so lange immer wieder selbst ausführt, bis die Abbruchbedingung zutrifft.

Zuerst wird der aktuelle “neue Text”, also text_new mit der shift()-Funktion um caesar verschoben. Anschließend wird der Text mithilfe der Datei “wortspeicher.txt”, der später erstellt wird, auf seine Gültigkeit überprüft. Dabei wird jede Zeile der Datei ausgelesen und das entsprechende Wort einmal groß und einmal klein geschrieben mit dem aktuellen Text verglichen.

Wenn mindestens 2 Wörter (2 um einen Zufall auszuschließen) aus dem Wortspeicher in dem Text gefunden werden, dann wird der Text für richtig und entschlüsselt befunden. Dadurch wird die erste Abbruchbedingung erfüllt und der entschlüsselte Text wird ausgegeben.

Wenn weniger als 2 Wörter des Wortspeichers in dem Text gefunden wurden, dann wird der Text für falsch befunden, caesar um 1 verringert (da der Text in die Gegenrichtung verschoben wird), sofern caesar > -26 ist. Wenn caesar verringert wurde, so wird die Funktion von vorne ausgeführt. Wenn allerdings caesar bereits -26 ist, dann wurden bereits alle möglichen Schlüssel ausprobiert. Dadurch wird die zweite Abbruchbedingung erfüllt und es wird eine Fehlermeldung ausgegeben.

def decode(text, text_new, caesar):
    
    wortspeicher = open("wortspeicher.txt", "r")
    
    test = 0
    text_new = shift(text, caesar)
    
    counter = 0
    word = wortspeicher.readline(counter)
    
    while (word != ":wq!"):
        if (word in text_new or word.lower() in text_new):
            test += 1
        counter += 1
        word = wortspeicher.readline(counter)
        
    if (test >= 2):
        print("\nEntschlüsselter Text: ")
        print(text_new)
    else:
        if (caesar > -26):
            caesar = caesar - 1
            text_new = shift(text, caesar)
            decode(text, text_new, caesar)
        else:
            print("Der Text konnte nicht entschlüsselt werden :(")

Der Wortspeicher, den ich angelegt habe, enthält nur eine kleine Auswahl der am meisten verwendeten Wörter in der deutschen Sprache (Quelle: Wikipedia). Man kann den Wortspeicher natürlich jederzeit erweitern.

Beim Anlegen des Wortspeichers muss folgendes beachtet werden:

Es wichtig, dass jedes Wort mehr als 2 Buchstaben hat, da sonst die jeweilige Buchstabenkombination auch zufällig entstehen kann.

Zudem sind alle Wörter im Wortspeicher großgeschrieben, sodass das Wort einmal groß- und einmal kleingeschrieben im verschlüsselten Text gesucht wird.

Außerdem muss darauf geachtet werden, dass die Wörter keine Sonderzeichen (ä, ö, ü und ß) enthalten, oder dass diese umgeschrieben wurden.

Abgesehen davon fallen alle Wörter raus, bei denen ein Wortteil bereits in der Liste enthalten ist, zum Beispiel fällt “Beim” raus, da “Bei” schon enthalten ist. Das hat den Grund, dass dies das Ergebnis der Überprüfung, ob die Entschlüsselung gelungen ist, verfälschen würde. Wenn nun zufällig die Buchstabenkombination “beim” entschlüsselt wird, dann werden zwei Treffer im Wortspeicher gefunden, und zwar “bei” und “beim”, obwohl das eigentlich nicht der Fall sein sollte, wenn sonst kein weiteres Wort in der Entschlüsselung enthalten ist.

Ganz am Ende des Dokuments wird eine Schlusszeile benötigt, wonach die decode()-Funktion die Schleife mit dem Kopf while(word != ":wq!") bei dem entsprechenden Wort die Schleife abbricht. Dabei kann meine Schlusszeile “:wq!” durch eine beliebige andere Kombination eingetauscht werden. Jedoch sollte darauf geachtet werden, dass diese Kombination kein richtiges Wort ist und in einem normalen deutschen Text so nicht auftritt.

Aber
Alle
Als
Anderen
Andern
Anders
Auch
Aus
Auf
Bald
Bei
Bin
Bis
Ck
Damit
Dann
Darauf
Das
Dem
Den
Der
Des
Deutsch
Dich
Die
Doch
Dort
Durch
Eben
Ein
Erst
Euch
Fuer
Frau
Ganz
Gar
Gegen
Gemacht
Gewesen
Gut
Habe
Hallo
Hand
Hat
Herr
Heute
Hier
Ich
Ihm
Ihn
Ihr
Immer
Ist
Jetzt
Kann
Kein
Kommen
Konnte
Lang
Lassen
Leben
Liebe
Machen
Macht
Man
Mehr
Mein
Menschen
Mich
Mit
Muss
Nach
Nicht
Noch
Nun
Nur
Oder
Ohne
Paragraph
Qu
Sagen
Sch
Sehr
Sein
Seite
Selbst
Sich
Sie
Sind
Solche
Soll
Sondern
Und
Unter
Uns
Viel
Vom
Von
Vor
Was
War
Weil
Weise
Weit
Welche
Welt
Wenn
Wer
Wie
Wir
Wird
Wohl
Wollen
Worden
Wurde
Zeit
Zum
Zur
Zwar
Zwei
Zwischen
:wq!

Zum Schluss wird die decode()-Funktion in den bisherigen Code integriert:

def specials(text):
    
    text_without_special = ""
    
    for letter in text:
        if (letter == "ä"):
            text_without_special += "ae"
        elif (letter == "ö"):
            text_without_special += "oe"
        elif (letter == "ü"):
            text_without_special += "ue"
        elif (letter == "ß"):
            text_without_special += "ss"
        else:
            text_without_special += letter
            
    return text_without_special

def encode(text, text_new, caesar):
    
    while(int(caesar) < -26 or int(caesar) > 26):
        print("Verschiebung nicht möglich, da der Parameter ungültig ist.")
        caesar = input("Um wie viele Stellen soll der Text verschoben werden ?? ")
    
    text_new = shift(text, caesar)
    print("\nVerschlüsselter Text: ")
    print(text_new)

def decode_with_key(text, text_new, caesar):
    
    while(int(caesar) <= 0 or int(caesar) > 26):
        print("Verschiebung nicht möglich, da der Parameter ungültig ist.")
        caesar = input("Um wie viele Stellen soll der Text verschoben werden ?? ")
        
    caesar = 26 - int(caesar)
    text_new = shift(text, caesar)
    print("\nEntschlüsselter Text: ")
    print(text_new)

def decode(text, text_new, caesar):
    
    wortspeicher = open("wortspeicher.txt", "r")
    
    test = 0
    text_new = shift(text, caesar)
    
    counter = 0
    word = wortspeicher.readline(counter)
    
    while (word != ":wq!"):
        if (word in text_new or word.lower() in text_new):
            test += 1
        counter += 1
        word = wortspeicher.readline(counter)
        
    if (test >= 2):
        print("\nEntschlüsselter Text: ")
        print(text_new)
    else:
        if (caesar > -26):
            caesar = caesar - 1
            text_new = shift(text, caesar)
            decode(text, text_new, caesar)
        else:
            print("Der Text konnte nicht entschlüsselt werden :(")

def shift(text, caesar):
    
    text_new = ""
    
    for i in text:
        ascii = ord(i)
        if(ascii < 65 or ascii > 90 and ascii < 97 or ascii > 122):
            text_new = text_new + chr(ascii)
        else:
            character_new = int(ascii) + int(caesar)
            if(character_new < 65):                     # Buchstabe kleiner als A = 65
                rest = 65 - character_new
                text_new += chr(91 - rest)
            elif(character_new > 90 and ascii <= 90):   # Buchstabe ist zwischen Z = 90 und a = 97, aber groß
                rest = character_new - 90
                text_new += chr(64 + rest)
            elif(character_new < 97 and ascii >= 97):   # Buchstabe ist zwischen Z = 90 und a = 97, aber klein
                rest = 97 - character_new
                text_new += chr(123 - rest)
            elif(character_new > 122):                    # Buchstabe größer als z = 122
                rest = character_new - 122
                text_new += chr(96 + rest)
            else:
                text_new += chr(character_new)
        
    return (text_new)

def main():

    code = input("Soll dein Text verschlüsselt werden (ja/nein) ?? ")
    text = input("Gib einen Text ein: ")
    text_new = ""

    if (code == "Ja" or code == "ja"):
        caesar = input("Um wie viele Stellen soll der Text verschoben werden ?? ")
        text_without_special = specials(text)
        encode(text_without_special, text_new, caesar)

    elif (code == "Nein" or code == "nein"):
        known_key = input("Ist der Schlüssel bekannt (ja/nein) ?? ")             # Herausfinden, ob der Schlüssel bekannt ist
        if (known_key == "Ja" or known_key == "ja"):
            caesar = input("Bitte gib den Schlüssel ein: ")
            decode_with_key(text, text_new, caesar)
        elif (known_key == "Nein" or known_key == "nein"):
            caesar = 0
            decode(text, text_new, caesar)
        else:
            print("Die Eingabe ist ungültig")
    else:
        print("Die Eingabe ist ungültig.")

if __name__ == '__main__':
    main()

Hier haben wir jetzt ein fertiges Programm, das mit der Caesar-Chiffre verschlüsseln und mit oder ohne Schlüssel einen Text entschlüsseln kann.

Die Vigenère-Chiffre

Kurz zur Geschichte …

Die Vigenère-Verschlüsselung wurde von dem Kryptografen Blaise de Vigenère entwickelt. Dabei vereinigte er in seiner Chiffre die Systeme der Verschlüsselungen von Alberti, Trithemius und Porta, mit denen Vigenère sich seit seinem 26. Lebensjahr beschäftigte.

Wie funktioniert die Vigenère-Chiffre?

Im Gegensatz zur Caesar-Chiffre gehört die Vigenère-Chiffre nicht zu den Substitutions-Chiffren. Bei der Vigenère-Verschlüsselung werden bis zu 26 verschiedene Alphabete zur Verschlüsselung verwendet.

Dafür wird ein Schlüsselwort festgelegt, wonach die jeweiligen Alphabete ausgewählt werden. Zum Beispiel wenn das Schlüsselwort “Licht” ist, dann wird das Alphabet, das mit “L” beginnt ausgewählt, das das mit “I” beginnt, usw. …

Zur Veranschaulichung gibt es das Vigenère-Quadrat:

ABCDEFGHIJKLMNOPQRSTUVWXYZ
BCDEFGHIJKLMNOPQRSTUVWXYZA
CDEFGHIJKLMNOPQRSTUVWXYZAB
DEFGHIJKLMNOPQRSTUVWXYZABC
EFGHIJKLMNOPQRSTUVWXYZABCD
FGHIJKLMNOPQRSTUVWXYZABCDE
GHIJKLMNOPQRSTUVWXYZABCDEF
HIJKLMNOPQRSTUVWXYZABCDEFG
IJKLMNOPQRSTUVWXYZABCDEFGH
JKLMNOPQRSTUVWXYZABCDEFGHI
KLMNOPQRSTUVWXYZABCDEFGHIJ
LMNOPQRSTUVWXYZABCDEFGHIJK
MNOPQRSTUVWXYZABCDEFGHIJKL
NOPQRSTUVWXYZABCDEFGHIJKLM
OPQRSTUVWXYZABCDEFGHIJKLMN
PQRSTUVWXYZABCDEFGHIJKLMNO
QRSTUVWXYZABCDEFGHIJKLMNOP
RSTUVWXYZABCDEFGHIJKLMNOPQ
STUVWXYZABCDEFGHIJKLMNOPQR
TUVWXYZABCDEFGHIJKLMNOPQRS
UVWXYZABCDEFGHIJKLMNOPQRST
VWXYZABCDEFGHIJKLMNOPQRSTU
WXYZABCDEFGHIJKLMNOPQRSTUV
XYZABCDEFGHIJKLMNOPQRSTUVW
YZABCDEFGHIJKLMNOPQRSTUVWX
ZABCDEFGHIJKLMNOPQRSTUVWXY

Nun werden die einzelnen Buchstaben des zu verschlüsselnden Textes nacheinander mit den einzelnen Alphabeten entsprechend des Schlüsselwortes verschlüsselt. Das heißt, dass der erste Buchstabe des Textes mit dem Alphabet des ersten Buchstaben des Schlüsselwortes verschlüsselt wird, der zweite Buchstabe des Textes mit dem Alphabet des zweiten Buchstaben des Schlüsselwortes, usw. Wenn das Schlüsselwort zu Ende ist, wird wieder von vorne begonnen.

Zum Beispiel:

Schlüsselwort = “Licht”

Klartext = “Hallo Welt”

Verschlüsselter Text = “Sinsh Hmna”

ABCDEFGHIJKLMNOPQRSTUVWXYZ
LMNOPQRSTUVWXYZABCDEFGHIJK
IJKLMNOPQRSTUVWXYZABCDEFGH
CDEFGHIJKLMNOPQRSTUVWXYZAB
HIJKLMNOPQRSTUVWXYZABCDEFG
TUVWXYZABCDEFGHIJKLMNOPQRS

Hier die Zuteilung: H→L, A→I, L→C, L→H, O→T W→L, E→I, L→C, T→H

Je länger also das Schlüsselwort, desto mehr Alphabete werden zur Verschlüsselung verwendet und desto komplizierter wird die Verschlüsselung.

Das ist natürlich ein großer Vorteil dieser Verschlüsselungsmethode. Allerdings wird dadurch die Implementierung etwas komplizierter und erfordert etwas Umdenken.

Der “Nachteil” ist daran, dass sich der Code nur schwer brechen lässt, die Vigenère-Chiffre wird nicht umsonst “le chiffre indéchiffrable”, französisch für “die unentziffbare Chiffre” genannt. Im Normalfall ist das natürlich super, jedoch nicht wenn man eine Automatische Entschlüsselung des Codes durch den Computer implementieren will. Daher beschäftigt sich dieser Beitrag auch nicht damit.

Tipp: Das Buch “Geheime Botschaften – Die Kunst der Verschlüsselung von der Antike bis in die Zeiten des Internets” von Simon Singh

Die Vigenère-Chiffre implementieren

Bevor wieder mit der Programmierung der eigentlichen Verschlüsselung begonnen wird, benötigen wir alle Eingaben in der main()-Funktion

Zuerst wird nach einem Schlüsselwort key gefragt und anschließend direkt auf seine Gültigkeit hin überprüft.

Zuerst wird geprüft, ob überhaupt ein Wort eingegeben wurde und ob dieses länger als ein Buchstabe ist. Wenn dies der Fall ist, tritt die while-Schleife in Kraft. Es wird überprüft, ob jedes Zeichen des Schlüsselwortes ein Buchstabe ist, also ob der Ascii-Code des Zeichens zwischen 65 (A), 90 (Z), 97 (a) und 122 (z) liegt. Wenn dies nicht der Fall ist, wird die Eingabe des Schlüsselwortes wiederholt. Die Schleife wird also so lange wiederholt, bis das Schlüsselwort mindestens 2 Stellen hat und alle Zeichen Buchstaben sind.

Danach wird der Klartext vom Input entnommen.

Anschließend wird das Schlüsselwort mit der .lower()-Funktion in Kleinbuchstaben umgeschrieben.

Zum Schluss wird noch die specials()-Funktion von oben benutzt, um die möglichen Sonderzeichen (ä, ö, ü und ß) des Klartextes umzuschreiben.

def main():
   
    check = 1
    key = " "
    while (key == "" or len(key) < 2 or check == 0):      # Eingabe des Schlüsselwortes wird überprüft
        check = 1
        for letter in key:
            if (ord(letter) >= 65 and ord(letter) <= 90 or ord(letter) >= 97 and ord(letter) <= 122):   # Wenn eine Eingabe kein Buchstabe ist (Großbuchstaben: 65-90, Kleinbuchstaben: 97-122)
                check = 1
            else:
                print("Das Schlüsselwort muss mindestens 2 Zeichen haben und darf keine Ziffern oder Sonderzeichen enthalten.")
                key = input("Lege ein Schlüsselwort fest: ")
                check = 0
                break
        
    text = input("Gib einen Text ein: ")
    text_new = ""
    key = key.lower()
    text_without_special = specials(text)
    vigenere(key, text_without_special, text_new)
    
if __name__ == '__main__':
    main()

In der Funktion vigenere() wird zuerst ein Zähler counter eingeführt, der später den zugehörigen Buchstaben des Schlüsselwortes zur Verschlüsselung auswählt.

counter ist anfangs gleich 0, da der Computer immer bei 0 anfängt zu zählen, sodass man, wenn man einen bestimmten Index anwählen will, immer 1 subtrahieren muss. Das heißt, dass wenn das Schlüsselwort key “Licht” ist und man das “L” anwählen möchte, muss man key[0] verwenden.

Anschließend beginnt eine forSchleife, die jedes Zeichen des Klartextes einzeln durchgeht.

Zuerst wird überprüft, ob es sich bei dem Zeichen letter um einen Buchstaben handelt, also ob der Ascii-Code des Zeichens zwischen 65 (A) und 90 (Z) oder zwischen 97 (a) und 122 (z) liegt. Dann wird der zugehörige Buchstabe des Schlüsselwortes key_letter mit key[counter] ausgewählt, also entspricht key_letter dem Buchstaben des Schlüsselwortes key an der Stelle counter. Danach wird der Buchstabe in der Funktion shift_vigenere() verschoben und der neue Buchstabe an den neuen verschlüsselten Text text_new angehängt.

Jetzt wird überprüft, ob der Zähler counter noch kleiner ist als die Länge des Schlüsselwortes len(key) minus 1. Wenn das der Fall ist, wird counter um 1 erhöht. Wenn nicht, dann wird der Zähler zurückgesetzt auf 0. Das hat den Sinn, dass beim nächsten Buchstaben des Klartextes der nächste Buchstabe des Schlüsselwortes ausgewählt wird.

Falls das aktuelle Zeichen des Klartextes kein Buchstabe ist, dann wird das Zeichen unverändert an den neuen verschlüsselten Text new_text angehängt. In diesem Fall wird der Zähler counter nicht erhöht, da sonst der nächste Buchstabe des Klartextes nicht mit dem nächsten Buchstaben des Schlüsselwortes verschlüsselt wird. Wenn der counter auch bei “Nicht-Buchstaben” erhöht wird, wird die Verschlüsselung verfälscht.

Am Schluss wird der verschlüsselte Text ausgegeben.

def vigenere(key, text, text_new):
    
    counter = 0
    
    for letter in text:
        if (ord(letter) >= 65 and ord(letter) <= 90 or ord(letter) >= 97 and ord(letter) <= 122):
            key_letter = key[counter]
            letter_new = shift_vigenere(letter, key_letter)
            text_new += letter_new
            if (counter < len(key) - 1):
                counter += 1
            else:
                counter = 0
        else:
            text_new += letter
            
    print(text_new)

Für die Verschlüsselung der einzelnen Buchstaben kann nicht die shift()-Funktion von oben verwendet werden, da bei der Vigenère-Chiffre mithilfe von einzelnen, dynamischen Buchstaben und nicht mit einer festen Zahl wie bei der Caesar-Chiffre verschlüsselt wird.

An die shift_vigenere()-Funktion werden daher der aktuelle Buchstabe des Klartextes letter und der zugeteilte Buchstabe des Schlüsselwortes key_letter übergeben.

Als erstes wird geprüft, ob es sich bei dem Buchstaben des Klartextes um einen Großbuchstaben handelt, also, ob der Ascii-Code des Buchstabens kleiner gleich 90 (Z) ist. In diesem Fall wird der Buchstabe des Schlüsselwortes mit key_letter.upper() in einen Großbuchstaben umgeschrieben.

Da wir nicht vorhaben, 26 verschiedene Alphabete als Arrays aufzuschreiben und dann entsprechend des Buchstaben des Schlüsselwortes in dem jeweiligen Alphabet zu navigieren, muss hier umgedacht werden. Also wird diese Lösung eher mathematisch ausfallen.

Dafür müssen wir wissen, an welcher Stelle des Alphabets der aktuelle Buchstabe steht, also wie weit er vom “A” entfernt ist. Deswegen wird vom Ascii-Code des Buchstabens ord(letter) die 65 (A) abgezogen. Der verschobene Buchstabe entsteht dann aus dem Ascii-Code des Buchstabens des Schlüsselwortes ord(key_letter) und der addierten Entfernung. Damit wird der Buchstabe des Schlüsselwortes gewissermaßen zum neuen “A”.

Jetzt muss noch sichergestellt werden, dass das Alphabet nach “Z” wieder von vorne anfängt. Wenn also der Ascii-Code des verschobenen Buchstabens größer ist als 90 (Z), muss wieder die 90 vom Ascii-Code abgezogen werden. Der Rest muss dann zu 64 (eins kleiner als 65 (A)) addiert werden, damit der neue Buchstabe korrekt herauskommt.

Andernfalls, wenn der Buchstabe noch im Alphabet ist, dann kann er so beibehalten werden.

Wenn der Ascii-Code des ursprünglichen Buchstabens größer ist als 90, dann handelt es sich um Kleinbuchstaben. In diesem Fall muss der Buchstabe des Schlüsselwortes nicht in einen Kleinbuchstaben umgeschrieben werden, da dies bereits in der main()-Funktion gemacht wurde. Die Berechnung des verschlüsselten Buchstaben erfolgt genauso wie oben bei den Großbuchstaben, mit den Ascii-Codes des kleinen Alphabets (97 (a) bis 122 (z)) ausgetauscht werden.

Zum Schluss wird der verschlüsselte Buchstabe letter_new an die aufrufende Funktion zurückgegeben.

def shift_vigenere(letter, key_letter):
    
    if (ord(letter) <= 90):                         # Großbuchstaben: 65-90
        key_letter = key_letter.upper()
        distance = ord(letter) - 65
        new_character = ord(key_letter) + distance
        if (new_character > 90):
            rest = new_character - 90
            letter_new = chr(65 + rest - 1)
        else:
            letter_new = chr(new_character)
    else:                                               # Kleinbuchstaben: 97-122
        distance = ord(letter) - 97
        new_character = ord(key_letter) + distance
        if (new_character > 122):
            rest = new_character - 122
            letter_new = chr(97 + rest - 1)
        else:
            letter_new = chr(new_character)
    
    return (letter_new)

Nun können wir die Vigenère-Chiffre zusammensetzen:

def vigenere(key, text, text_new):
    
    counter = 0
    
    for letter in text:
        if (ord(letter) >= 65 and ord(letter) <= 90 or ord(letter) >= 97 and ord(letter) <= 122):
            key_letter = key[counter]
            letter_new = shift_vigenere(letter, key_letter)
            text_new += letter_new
            if (counter < len(key) - 1):
                counter += 1
            else:
                counter = 0
        else:
            text_new += letter
            
    print(text_new)

def shift_vigenere(letter, key_letter):
    
    if (ord(letter) <= 90):                         # Großbuchstaben: 65-90
        key_letter = key_letter.upper()
        distance = ord(letter) - 65
        new_character = ord(key_letter) + distance
        if (new_character > 90):
            rest = new_character - 90
            letter_new = chr(65 + rest - 1)
        else:
            letter_new = chr(new_character)
    else:                                               # Kleinbuchstaben: 97-122
        distance = ord(letter) - 97
        new_character = ord(key_letter) + distance
        if (new_character > 122):
            rest = new_character - 122
            letter_new = chr(97 + rest - 1)
        else:
            letter_new = chr(new_character)
    
    return (letter_new)

def main():
   
    check = 1
    key = " "
    while (key == "" or len(key) < 2 or check == 0):      # Eingabe des Schlüsselwortes wird überprüft
        check = 1
        for letter in key:
            if (ord(letter) >= 65 and ord(letter) <= 90 or ord(letter) >= 97 and ord(letter) <= 122):   # Wenn eine Eingabe kein Buchstabe ist (Großbuchstaben: 65-90, Kleinbuchstaben: 97-122)
                check = 1
            else:
                print("Das Schlüsselwort muss mindestens 2 Zeichen haben und darf keine Ziffern oder Sonderzeichen enthalten.")
                key = input("Lege ein Schlüsselwort fest: ")
                check = 0
                break
        
    text = input("Gib einen Text ein: ")
    text_new = ""
    key = key.lower()
    text_without_special = specials(text)
    vigenere(key, text_without_special, text_new)
    
if __name__ == '__main__':
    main()

Jetzt haben wir eine fertige Vigenère-Verschlüsselung.

Der vollständige Quelltext

Das Einsetzen der Vigenère-Chiffre in den Quelltext der Caesar-Chiffre

Zuerst wird das Menü der Caesar-Chiffre erweitert um das Menü der Vigenère-Chiffre.

Dabei wird eine Auswahl eingeführt, ob die Caesar- oder die Vigenère-Chiffre angewendet werden soll. Wenn “Caesar” bzw. “caesar” eingegeben wird, wird das Menü der Caesar-Chiffre ausgeführt. Wenn “Vigenere” bzw. “vigenere” eingegeben wird, so wird das Menü der Vigenère-Verschlüsselung ausgeführt. Falls etwas anderes eingegeben wird, ist die Eingabe ungültig und es wird eine Fehlermeldung zurückgegeben.

def main():
    
    wahl = input("Welche Verschlüsselung soll angewendet werden (Caesar/Vigenere) ?? ")
    
    if (wahl == "Caesar" or wahl == "caesar"):
        code = input("Soll dein Text verschlüsselt werden (ja/nein) ?? ")
        text = input("Gib einen Text ein: ")
        text_new = ""
        
        if (code == "Ja" or code == "ja"):
            caesar = input("Um wie viele Stellen soll der Text verschoben werden ?? ")
            text_without_special = specials(text)
            encode(text_without_special, text_new, caesar)
        elif (code == "Nein" or code == "nein"):
            known_key = input("Ist der Schlüssel bekannt (ja/nein) ?? ")             # Herausfinden, ob der Schlüssel bekannt ist
            if (known_key == "Ja" or known_key == "ja"):
                caesar = input("Bitte gib den Schlüssel ein: ")
                decode_with_key(text, text_new, caesar)
            elif (known_key == "Nein" or known_key == "nein"):
                caesar = 0
                decode(text, text_new, caesar)
            else:
                print("Die Eingabe ist ungültig")
        else:
            print("Die Eingabe ist ungültig.")
    elif (wahl == "Vigenere" or wahl == "vigenere"):
        check = 1
        key = " "
        while (key == "" or len(key) < 2 or check == 0):      # Eingabe des Schlüsselwortes wird überprüft
            check = 1
            for letter in key:
                if (ord(letter) >= 65 and ord(letter) <= 90 or ord(letter) >= 97 and ord(letter) <= 122):   # Wenn eine Eingabe kein Buchstabe ist (Großbuchstaben: 65-90, Kleinbuchstaben: 97-122)
                    check = 1
                else:
                    print("Das Schlüsselwort muss mindestens 2 Zeichen haben und darf keine Ziffern oder Sonderzeichen enthalten.")
                    key = input("Lege ein Schlüsselwort fest: ")
                    check = 0
                    break
        
        text = input("Gib einen Text ein: ")
        text_new = ""
        key = key.lower()
        text_without_special = specials(text)
        vigenere(key, text_without_special, text_new)
    else:
        print("Die Eingabe ist ungültig.")
    
if __name__ == '__main__':
    main()

Die restlichen Teilcodes bleiben so wie sie sind. Die einzelnen Funktionen können einfach aneinander gereiht werden.

def specials(text):
    
    text_without_special = ""
    
    for letter in text:
        if (letter == "ä"):
            text_without_special += "ae"
        elif (letter == "ö"):
            text_without_special += "oe"
        elif (letter == "ü"):
            text_without_special += "ue"
        elif (letter == "ß"):
            text_without_special += "ss"
        else:
            text_without_special += letter
            
    return text_without_special

def encode(text, text_new, caesar):
    
    while(int(caesar) < -26 or int(caesar) > 26):
        print("Verschiebung nicht möglich, da der Parameter ungültig ist.")
        caesar = input("Um wie viele Stellen soll der Text verschoben werden ?? ")
    
    text_new = shift(text, caesar)
    print("\nVerschlüsselter Text: ")
    print(text_new)
    
def decode_with_key(text, text_new, caesar):
    
    while(int(caesar) <= 0 or int(caesar) > 26):
        print("Verschiebung nicht möglich, da der Parameter ungültig ist.")
        caesar = input("Um wie viele Stellen soll der Text verschoben werden ?? ")
        
    caesar = 26 - int(caesar)
    text_new = shift(text, caesar)
    print("\nEntschlüsselter Text: ")
    print(text_new)
    
def decode(text, text_new, caesar):
    
    wortspeicher = open("wortspeicher.txt", "r")
    
    test = 0
    text_new = shift(text, caesar)
    
    counter = 0
    word = wortspeicher.readline(counter)
    
    while (word != ":wq!"):
        if (word in text_new or word.lower() in text_new):
            test += 1
        counter += 1
        word = wortspeicher.readline(counter)
        
    if (test >= 2):
        print("\nEntschlüsselter Text: ")
        print(text_new)
    else:
        if (caesar > -26):
            caesar = caesar - 1
            text_new = shift(text, caesar)
            decode(text, text_new, caesar)
        else:
            print("Der Text konnte nicht entschlüsselt werden :(")
        
def shift(text, caesar):
    
    text_new = ""
    
    for i in text:
        ascii = ord(i)
        if(ascii < 65 or ascii > 90 and ascii < 97 or ascii > 122):
            text_new = text_new + chr(ascii)
        else:
            character_new = int(ascii) + int(caesar)
            if(character_new < 65):                     # Buchstabe kleiner als A = 65
                rest = 65 - character_new
                text_new += chr(91 - rest)
            elif(character_new > 90 and ascii <= 90):   # Buchstabe ist zwischen Z = 90 und a = 97, aber groß
                rest = character_new - 90
                text_new += chr(64 + rest)
            elif(character_new < 97 and ascii >= 97):   # Buchstabe ist zwischen Z = 90 und a = 97, aber klein
                rest = 97 - character_new
                text_new += chr(123 - rest)
            elif(character_new > 122):                    # Buchstabe größer als z = 122
                rest = character_new - 122
                text_new += chr(96 + rest)
            else:
                text_new += chr(character_new)
        
    return (text_new)

def vigenere(key, text, text_new):
    
    counter = 0
    
    for letter in text:
        if (ord(letter) >= 65 and ord(letter) <= 90 or ord(letter) >= 97 and ord(letter) <= 122):
            key_letter = key[counter]
            letter_new = shift_vigenere(letter, key_letter)
            text_new += letter_new
            if (counter < len(key) - 1):
                counter += 1
            else:
                counter = 0
        else:
            text_new += letter
            
    print(text_new)
    return (text_new)

def shift_vigenere(letter, key_letter):
    
    if (ord(letter) <= 90):                         # Großbuchstaben: 65-90
        key_letter = key_letter.upper()
        distance = ord(letter) - 65
        new_character = ord(key_letter) + distance
        if (new_character > 90):
            rest = new_character - 90
            letter_new = chr(65 + rest - 1)
        else:
            letter_new = chr(new_character)
    else:                                               # Kleinbuchstaben: 97-122
        distance = ord(letter) - 97
        new_character = ord(key_letter) + distance
        if (new_character > 122):
            rest = new_character - 122
            letter_new = chr(97 + rest - 1)
        else:
            letter_new = chr(new_character)
    
    return (letter_new)

def main():
    
    wahl = input("Welche Verschlüsselung soll angewendet werden (Caesar/Vigenere) ?? ")
    
    if (wahl == "Caesar" or wahl == "caesar"):
        code = input("Soll dein Text verschlüsselt werden (ja/nein) ?? ")
        text = input("Gib einen Text ein: ")
        text_new = ""
        
        if (code == "Ja" or code == "ja"):
            caesar = input("Um wie viele Stellen soll der Text verschoben werden ?? ")
            text_without_special = specials(text)
            encode(text_without_special, text_new, caesar)
        elif (code == "Nein" or code == "nein"):
            known_key = input("Ist der Schlüssel bekannt (ja/nein) ?? ")     # Herausfinden, ob der Schlüssel bekannt ist
            if (known_key == "Ja" or known_key == "ja"):
                caesar = input("Bitte gib den Schlüssel ein: ")
                decode_with_key(text, text_new, caesar)
            elif (known_key == "Nein" or known_key == "nein"):
                caesar = 0
                decode(text, text_new, caesar)
            else:
                print("Die Eingabe ist ungültig")
        else:
            print("Die Eingabe ist ungültig.")
    elif (wahl == "Vigenere" or wahl == "vigenere"):
        check = 1
        key = " "
        while (key == "" or len(key) < 2 or check == 0):      # Eingabe des Schlüsselwortes wird überprüft
            check = 1
            for letter in key:
                if (ord(letter) >= 65 and ord(letter) <= 90 or ord(letter) >= 97 and ord(letter) <= 122):   # Wenn eine Eingabe kein Buchstabe ist (Großbuchstaben: 65-90, Kleinbuchstaben: 97-122)
                    check = 1
                else:
                    print("Das Schlüsselwort muss mindestens 2 Zeichen haben und darf keine Ziffern oder Sonderzeichen enthalten.")
                    key = input("Lege ein Schlüsselwort fest: ")
                    check = 0
                    break
        
        text = input("Gib einen Text ein: ")
        text_new = ""
        key = key.lower()
        text_without_special = specials(text)
        vigenere(key, text_without_special, text_new)
    else:
        print("Die Eingabe ist ungültig.")
    
if __name__ == '__main__':
    main()

Zum Schluss haben wir einen vollständigen Quelltext, der die Caesar-Verschlüsselung und Entschlüsselung sowie das Brechen des Codes enthält. Zudem kann das Programm einen Text mit der Vigenère-Chiffre verschlüsseln. All das zusammengefasst in einem übersichtlichen Menü.

Abschlussbericht

Was muss allgemein in den Abschlussbericht eines Projekts?

  1. Ziele des Projekts
    • Ziele und Funktionen des Programms/Projekts (Infos aus der Aufgabenstellung)
    • gegebenenfalls eigene Ziele
  2. Umsetzung
  3. Probleme bei der Umsetzung
    • Probleme, die vorher bekannt waren oder vermutet wurden
    • Probleme, die während der Umsetzung aufgetreten sind
    • gegebenenfalls: Wie wurde das Problem gelöst?
  4. Wie viel Zeit wurde benötigt?
    • optional
    • gegebenenfalls eine genauere Aufteilung, wieviel Zeit für was benötigt wurde

Kurzer Abschlussbericht von diesem Bericht

Die Ziele dieses Semesterprogrammierprojekts waren es, eine funktionierende Ver- und Entschlüsselung mit der Caesar-Chiffre, sowie das Brechen des Codes, also das Selbstständige Entschlüsseln des Codes durch den Computer ohne Schlüssel, zu implementieren. Zusätzlich habe ich mir vorgenommen, eine zusätzliche Chiffre, die Vigenère-Chiffre, umzusetzen.

Die Erläuterung der Umsetzung dieser Ziele ist oben beschrieben.

Meine einzigen Probleme beim Programmieren haben sich auf die Dateioperationen bezogen. Diese werden für die Überprüfung beim Brechen der Caesar-Chiffre benötigt. Um das umzusetzen, musste ich noch etwas recherchieren und herum probieren, weil ich mich mit Dateioperationen noch nicht ausführliche beschäftigt hatte.

Ich habe insgesamt für die Programmierung des gesamten Projekts rund 4 Stunden gebraucht.

14630cookie-checkSemesterprogrammierprojekt: Caesar- und Vigenère-Verschlüsselung in Python

2 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *