Enigma Cipher¶
| GitHub Repo | Main Language | Status |
|---|---|---|
| Enigma Cipher | Finished |
The Enigma Machine is a very well known cipher that was used in WWII. Its purpose was to serve as a bidirectional message cipher (encoding and decoding) with a specific configuration.
Motivation¶
The project displayed here had the simple goal of bringing this ciphering functionality with an OOP structure and defining a very modular Python package. Along with the package creation, the project contains proper documentation for every module.
Important
At last, the whole project was coded without following any guide nor tutorial. All required information was obtained by reading and understanding about the authentic enigma machine.
Project Road¶
The enigma-cipher Python package differs from the others in its modularity.
All other projects seem to recreate the exact enigma machine, while this project takes how it worked and expands it to a very custom setup.
Understanding the machine¶
The key point to understand the ciphering is that every pair of letters is always paired at a certain state. Assuming a frozen state, pressing any key will always return its paired key. Considering the first state of the next image, it can be seen that 'A' will always return 'G' (for this configuration) and 'G' will always return 'A'. This is the main reason why the tool works as both encoder and decoder for any message, as for decoding it the machine just needs to be at the same initial state and provide as input the encoded message.
The machine is then composed by three unique parts:
- The PlugBoard, which defines an initial mapping among letters that affects at the first input. Thus, if 'A' if connected to 'F', when the key 'A' is pressed the input received by the first rotor is 'F'. If a letter is not connected to any other, and it is pressed, the same letter is provided as the input for the first rotor.
- The Rotors, which provide an N-shift letter ciphering, where N is the rotor index position from 0 to 25 (all letters). When N=0, if the letter 'A' is provided the rotor returns 'A', but if N=5 the same 'A' input provides 'F' to the next step.
- The Reflector, which is analogous to the plugboard but with the difference that here all letters are mapped to each other, so no letter can be without any pair. This piece was also always static and its configuration could not be changed.
The machine as code¶
After reading the description of the mechanical components, it is clear that every component translates to some kind of Python mapping. It is also important to note that these mappings are not the same for each component:
PlugBoard: Mapping from a letter to another. This is the only mapping that can leave letters without any mapping. For example, a mapping{"a": "c", "b": "h"}is already a complete plugboard configuration.Rotors: N-shift mapping, easily implementable usingstring.ascii_lowercase. The class must also have an internal state that updates the N-shift in 1 every time a letter is typed.Reflector: Full key-mapping, and the only mapping that is static.
When implementing the machine as code, the only complication is that each letter-connection must be analyzed twice per component. In other words, the output is generated by processing and input forward to the reflector and back (through a different path) to the plugboard, with this signal mapped through all the components.
In this ciphering operation back- and forward, the order matters while ciphering a letter through a component, as each component can return a different result for the same input. The strategy then to implement it in Python is:
- Make each component a single Python class, all with the method
cipher_character(c: str) -> str. Rotorsare the only element that is affected by a forwards (+ N-shift) or backwards (- N-shift) ciphering.- Encapsulate all final components instances in a new class (
EnigmaMachine), in charge to compute the ciphering forwards and backwards. - Only when a key is fully cipher, then the state of the rotors can change. This state works updating the most-right rotor in 1, only updating its immediate left rotor when itself made a full rotation.
What makes my code different?¶
It is important to note the Enigma Machine is very well known, and anyone that researches can fully create their own version. However, I find important to deviate from whatever exist there.
- Ciphering numbers and symbols: The original machine can only encode letters. My package allows also to cipher numbers and symbols when creating the configuration at each component.
- Number of rotors: Historically, the machine had only 3 rotors. I prepared the
EnigmaMachineclass to be able to work with any number of rotors. This was just a small goal I set, as it actually doesn't make the ciphering any more secure. - Reflector configuration: As mentioned before, each machine had a reflector which had a fixed mapping and could not be modified. This reflector also had to be the same in all machines to work. My package allows any user to configure any full mapping at the reflector, even with a random configuration.
- Easy configuration import/export: At last, the machine allows to export a configuration as a JSON file, or even initialize it from one. This is only needed for those cases that multiple users want to work to ciphering texts with the same configuration.