After a visit to Bletchley Park in 2012, I got the urge to write an Enigma emulator.
There are many excellent sources of Enigma information on the net. The wikipedia pages were very useful. Though none of the mentioned emulators were useful to me. Either they only ran on Windows, or didn't fully emulate the machine. Of course I've since found many other sources of Enigma information and at least one quite functional emulator.
Regardless, I was interested in writing this emulator, to confirm my understanding of how the machine worked.
I chose to write in Python because it is highly portable, and emulating a machine screamed for an object oriented approach. The end result is reasonably compact:
$ wc -l enigma/*py 208 enigma/enigma.py 65 enigma/plugboard.py 253 enigma/rotor.py 526 total $
As can be seen above the rotor is the most complex component, and certainly was the bulk of the effort, though the initial implementation was only 100 lines. It was also the obvious starting point.
My initial design was very simple, each rotor instance, had a transform - essentially just an array of letters of the alphabet in the correct order for each rotor (per the wikipedia rotor page) and one or more turnover positions (when the next rotor is caused to rotate).
Apart from the transform, each rotor had to track its position (what letter is being displayed), and the offset of the transform from the alphabet ring (default being 0). Each rotor also has to know the next and previous rotors, so they can cause the next rotor to rotate when needed, and can invoke its transform.
The reflector is just another rotor instance, that does not rotate and triggers the reverse transform.
Run by itself rotor.py serves as a simple unit-test.
An extract from pydoc:
class rotor | Methods defined here: | | __init__(self, name, conf={}, offset=0, previous=None, next=None, debug=0) | create rotor instance using transform and turnover points from conf | | Many rotor based cipher machines were in use at various times. | We want to be able to emulate any of them. | Of course that requires knowing the rotor details. | | __str__(self) | | display(self) | indicate the letter that would be visible for this rotor. | The request is passed on to the next rotor first. | | rotate(self) | rotate this rotor one step. | Check the turnover notches (if any) and call next rotors | rotate method if needed. | Only the 3 right most rotors step. | The 2nd rotor can double step. | | set_position(self, position) | initialize the position of a rotor | This is how the session key is set. | | transform(self, c, backwards=False) | Transform c according to this rotor's wiring. | Pass on to previous or next rotor based on value of backwards. | If we are the reflector we set backwards True. | DATA Rotors = {'A': {'transform': 'EJMZALYXVBWFCRQUONTSPIKHGD', 'turnover':...
The Rotors dictionary makes it trivial to lookup a rotor, and pass the dictionary value to the constructor.
Although the rotor definitions include those for the real Enigma machine, the implementation is not limited and can handle rotors which have more than just upper case letters, any number of turnover notches and so on.
The plugboard added greatly to the strength of the machine. It is much simpler to implement in software:
class plugboard | Methods defined here: | | __init__(self, pairs=[], debug=0) | create a bi-directional mapping for each pair of letters | | transform(self, c) | replace c with its pair or leave as is
The enigma class itself is quite simple:
DESCRIPTION Most of the complexity is in the rotor class. The plugboard is a simple bi-directional transformation. By default we emulate a standard 3 rotor machine, but can also emulate a 4 or more rotor machine. By using the 'thin B' reflector and 'Beta' rotor in the 'A' position, we can emulate a 4 rotor machine emulating a 3 rotor machine ;-) CLASSES enigma class enigma | Methods defined here: | | __init__(self, rotors=[], plugs=[], debug=0) | create an Enigma machine using the supplied rotors and plug pairs | | cipher(self, str) | process a string of input and output in 4 letter groups | | process(self, c) | Each input char is first transformed by the pluggboard, | then the right most rotor (after stepping), which in turn invokes | the other rotors forwards and backwards. | Finally the plugboard has a final chance to transform the result | from the rotors. | | set_key(self, key) | Set each rotor to its initial position
Verifying that we produce correct results is obviously important. Fortunately there are a number of sites which provide useful examples.
Tony Sale's worked example was very useful for verifying basic operation. Unfortunately his simulator for the more complex examples just didn't work with any browser I could find (and the site appears to be unmaintained at this point).
Later, the DIY Enigma Machine was useful for verifying behavior with more interesting initial positions etc.
But my original concept for handling ring offsets (rotate the transform), just didn't work. I tried several variations, but none of them worked correctly.
I knew they didn't work since neither the simple examples on wikipedia nor Tony Sales examples that involved ring offsets produced the expected results.
Finally I came across Mike Koss's pages - refered to from DIY Enigma Machine and found his enigma-sim simulator (in javascript), which accurately emulates a 3 rotor machine.
Ah! rather than represent the transforms as letter substitutions, Mike represented them as letter shifts (eg. rather than A->E, you add 4 to what ever letter you came in with). This is actually a better representation of what the wiring in a rotor does, and not only handled ring offsets correctly, it also simplified the transform process in general. Using that transform my emulator correctly handled all the examples I could find.
Here's a cool example:
echo HELLOXWORLD | ./enigma.py -R I,V,II -O 1,2,3 -P AE,IO,UW -K FOO - IDJA TJCH ABZ echo IDJA TJCH ABZ | ./enigma.py -R Beta,I,V,II -O 0,1,2,3 -P AE,IO,UW -K AFOO - HELL OXWO RLD
That is encrypting a message with a 3 rotor machine, and decrypting it with a 4 rotor machine in the 3 rotor setup (4th rotor in A position). When there are more than 3 rotors it defaults to the thin B reflector which was standard on the 4 rotor machines.
You can get various levels of debug output, compare this to Tony's worked example:
$ ./enigma.py -R I,II,III -K AAZ -d G Type | A B C D E F G H I J K L M N O P Q R S T U V W X Y Z | Turnover B | Y R U H Q S L D P X N G O K M I E B F Z C W V J A T | [] (0) I | 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 | [] (0) II | 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 | [4] (0) III | 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 | [21] (0) 3: position A 0 2: position A 0 1: position Z 25 1: rotate -> 0 [A] 1: G -> C 2: C -> D 3: D -> F R: position A 0 R: F -> S 3: S -> S 2: S -> E 1: E -> P AAA G -> P P $
The AAA represents what would be displayed by the rotors. If we bump the debug level a notch we see more info about the transforms:
1: G -> C (i = 6, shift = 22, position = 0, offset = 0) 2: C -> D (i = 2, shift = 1, position = 0, offset = 0) 3: D -> F (i = 3, shift = 2, position = 0, offset = 0) R: position A 0 R: F -> S (i = 5, shift = 13, position = 0, offset = 0) 3: S -> S (i = 18, shift = 0, position = 0, offset = 0) 2: S -> E (i = 18, shift = 12, position = 0, offset = 0) 1: E -> P (i = 4, shift = 11, position = 0, offset = 0)
where i is the index of the incomming letter, shift is the result of looking up i + position - offset in the transform map.
And to wrap up, here is the 4 rotor (in 3 rotor mode), doing the same thing:
$ ./enigma.py -R Beta,I,II,III -K AAAZ -d G Type | A B C D E F G H I J K L M N O P Q R S T U V W X Y Z | Turnover thin B | E N K Q A U Y W J I C O P B L M D X Z V F T H R G S | [] (0) Beta | L E Y J V C N I X W P B Q M D R T A K Z G F U H O S | [] (0) I | 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 | [] (0) II | 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 | [4] (0) III | 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 | [21] (0) 4: position A 0 3: position A 0 2: position A 0 1: position Z 25 1: rotate -> 0 [A] 1: G -> C 2: C -> D 3: D -> F 4: F -> C R: position A 0 R: C -> K 4: K -> S 3: S -> S 2: S -> E 1: E -> P AAAA G -> P P
Note how with the combination of Beta as 4th rotor and thin B reflector, the trasform for the 4th rotor through the reflector and back out the 4th rotor is equivalent to the normal B reflector (F -> S).
You can download the emulator from http://www.crufty.net/ftp/pub/sjg/enigma-py.zip
There were many rotor based cipher machines in use during the Enigma era.
Of particular interest here is the British TypeX which was a teletype machine with a rotor cage derrived from the commercial Enigma. It was used throughout WWII and beyond.
The Germans captured some at Dunkirk, recognized it as an Enigma clone with more rotors, and apparently never made a serious effort to break it.
The TypeX could be configured to emulate an Enigma machine, and indeed this is what was used at Bletchley Park to decode traffic once the settings had been found.
Unfortunately I cannot find any documentation detailing the rotors, otherwise it would be interesting to add a class to emulate it.
The US ECM Mark II would also be interesting. The Combined Cipher Machine (CCM) allowed ECM Mark II and TypeX to interoperate.
Author: | sjg@crufty.net /* imagine something very witty here */ |
---|