Enigma-E : Encryption Inspired by History
376 Views, 4 Favorites, 0 Comments
Enigma-E : Encryption Inspired by History
Image: Enigma 4-rotor at IMWWII.agr.jpg, ArnoldReinhold via Wikimedia Commons, under: Creative Commons Attribution-Share Alike 4.0, File:Enigma 4-rotor at IMWWII.agr.jpg - Wikimedia Commons
The Enigma machine was the pinnacle of cryptographic hardware in the early 20th century — a feat of electrical engineering whose cipher remained unbroken for over a decade. As far as the Enigma is concerned, it all traced back to the reflector component (which shall be explained later) which didn't allow for the encryption of the letter to itself which helped cryptanalysts to eliminate several possibilities and finally break it at Bletchley Park in 1940.
Here is where I got the idea of implementing its working using C++ as it not only is fast but also helps in low-level control.
Some of the topics covered in the instructable are:
- Hardware functionality of the original machine
- The issue with the reflector, and its elimination
- Deduced pseudocode for our project
Supplies
As mentioned, this project is completely based on software, so no need of any hardware.
Software:
- C++ compiler, any standard C++17 compiler works, I used g++ (part of GCC)
- VS Code as the recommended IDE, with the C/C++ extension by Microsoft
- As an alternative for people who don't want to install anything — JDoodle online IDE and compiler
Important Links (for the software):
- VS Code download: https://code.visualstudio.com/download
- JDoodle C++ compiler: https://www.jdoodle.com/online-compiler-c++
Knowledge prerequisites:
- Basic understanding of C++, like variables, arrays, loops, functions etc.
- No cryptography background needed — everything is explained from scratch
Command to run your code: (g++ -std=c++17 -o enigmaE enigmaE.cpp)
One recommendation for those who want to dive into the hardware and the intricate details of the actual Enigma: How did the Enigma Machine work? by Jared Owen, You Tube.
Hardware Functionality of the Enigma
To interact with the user the hardware of the Enigma machine features a keyboard which is like modern day keyboard in the functionality to send high signal from the installed battery to the corresponding letter and light bulb to show the final encrypted output for the input letter.
The three main parts over which the whole letter shifting process of Enigma was based upon was:
- Plugboard
- Rotors (x3)
- Reflector
- Plugboard -
This was the very first place where the switching would take place, and as shown in the image, not all but exactly 20 letters were paired up, leaving 6 letters unpaired effectively keeping them unchanged after they were selected on the keyboard, this was a mathematical and strategic choice as this allows for maximizing the number of permutations of possible pairs and also adding to the ambiguity if a letter is paired or not;
- Rotors -
The fundamental functioning of the rotor is same as the plugboard; to interchange one letter with another but here, two separate discs are used to show the mapping in the image and each letter as the input counted as a high signal is mapped to some other letter on the other disc which may (not) be differing from the input letter which is set high (in digital electronics logical 1), note that all the three rotors different internal circuit leading to distinct mapping from one another. Apart from this each time a key was released the rotors would rotate (out of the three, one would rotate every time, one would rotate once every time the former ones complete 26 rotations and the last one would rotate when the 2nd rotor would complete 26 rotations) leading to distinct metal pins coming to contact relative to each other and different mapping for the next letter even if the input letter is same;
- Reflector -
Though being similar to the above in functioning however it came with one critical limitation, as shown in the diagram in the related image that the exchange process happened on the same disc which caused each letter to be compulsorily mapped to some different letter which would be set to high.
One-cycle signal path :
Keypress (Eg; input A)
↓
Plugboard (Eg; A -> C; i.e., A switched to C)
↓
Rotor 1 (Eg; C -> C)
↓
Rotor 2 (Eg; C -> G)
↓
Rotor 3 (Eg; G -> P)
↓
Reflector (Eg; P -> A)
↓
Rotor 3 (Eg; A -> Z)
↓
Rotor 2 (Eg; Z -> Q)
↓
Rotor 1 (Eg; Q -> R)
↓
Plugboard (Eg; No shift from R)
↓
The bulb R lights up
***The same is also illustrated using the single-input circuit image, in which the top-left device represents the reflector, the connected devices on the top-right represent the rotors, the bottom-most section is the plugboard, above which is the keyboard, and above that is the light board.
The Flaw: Why the Reflector Was a Problem
The Enigma’s greatest weakness was the reflector, a component that sent the electrical signal back through the rotors. This design ensured the machine was reciprocal (meaning the machine could be used to encrypt as well as decrypt the message with same settings; i.e., same rotor positions and plugboard combinations) but created a fatal flaw: no letter could ever encrypt to itself.
How can this be exploited?
Via Crib-Dragging:
For a word which was surely known to exist in daily messages; eg, hail; then that word was dragged through the text and whichever places the letters matched in the cipher text and crib text, all such positions of rotors and plugboard combinations were immediately eliminated.
Secondarily, as it was reciprocal in nature, that meant that if cryptanalyst was sure about A mapping to G for some settings that also revealed the required combinations for G mapping to A
Hence, we would be removing reflector entirely in the pseudocode to remove both the issues:
- no self mapping
- symmetric mapping
Selectively Inheriting and Developing Enigma Design
Some of design changes and their need are:
- Eliminate the reflector - based on arguments of the previous step;
- Have 6 rotors in place of 3 - if not done then we would have to pass the signal or the selected letter directly through the plugboard after it passes through the 3 rotors because of absence of reflector which would rather become a drawback of removing reflector as it reduced the number of shifts over the letter, hence to keep the number of shifts same we have to add another 3 rotors, additionally adding 3 totally different rotors allows us to have even more jumbled mappings;
- Position update of the rotors - as in the Enigma, the updates followed a pattern of updating every time the previous rotor completes 26 rotations, hence if seen with respect to the first rotor we would be updating:
- first rotor every time
- second rotor every 26 times
- third rotor every 576 times
- fourth rotor every 17576 times
- fifth rotor every 456976 times
- sixth rotor every 11881376 times
Rest all design of the plugboard would be kept same including the number of pairs as its mathematically already the best choice.
Finally, our design choice grants us advantage in,
- No crib-dragging attacks
- No symmetric or reciprocal damages
- Added mapping advantage of 3 totally different rotors
The Plugboard: Design & Implementation
Its functioning won't be different from that of the actual Enigma, so it would be just statically swapping the letters, once before serving the input through the keyboard and once at the end just before displaying the encrypted/decrypted letter on the light board.
For the code, we would be using string array of dimension 2 rows * 10 columns (pbc[2][10]), where each of the column stores the letter pair, hence whenever any letter is passed through the plugboard function it checks through all the 20 values and if it matches with one of the values, then the other element in the column is the output letter else the letter is kept unchanged.
We also know that those mappings could be changed and updated, hence, we would be taking input from the user and those entered pairs of distinct letters which didn't occur in any of the previous pairs would be stored as the new entry. This requires us to use nested conditional statements to check multiple conditions such as, if the entered string is of length 1, its ASCII value after converting the char value to int lies between that of capital letters 65-90 (inclusive) and the letter isn't a part of any previous pairs and is checked by nested loops to check for each of the column in pbc array.
Here I said capital letters, however user isn't required to enter a capital letter as input, so we use a standard() function which changes the letter to upper case and leaves all other characters unchanged, again via if-else condition which would subtract 32 from the ascii value of the char-(character data type in C++) if it's in the range (97-122).
Applying the above the pseudo-code:
- PBC (plugboard combinations) array -
- Plugboard shift code -
- Plugboard combinations entry -
The Rotors: Design & Implementation
In our implementation, we have the working of the rotor same as that of Enigma, however we would be increasing the number of rotors with distinct mapping to 6, so each one of them would be changing one letter to the other sequentially.
Similar to the plugboard we would be having arrays which would storing the keys and their corresponding values hence, we would use a 6 depth * 2 rows * 26 columns array (rotor[6][2][26]) where each depth would be representing a rotor's mapping and each of the column would be representing the mapping of letter as the input taken as the first row element to the corresponding second row element. Hence, for ease of mapping the first row's elements are taken as A, B, ..., Z and second row for each depth or rotor is:
- Q, M, A, T, Z, L, E, N, U, D, Y, H, K, B, W, O, J, R, C, G, F, X, I, S, P, V
- B, X, E, U, N, P, S, Y, C, K, G, T, O, H, Z, R, D, W, L, F, Q, I, J, A, V, M
- J, T, E, M, B, I, Z, V, F, C, L, X, P, U, D, S, G, H, Y, A, K, R, Q, O, W, N
- C, W, H, O, E, R, X, B, L, G, I, A, T, F, N, Z, M, Y, J, U, D, K, V, S, Q, P
- V, M, U, K, T, Y, H, P, E, J, Z, G, A, O, S, B, C, F, W, I, D, N, L, Q, X, R
- F, Y, U, C, E, T, H, X, B, R, W, I, K, M, L, Z, D, J, A, V, G, S, P, Q, N, O
However, unlike the plugboard rotors aren't static and their updating has been described by rotation in the actual Enigma, so to replicate that in our code we use basics of modular addition, which is nothing but starting from some base count let's say 10 and when talking about the second rotor we know it would be updating every 26 times so we add keep adding 1 (for each letter encrypted) to the base count (10) until its 26 and when it's so, %26 makes it zero and we use this repetitive pattern to update all 6 rotors.
Here, k is the column where the first-row element and the input letter are same and as said rotorS indicates the base count which would be incremented by 1 for the first rotor for each letter encrypted, for the second rotor it would be incremented by 1 when 26 letters are encrypted and so on (note that 26^(rotor no - 1) is the threshold for updation). The logic behind this is;
With the threshold being:
- 1 for rotor 1
- 26 for rotor 2
- 576 for rotor 3
- 17576 for rotor 4
- 456976 for rotor 5
- 11881376 for rotor 6
One very important thing to note is that we don't have symmetry in the code while doing that, so we lose reciprocal property of Enigma; hence for decryption we need to define a separate function which instead of switching letters for given rotor shifts (rotorS) from rotor 1 to 6 would do it from rotor 6 to 1 (reverse) and also we need to search the row 2 as keys and map them to row 1 in decryption; hence both share the same rotor array and the initial shift of the rotor has to be specified for both.
- Getting rotor shifts:
- rotor based encrypt:
- rotor based decrypt:
***Note the difference in direction of fetching indices of iteration over rotor array from 0 to 5 in rotEncrypt whereas it 5 to 0 in rotDecrypt
Worked Example for (En/De)cryption Flow
Let's take an example case to see how our model Enigma would work after assembling the encryption and decryption modules containing, rotors and plugboard.
When we put 'i' as the input message in encryption mode :
rotor settings: 0,0,0,0,0,0 (for simplicity)
plugboard combinations: A->B, C->D, E->F,.... , I->J, K->L, ..., S->T (for simplicity)
input string - 'i' (chosen for simplicity)
↓ (standard)
I
↓ (plugboard)
J
↓ (rotor 1)
D
↓ (rotor 2)
U
↓ (rotor 3)
K
↓ (rotor 4)
I
↓ (rotor 5)
E
↓ (rotor 6)
E
↓ (plugboard)
F
Hence, the output or the cipher text for the sample input is 'F'.
Terminal :-
Now when we put 'f' in decryption mode:
rotor settings: 0,0,0,0,0,0 (for simplicity)
plugboard combinations: A->B, C->D, E->F,.... , I->J, K->L, ..., S->T (for simplicity)
***Note that same rotor shifts and plugboard shifts are a must for reliable decryption
cipher string - 'F'
↓ (standard) -> no need but for safety
F
↓ (plugboard)
E
↓ (rotor 6)
E
↓ (rotor 5)
I
↓ (rotor 4)
K
↓ (rotor 3)
U
↓ (rotor 2)
D
↓ (rotor 1)
J
↓ (plugboard)
I
↓ (destandardizer)
i
Hence, we get back our input string from the cipher text by the above steps.
Terminal Output :-
YouTube video for reference on worked example: Enigma E
How to Run
Link for my GitHub repo: Enigma-E_files
- If you don't want to compile the code on your side and have Windows device, you can use the .exe file for the purpose
- If you have VS code preinstalled as per instructions or have JDoodle, copy paste the code from the .cpp file or download the repository on your device
- Run the code in JDoodle by pressing on Run button (looks like play button) -> easiest way out
- If in VS Code use the command (after opening the file in VS code): g++ -std=c++17 -o enigmaE enigmaE.cpp ***If you are using the g++ compiler
- Walk through the code as per your own combinations and go into the encryption mode by 'e' and decryption mode by 'd'.
Future Advancements
The current advantages what this model offers over the original Enigma are highlighted while deciding the inherited and our design choices over the current model; as far as possible advancements are concerned, they can be made in:
- Supporting the whole Unicode values or at the nevertheless the ASCII values
- GUI based interface for a modern interface-based workflow and introducing python-based file content reading and passing the .txt data to the code via subprocesses module to directly encrypt the .txt file rather than requiring the terminal
- Secure key exchange protocols for sharing plugboard combinations and initial rotor shifts.
***NOTE: Those additional design choices were not included, as they would have shifted the project's focus heavily toward modern-day cryptography and coding. However, the purpose of the project is to highlight historical design feats in electrical engineering, and including them would have taken it completely out of scope.