Found this script may be useful.
PHP Code:
""" enigma.py
"""
import operator
from string import ascii_uppercase as UPPER
from copy import deepcopy
from permutations import Permutation,cycleform,permform
def char2int(key):
try:
c = key.upper()
return UPPER.index(c)
except:
return key
class Rotor(Permutation):
def __init__(self,perm,ringsetting='A',key='A',notches=()):
Permutation.__init__(self,perm)
self.notches = notches
self.setRing(ringsetting)
self.setKey(key)
def setRing(self,A):
r = char2int(A)
cycles = [[(x+r) % 26 for x in cycle] for cycle in self.C]
perm = permform(cycles)
self.P = perm
self.C = cycleform(perm)
def setKey(self,A):
k = char2int(A)
cycles = [[(x-k) % 26 for x in cycle] for cycle in self.C]
perm = permform(cycles)
self.P = perm
self.C = cycleform(perm)
self.key = UPPER[k]
def step(self):
cycles = [[(x-1) % 26 for x in cycle] for cycle in self.C]
perm = permform(cycles)
self.P = perm
self.C = cycleform(perm)
k = char2int(self.key)
k = (k+1) % 26
self.key = UPPER[k]
def trigger(self):
return self.key in self.notches
def rotor(strng):
return Permutation(tuple(strng.lower()))
# The rotors
I = Rotor("EKMFLGDQVZNTOWYHXUSPAIBRCJ",notches=("Q"))
II = Rotor("AJDKSIRUXBLHWTMCQGZNPYFVOE",notches=("E"))
III = Rotor("BDFHJLCPRTXVZNYEIWGAKMUSQO",notches=("V"))
IV = Rotor("ESOVPZJAYQUIRHXLNFTGKDCMWB",notches=("J"))
V = Rotor("VZBRGITYUPSDNHLXAWMJQO****",notches=("Z"))
VI = Rotor("JPGVOUMFYQBENHZRDKASXLICTW",notches=("Z","M"))
VII = Rotor("NZJHGRCXMYSWBOUFAIVLPEKQDT",notches=("Z","M"))
VIII = Rotor("FKQHTLXOCBJSPDZRAMEWNIUYGV",notches=("Z","M"))
# Used only in Model M-4 with thinB and thinC reflectors
beta = Rotor("LEYJVCNIXWPBQMDRTAKZGFUHOS")
gamma = Rotor("FSOKANUERHMBTIYCWLQPZXVGJD")
# The reflectors
B = Rotor("YRUHQSLDPXNGOKMIEBFZCWVJAT")
C = Rotor("FVPJIAOYEDRZXWGCTKUQSBNMHL")
# The reflectors used in Model M-4 with beta and gamma rotors.
thinB = Rotor("ENKQAUYWJICOPBLMDXZVFTHRGS")
thinC = Rotor("RDOBJNTKVEHMLFCWZAXGYIPSUQ")
# The cyclic permutation and its inverse
rho = Permutation("BCDEFGHIJKLMNOPQRSTUVWXYZA")
identity = Permutation("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
# The 'QWERTZU' in military and civilian types. We
# have the 'QWERTZU' act on the left so we use the
# inverse of the input permutation.
military = Permutation("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
civilian = Permutation("QWERTZUIOASDFGHJKPYXCVBNML")
# This class still needs to be checked to see if it
# performs correctly.
class Enigma(object):
def __init__(self,
rotorList = (I,II,III),
reflector = B,
ringSettings = (),
stecker = identity,
qwertzu = military):
""" The rotor (wheel) list should be given from slowest to fastest:
U, W_L, W_M, W_R. The ring settings default to 'AA...', the
stecker and 'qwertzu' both default to the identity. The key
settings are made after the machine is initialized.
"""
self.qwertzu = qwertzu
self.rotors = [deepcopy(R) for R in rotorList]
self.rotors.insert(0,deepcopy(reflector))
self.nR = len(self.rotors)
self.__setRings(ringSettings)
self.setStecker(stecker)
def __repr__(self):
return repr(self.permutation)
def __str__(self):
return str(self.permutation)
def __call__(self,text):
return "".join(map(self.encipher,text))
def setStecker(self,stecker):
try:
self.SQ = stecker * self.qwertzu
except:
self.SQ = Permutation(stecker) * self.qwertzu
self.setPermutation()
def __setRings(self,ringSettings):
# Convert ring setting letters to numbers.
ringSettings = map(char2int,ringSettings)
# All ring settings default to 'A'.
nS = len(ringSettings)
ringSettings = (0,)*(self.nR - nS) + tuple(ringSettings)
for k,R in enumerate(self.rotors):
R.setRing(ringSettings[k])
def setKeys(self,keySettings):
# Convert key setting letters to numbers.
keySettings = map(char2int,keySettings)
# All key settings default to 'A'.
nK = len(keySettings)
keySettings = (0,)*(self.nR - nK) + tuple(keySettings)
for k,R in enumerate(self.rotors):
R.setKey(keySettings[k])
self.setPermutation()
def setPermutation(self):
self.permutation = (self.SQ >> reduce(operator.lshift,self.rotors))
def step(self):
if self.rotors[-2].trigger():
motion = (1,1,1)
elif self.rotors[-1].trigger():
motion = (0,1,1)
else:
motion = (0,0,1)
for i in range(3):
if motion[i]:
self.rotors[i-3].step()
self.setPermutation()
def encipher(self,c):
self.step()
return self.permutation.encipher(c)