mein Ziel ist es, den Algorithmus der ENIGMA in Python zu implementieren. Soweit läuft es ganz gut. Die Daten werden über eine Konfigurationsdatei übergeben:
Code: Alles auswählen
[Initialisierung]
umkehrwalze = B
walzenlage = I IV III
ringstellung = 16 26 8
steckerverbindungen = AD CN ET FL GI JV KZ PU QY WX
individueller_spruchschlüssel = RTZ
text = Das Oberkommando der Wehrmacht gibt bekannt:
Aachen ist gerettet.
Durch gebuendelten Einsatz der Hilfskraefte konnte die Bedrohung abgewendet
und die Rettung der Stadt gegen achtzehn Uhr sichergestellt werden.
zurechtgebogene nachricht = DAS OBERKOMMANDO DER WEHRMACHT GIBT BEKANNT:
AACHEN IST GERETTET.
DURCH GEBUENDELTEN EINSATZ DER HILFSKRAEFTE KONNTE DIE BEDROHUNG ABGEWENDET
UND DIE RETTUNG DER STADT GEGEN ACHTZEHN UHR SICHERGESTELLT WERDEN.
ergebnis = MM
Code: Alles auswählen
# Soll in ferner Zukunft Nachrichten der ENIGMA I ver-/entschlüsseln können
from string import ascii_uppercase
import configparser
import re
## ================ 1. Initialisierung ===========================================
c = configparser.ConfigParser(inline_comment_prefixes=("#", ";"))
# Sorgt dafür, dass Kommentare nicht mitverarbeitet werden. ACHTUNG:
# Kommentare werden nicht bewahrt, sondern gelöscht
# Dieses Feature wird von configarser, dem Standard-Modul von Python für
# das Parser von Konfigurationsdateien nicht unterstützt
c.read("test.ini")
# == 1.1 Paarung: Erschaffung des Wertes und Überprüfung auf syntaktische
# Korrektheit ==
umkehrwalze = c.get("Initialisierung", "Umkehrwalze")
if re.fullmatch("A|B|C", umkehrwalze) == None:
raise ValueError("Die Umkehrwalze in der Konfigurationsdatei ist weder A, B, noch C!")
## print(umkehrwalze)
walzenlage = c.get("Initialisierung", "Walzenlage")
walzenlage = walzenlage.split()
if len(walzenlage) == 3 and walzenlage[0] != walzenlage[1] != walzenlage[2]:
for i in walzenlage:
if re.fullmatch("I|II|III|IV|V", i) == None:
print("""Einer der Bestandteile der Walzenlage aus der Konfigura-
tionsdatei ist keine römische Zahl zwischen 1 und 5""")
else:
print("""Dieses Programm arbeitet nur mit exakt drei Walzen. Sie haben in
der Konfigurationsdatei zu viele oder zu wenige angegeben""")
ringstellung = c.get("Initialisierung", "Ringstellung")
ringstellung = ringstellung.split() # Ringstellung noch nicht implementiert
## print(ringstellung)
steckerung = c.get("Initialisierung", "Steckerverbindungen")
steckerverbindungen = steckerung.split()
if len(steckerverbindungen) <= 10:
for i in steckerverbindungen:
if re.fullmatch("[A-Z]{2}", i) == None:
raise ValueError("Die Steckerverbindungen bestehen nicht aus exakt zwei Großbuchstaben!")
## print(steckerverbindungen)
spruchschluessel = c.get("Initialisierung", "individueller_Spruchschlüssel")
if re.fullmatch("[A-Z]{3}", spruchschluessel) == None:
raise ValueError("""Der Wert des Spruchschlüssels in der Konfigurationsdatei
besteht nicht aus drei Großbuchstaben! """+spruchschluessel)
spruchschluessel = list(spruchschluessel)
#=== 1.2. alle Werte überprüft, Erzeugung der temporären Variablen =============
for l in spruchschluessel:
spruchschluessel[spruchschluessel.index(l)] = ord(l)-65 # "A" --> 0
print("Spruchschlüssel: ", spruchschluessel)
nachricht = c.get("Initialisierung", "Text")
## print(nachricht)
ascii_uppercase = list(ascii_uppercase)
# Buchstaben-Zahlen-Mapping
zuzahl = dict(zip(list(ascii_uppercase), list(range(26))))
zubuchstabe = dict((value, key) for (key, value) in zuzahl.items())
print("Zuzahl: ", zuzahl)
print("zubuchstabe: ", zubuchstabe)
print("ASCII_uppercase: ", ascii_uppercase)
# interne Verkabelung der Walzen
walzeI = ["E", "K", "M", "F", "L", "G", "D", "Q", "V", "Z", "N", "T", "O", "W",
"Y", "H", "X", "U", "S", "P", "A", "I", "B", "R", "C", "J"]
walzeII = ["A", "J", "D", "K", "S", "I", "R", "U", "X", "B", "L", "H", "W",
"T", "M", "C", "Q", "G", "Z", "N", "P", "Y", "F", "V", "O", "E"]
walzeIII = ["B", "D", "F", "H", "J", "L", "C", "P", "R", "T", "X", "V", "Z",
"N", "Y", "E", "I", "W", "G", "A", "K", "M", "U", "S", "Q", "O"]
walzeIV = ["E", "S", "O", "V", "P", "Z", "J", "A", "Y", "Q", "U", "I", "R",
"H", "X", "L", "N", "F", "T", "G", "K", "D", "C", "M", "W", "B"]
walzeV = ["V", "Z", "B", "R", "G", "I", "T", "Y", "U", "P", "S", "D", "N",
"H", "L", "X", "A", "W", "M", "J", "Q", "O", "F", "E", "C", "K"]
print("Walze 3: ", list(zip(ascii_uppercase, walzeIII)))
walze_I = [dict(zip(ascii_uppercase, walzeI)), zuzahl["R"]]
walze_II = [dict(zip(ascii_uppercase, walzeII)), zuzahl["F"]]
walze_III = [dict(zip(ascii_uppercase, walzeIII)), zuzahl["W"]]
walze_IV = [dict(zip(ascii_uppercase, walzeIV)), zuzahl["K"]]
walze_V = [dict(zip(ascii_uppercase, walzeV)), zuzahl["A"]]
#print(walze_V)
for f in walzenlage:
if f == "I":
walzenlage[walzenlage.index(f)] = walze_I
elif f == "II":
walzenlage[walzenlage.index(f)] = walze_II
elif f == "III":
walzenlage[walzenlage.index(f)] = walze_III
elif f == "IV":
walzenlage[walzenlage.index(f)] = walze_IV
elif f == "V":
walzenlage[walzenlage.index(f)] = walze_V
else:
print("Fehler in der Walzenlagenverarbeitung")
print("Walzenlage: ", walzenlage)
walzenlage_invers = []
print("")
for f in walzenlage:
print("f: ", f[0])
einzelnes_dict = {wert : schluessel for (schluessel, wert) in f[0].items()}
print("dict: ", einzelnes_dict)
walzenlage_invers.append(einzelnes_dict)
walzenlage_invers = tuple(walzenlage_invers)
print("walzenlage_invers: ", walzenlage_invers)
# Steckerung:
print("Steckerverbindungen: ", steckerverbindungen)
#print({i[0]:i[1] for i in steckerverbindungen})
#print({i[1]:i[0] for i in steckerverbindungen})
steckerungsdict = {i[0]:i[1] for i in steckerverbindungen}
#print("Steckerungsdict: ", steckerungsdict)
## print(steckerungsdict)
inverses_steckerungsdict = {value:key for (key,value) in steckerungsdict.items()}
## print(inverses_steckerungsdict)
steckerungsdict.update(inverses_steckerungsdict) # Die Steckerung ist invers, so aufwendig implementiert, da das sofortige Erzeugen+Zusammenfügen nicht möglich war (Erzeugung eines
# Objektes des Types NoneType)
##print(steckerungsdict)
##print(len(steckerverbindungen))
##print(len(steckerungsdict))
# Umkehrwalzen
# Beispiel für die Erzeugung des Dictionarys ("Hash" oder "associative array"
# in anderen Programmiersprachen), das die Daten der Umkehrwalze B enthält:
##>>> s = " AY BR CU DH EQ FS GL IP JX KN MO TZ VW "
##>>> e = s.split()
##>>> e
##['AY', 'BR', 'CU', 'DH', 'EQ', 'FS', 'GL', 'IP', 'JX', 'KN', 'MO', 'TZ', 'VW']
##>>> umkb = {i[0]:i[1] for i in e}
##>>> umkb
##{'V': 'W', 'T': 'Z', 'F': 'S', 'G': 'L', 'D': 'H', 'E': 'Q', 'B': 'R', 'C': 'U', 'A': 'Y', 'M': 'O', 'J': 'X', 'K': 'N', 'I': 'P'}
##>>> umkb.update(dict((value, key) for (key, value) in umkb.items())
##>>> len(e)
##13
##>>> len(umkb)
##13
umkehrwalze_A = {'Y': 'G', 'X': 'H', 'Z': 'D', 'Q': 'O', 'P': 'U', 'S': 'T',
'R': 'N', 'U': 'P', 'T': 'S', 'W': 'K', 'V': 'I', 'I': 'V',
'H': 'X', 'K': 'W', 'J': 'B', 'M': 'C', 'L': 'F', 'O': 'Q',
'N': 'R', 'A': 'E', 'C': 'M', 'B': 'J', 'E': 'A', 'D': 'Z',
'G': 'Y', 'F': 'L'}
umkehrwalze_B = {'Y': 'A', 'X': 'J', 'Z': 'T', 'Q': 'E', 'P': 'I', 'S': 'F',
'R': 'B', 'U': 'C', 'T': 'Z', 'W': 'V', 'V': 'W', 'I': 'P',
'H': 'D', 'K': 'N', 'J': 'X', 'M': 'O', 'L': 'G', 'O': 'M',
'N': 'K', 'A': 'Y', 'C': 'U', 'B': 'R', 'E': 'Q', 'D': 'H',
'G': 'L', 'F': 'S'}
umkehrwalze_C = {'Y': 'H', 'X': 'M', 'Z': 'L', 'Q': 'T', 'P': 'C', 'S': 'U',
'R': 'K', 'U': 'S', 'T': 'Q', 'W': 'N', 'V': 'B', 'I': 'E',
'H': 'Y', 'K': 'R', 'J': 'D', 'M': 'X', 'L': 'Z', 'O': 'G',
'N': 'W', 'A': 'F', 'C': 'P', 'B': 'V', 'E': 'I', 'D': 'J',
'G': 'O', 'F': 'A'}
if umkehrwalze == "A":
verwendete_umkehrwalze = umkehrwalze_A
elif umkehrwalze == "B":
verwendete_umkehrwalze = umkehrwalze_B
elif umkehrwalze == "C":
verwendete_umkehrwalze = umkehrwalze_C
# Nachricht nachbearbeiten! ersetzt Kleinbuchstaben und Ziffern durch
# Großbuchstaben und ausgeschrieben Zahlen
nachricht = nachricht.upper()
nachricht = nachricht.replace("Ü", "UE").replace("Ö","OE").replace("Ä","AE")
nachricht_bearbeitet = ""
for i in nachricht:
if i =="0":
i="NULL"
elif i == "1":
i="EINS"
elif i == "2":
i="ZWEI"
elif i == "3":
i="DREI"
elif i == "4":
i="VIER"
elif i == "5":
i="FUENF"
elif i == "6":
i="SECHS"
elif i == "7":
i="SIEBEN"
elif i == "8":
i="ACHT"
elif i == "9":
i="NEUN"
else:
pass
nachricht_bearbeitet += i
c.set("Initialisierung", "zurechtgebogene Nachricht", nachricht_bearbeitet)
print(c.items("Initialisierung"))
nachricht = nachricht_bearbeitet
del nachricht_bearbeitet
## ======================== "ausführender" Programmteil =======================
ergebnis = ""
print(zubuchstabe)
def enigma():
global ergebnis
print(verwendete_umkehrwalze)
print("==========================================================")
print("zuzahl = ", zuzahl)
print("\n", "walzenlage[2][1] = ", walzenlage[2][1])
for i in nachricht:
if nachricht.index(i) < 2:
print("===================================================")
print("Anfang: ", i)
if i in ascii_uppercase:
if i in steckerungsdict.keys():
i = steckerungsdict[i]
print("gesteckert: ", i)
else:
pass
print("Position der ersten Walze: ", spruchschluessel[2], "/", zubuchstabe[spruchschluessel[2]])
spruchschluessel[2] = (spruchschluessel[2]+1) % 26 # Fortschalten der ersten Walze bei jedem Tastendruck; Spruchschluessel = Liste der drei Walzenlagen in Zahlen
print("1. Walze fortgeschaltet")
print("Position der ersten Walze: ", spruchschluessel[2], "/", zubuchstabe[spruchschluessel[2]])
if spruchschluessel[2] == walzenlage[2][1]:
spruchschluessel[1] = (spruchschluessel[1]+1) % 26
print("2. Walze fortgeschaltet")
if spruchschluessel[1] == walzenlage[1][1]:
spruchschluessel[0] = (spruchschluessel[0]+1) % 26
spruchschluessel[1] = (spruchschluessel[1]+1) % 26 # jetzt sind die Walzen fortgeschaltet
print("3. und 2. Walze fortgeschaltet")
# Momentanzustand: i = Großbuchstabe
# zuzahl = Buchstabe-Zahl-Dict
# zubuchstabe = Zahl-Buchstabe-Dict
i = walzenlage[2][0][zubuchstabe[(zuzahl[i]+spruchschluessel[2])%26]] # Walzen
print("1. Walze: ", i)
i = walzenlage[1][0][zubuchstabe[(zuzahl[i]+
spruchschluessel[1]-spruchschluessel[2])%26]]
print("2. Walze: ", i)
i = walzenlage[0][0][zubuchstabe[(zuzahl[i]\
+spruchschluessel[0]-spruchschluessel[1]\
)%26]]
print("3. Walze: ", i) # bis hierhin stimmt´s
#===============================================================
# print("Walzenlage: ", walzenlage)
# print("Buchstabe bis hierhin (korrekt): ", i)
# print("Buchstabe bis hierhin (als Zahl): ", zuzahl[i])
# print("Spruchschlüssel [0] (als Buchstabe):",
# zubuchstabe[spruchschluessel[0]])
# print("Spruchschlüssel [0] (als Zahl) :", spruchschluessel[0])
# print("verwendete Umkehrwalze: B / ", verwendete_umkehrwalze)
# print("inverser Buchstabe: ", (25-zuzahl[i])%26)
# print("Zwischenergebnis (als Buchstabe): ", zubuchstabe[(zuzahl[i]+spruchschluessel[0])%26])
# print("Zwischenergebnis (als Zahl): ", (zuzahl[i]+spruchschluessel[0])%26)
#===============================================================
print("Umkehrwalze['e']: ", verwendete_umkehrwalze["E"])
print("umkehrwalze - 3. walze: ", zubuchstabe[(zuzahl[i]-spruchschluessel[0])%26])
print("wieder ohne Zahl: ", (zuzahl[i]-spruchschluessel[0]))
i = verwendete_umkehrwalze[zubuchstabe[(zuzahl[i]-spruchschluessel[0])%26]]
print("Nach Umkehrwalze: ", i)
print("3. Walze invers['C']: ", walzenlage_invers[0]["C"])
print("3. Walze invers: ", walzenlage[0][0]["O"])
print("Zwischenergebnis: ", zuzahl[i])
i = walzenlage_invers[0][zubuchstabe[(zuzahl[i]+spruchschluessel[0]-spruchschluessel[1]-spruchschluessel[2])%26]]
print("3. Walze beim zweiten Mal: ", i)
print("nach der 3. Walze beim zweiten Male (als Zahl): ", zuzahl[i])
print("zweite Walze: ", walzenlage[1][0])
i = walzenlage_invers[1][zubuchstabe[(zuzahl[i]+spruchschluessel[0])%26]]
print("2. Walze beim zweiten Mal: ", i)
i = walzenlage_invers[2][zubuchstabe[(zuzahl[i]-spruchschluessel[2])%26]]
print("1. Walze beim zweiten Mal: ", i)
# sonstiges ...
if i in steckerungsdict.keys():
i = steckerungsdict[i]
else:
pass
print("zum zweiten Male gesteckert = Ergebnis: ", i)
ergebnis += i
print("Ergebnis: ", i)
else:
break
print()
print(ergebnis)
c.set("Initialisierung", "Ergebnis", ergebnis)
file = open("test.ini", "w")
c.write(file)
if __name__ == "__main__":
enigma()
Danke.
PS: Ich habe auf Klassen etc. verzichtet, da die Dateien für mich einen PoC darstellen, den ich irgendwann nach OpenCL implementieren möchte. Da ich in OpenCL noch sehr unerfahren bin, habe ich mich dazu entschieden, nur möglichst einfache grammatikalische Strukturen zu verwenden, um die Portierung zu erleichtern.