My approach was to model the rotors, the reflector, and the plug board first, allowing for their initialisation. Then the cipher/decipher process is relatively straightforward; as both ciphertext letter and plaintext letter are identified through the same ‘reflection’ operation.
The rotor settings and arrangements were taken from wikipedia.
import string
STEP 1. Wheel starting position (for example):
rotor1_start = 'O'
rotor2_start = 'V'
rotor3_start = 'D'
STEP 2. Produce rotors and set their starting positions, then define plugboard
alpha_list = [chr(num+97).upper() for num in range(0,26,1)]
rotor1 = "EKMFLGDQVZNTOWYHXUSPAIBRCJ"
rotor1 = [letter for letter in rotor1]
slice_index = 0
for letter in rotor1:
if letter != rotor1_start:
slice_index += 1
else:
break
a = rotor1[slice_index:]
b = rotor1[:slice_index]
for letter in b:
a.append(letter)
rotor1_init = a
rotor1 = zip(alpha_list,rotor1_init)
rotor1 = {a:b for a,b in rotor1}
rotor2 = "AJDKSIRUXBLHWTMCQGZNPYFVOE"
rotor2 = [letter for letter in rotor2]
slice_index = 0
for letter in rotor2:
if letter != rotor2_start:
slice_index += 1
else:
break
a = rotor2[slice_index:]
b = rotor2[:slice_index]
for letter in b:
a.append(letter)
rotor2_init = a
rotor2 = zip(alpha_list,rotor2_init)
rotor2 = {a:b for a,b in rotor2}
rotor3 = "BDFHJLCPRTXVZNYEIWGAKMUSQO"
rotor3 = [letter for letter in rotor3]
slice_index = 0
for letter in rotor3:
if letter != rotor3_start:
slice_index += 1
else:
break
a = rotor3[slice_index:]
b = rotor3[:slice_index]
for letter in b:
a.append(letter)
rotor3_init = a
rotor3 = zip(alpha_list,rotor3_init)
rotor3 = {a:b for a,b in rotor3}
From Enigma Reflector ‘A’
reflector = "EJMZALYXVBWFCRQUONTSPIKHGD"
reflector = [letter for letter in reflector]
reflector = zip(alpha_list,reflector)
reflector = {a:b for a,b in reflector}
Set up the plug board
plug_board = {'E':'J','O':'Y','I':'V','A':'Q','K':'W','F':'X','M':'T','P':'S','L':'U','B':'D'}
plug_board_list = ['E','O','I','A','K','F','M','P','L','B']
plug_board_rev = {'J':'E','Y':'O','V':'I','Q':'A','W':'K','X':'F','T':'M','S':'P','U':'L','D':'B'}
plug_board_list_rev = ['J','Y','V','Q','W','X','T','S','U','D']
STEP 3. Initialisation Settings for rotor order, for example:
Wheel order
wheel_order = (rotor1,rotor2,rotor3)
STEP 4. Based on starting order, convert all alphabets except for the first to numerical
conversion_map = {chr(num+97).upper():num for num in range(0,26,1)}
for k,v in wheel_order[0].iteritems():
numeric = conversion_map[v]
wheel_order[0][k] = numeric
for k,v in wheel_order[1].iteritems():
numeric = conversion_map[v]
wheel_order[1][k] = numeric
numeric2 = conversion_map[k]
wheel_order[1][numeric2] = wheel_order[1][k]
del wheel_order[1][k]
for k,v in wheel_order[2].iteritems():
numeric = conversion_map[v]
wheel_order[2][k] = numeric
numeric2 = conversion_map[k]
wheel_order[2][numeric2] = wheel_order[2][k]
del wheel_order[2][k]
for k,v in reflector.iteritems():
numeric = conversion_map[v]
reflector[k] = numeric
numeric2 = conversion_map[k]
reflector[numeric2] = reflector[k]
del reflector[k]
first_rotor = wheel_order[0]
second_rotor = wheel_order[1]
third_rotor = wheel_order[2]
STEP 5. Define and load the functions for making the substitutions across rotors, reflector board, and plug board.
def rotor_substitution(pt_letter,wheel_order):
first_rotor,second_rotor,third_rotor = wheel_order
#get first move:
first_mv = first_rotor[pt_letter]
#get second move:
second_mv = second_rotor[first_mv]
#get third move:
third_mv = third_rotor[second_mv]
#get reflector move
reflector_mv = reflector[third_mv]
#first reverse move
for k,v in third_rotor.iteritems():
if v == reflector_mv:
first_mv_rev = k
#second reverse move
for k,v in second_rotor.iteritems():
if v == first_mv_rev:
second_mv_rev = k
#third reverse move and first substitution
for k,v in first_rotor.iteritems():
if v == second_mv_rev:
cipher_text_letter = k
return cipher_text_letter
def plug_board_encrypt(cipher_text_letter1):
if cipher_text_letter1 in plug_board_list:
cipher_text_letter2 = plug_board[cipher_text_letter1]
return cipher_text_letter2
elif cipher_text_letter1 in plug_board_list_rev:
cipher_text_letter2 = plug_board_rev[cipher_text_letter1]
return cipher_text_letter2
else:
return cipher_text_letter1
def rotor_step(rotor):
rotor_list = []
for k,v in rotor.iteritems():
rotor_list.append(v)
step = rotor_list[0]
rotor_list.remove(step)
rotor_list.append(step)
i = 0
for k,v in first_rotor.iteritems():
rotor[k] = rotor_list[i]
i += 1
return rotor
STEP 6. To encipher:
plaintext = 'Hello World!'
plaintext = plaintext.upper()
plaintext = plaintext.replace("!","")
plaintext = plaintext.replace(".","")
plaintext = plaintext.replace(",","")
plaintext = plaintext.replace("?","")
plaintext = plaintext.replace(" ","")
plaintext = [letter for letter in plaintext]
ciphertext = ''
index = 0
for pt_letter in plaintext:
cipher_text_letter1 = rotor_substitution(pt_letter,wheel_order)
cipher_text_letter2 = plug_board_encrypt(cipher_text_letter1)
ciphertext = ciphertext + cipher_text_letter2
index += 1
first_rotor,second_rotor,third_rotor = wheel_order
first_rotor = rotor_step(first_rotor)
if index%25==0:
second_rotor = rotor_step(second_rotor)
if index%625==0:
third_rotor = rotor_step(third_rotor)
wheel_order = first_rotor,second_rotor,third_rotor
ciphertext_spread = ''
index = 1
for letter in ciphertext:
ciphertext_spread = ciphertext_spread+letter
if index%5==0:
ciphertext_spread = ciphertext_spread+' '
index+=1
print "enigma ciphertext is: ",ciphertext_spread
gives:
enigma ciphertext is: EHQHO VPAKI
STEP 7. To decipher. RESET THE ROTOR TO THE INITIAL SETTINGS: RERUN STEPS NO. 1 to 4 INCLUSIVE, then run the code below.
ciphertext = 'EHQHO VPAKI'
ciphertext = ciphertext.replace(" ","")
ciphertext = [letter for letter in ciphertext]
plaintext = ''
index = 0
for ct_letter in ciphertext:
plain_text_letter1 = plug_board_encrypt(ct_letter)
plain_text_letter2 = rotor_substitution(plain_text_letter1,wheel_order)
plaintext = plaintext + plain_text_letter2
index += 1
first_rotor,second_rotor,third_rotor = wheel_order
first_rotor = rotor_step(first_rotor)
if index%25==0:
second_rotor = rotor_step(second_rotor)
if index%625==0:
third_rotor = rotor_step(third_rotor)
wheel_order = first_rotor,second_rotor,third_rotor
print "plaintext is: ",plaintext
plaintext is: HELLOWORLD