Since enough people seemed interested in a status I posted some time ago that I thought, hey, it might be a good idea to do a write up. It'll be short enough that it'll actually end!
This section is just to provide an outline of this series:
- What is the Enigma Machine?
- Why did I choose to implement the Enigma machine?
Before Programming Begins:
- Understanding the theory of the Enigma Machine
- Finding a programming environment
- Programming the features
- Rotor housing
- Plug Board
If you'd like to look at the source code, it's uploaded on GitHub.
A bit of background: What is the Enigma Machine?
During World War II, everyone had their way of encrypting and decrypting messages. The Germans used a modified commercial product that did this called the Enigma Machine. It has a key for every letter (in my case, 26 for the English alphabet). Each key was electrically wired up so that when it was pressed, an electrical connection was made through it, then to a few rotors where it would come out to another key, which would light up a bulb corresponding to that key. So if you pressed A, it would get scrambled into something like D. Since it was electrically connected, you could also do something like swap letters so that the input would get swapped or the output would get swapped. From Wikipedia, here's a basic diagram of how it works (Pressing A results in a D, though it would've resulted in an S if not for the plug board connection in item 8):
Though it wouldn't do much good if pressing A always resulted in a D. To solve this, every time a key is pressed, a rotor advances. In this case, the right most one. And when that makes a full revolution, it advances the next one, and so on. This makes it so that pressing the same letter always results in a different one. A key element in the Enigma machine was the reflector element (item 6). This was required due to how the machine was designed, which introduced a flaw in that a letter cannot encode to itself.
To decode the message, you take the encoded message, set the rotors to same position as when the encoding started, then type in the encoded message. The machine will light up the decoded letter for each encoded one.
In short, the Enigma machine is a rotating substitution cipher. Each combination of rotor positions represents a different substitution cipher that it rotates through automatically. There was also another substitution cipher in the form of the plug board, but this was manually entered and static.
Why did I choose to implement the Enigma machine?
I was thinking of some simple projects to do on the side. While nice complex projects can be fun, they can also be a pain and having something done feels more like a sense of an accomplishment than getting 50% there on a complicated project after dumping hours into it.
The Enigma Machine came up because I figured it'd be a relatively good challenge and yet it's simple in theory. So it shouldn't be hard to debug and verify it works. And also World War II is my favorite time period, with the Enigma having interesting stories around it.
Before Programming Begins
Most successful programming projects, or just any real project, needs a lot of planning and research ahead of time before the work can really begin. Poorly researched aspects can cause hiccups in the future that may not make themselves apparent until a lot of work has already started.
Understanding the Theory of the Enigma Machine
There isn't much point in trying to program something if you don't understand how the system works in general. So step one is to understand how the Enigma Machine works. The most interesting part was the rotors, which aren't really that complex: there are input pins and output pins, and the input pins wire to an arbitrarily picked output pin. So the overall requirements for this system to work is:
The pin mapping of the rotors should be randomly generated. However, this should not be uncontrolled random generation.
- That is, the user needs to input the RNG seed. Otherwise, the usefulness of the program is only good for that instance of the program. Each new instance would have a different randomly generated set of rotors with no way of setting it to what another instance used.
For each rotor, an "input" must map to an "output" such that if you give the rotor an "input" value, it returns an "output" value. But if you give it the "output" value, it returns the "input" value. That is:
- If I give the rotor 1 and it returns 3, if I give the rotor 3, it returns 1.
Each time a rotor is used, depending on its position, it needs to "advance". That is the next time I use the rotor, the mapping needs to be offset for the same input.
- For example: If the letter "A" maps to pin 1 on the rotor, the next time I feed the letter "A" into the rotor, it goes to pin 2 instead.
The plug board has a similar idea, in that it's also a substitution cipher that works in the same way as the rotors, namely it needs the second requirement. However, they behave differently as far as the system is concerned so they need different sets of logic to function. These are:
- The plug board does not automatically advance. i.e., the mapping doesn't change automatically.
- The mapping can change based on the user needs. The rotors are more or less permanently wired. The plug board, as the name implies, has plugs the user can connect wires into and disconnect said wires.
The user-changeable mapping presents a problem, say we have a mapping of A -> B, which means B -> A, and another mapping of C -> D, which means D -> C. What if I want to wire A -> C?
- The question will be answered in the section where I talk about the plug board design.
Then there's the path of how a key press turns into a lit lamp:
- A key press goes to the plug board to be remapped. By default, the letter maps to itself.
- The output of the plug board goes into the input if the first rotor.
- The output of the first rotor goes into the input of the second pin for pin (i.e., rotor 1 outputs pin 2, so it goes into pin 2 of rotor 2)
- Repeat for N-rotors
- The output of the last rotor goes into the reflector, which spits out a value to go back into the nth rotor's "output" side, this spits out something on the "input" side.
- The "input" of the rotor goes into the "output" pin of the previous rotor, and repeat until the "input" of Rotor 1 is given.
- The returned "input" goes into the plug board to be remapped.
- The output of the plug board then spits out the letter.
The key pressing and lamps are merely inputs and outputs. They don't affect the theory of operation of how the Enigma Machine works.
Figuring out What Language/Environment to Use
I wanted this to have a GUI, because eventually I would need to have that keyboard + "light" interface. And because there are components in the Enigma Machine that do independent things and there could be multiples of one of them, I felt a language that supported object-oriented design is best. So these were the requirements for the language and environment I wanted:
- What has good GUI framework support?
- What supports object-oriented design?
- What features of the language makes things like manipulating entries in data structures or creating multiple instances of an object easier?
- What environment is easy to setup?
Out of what I do know:
- Python: Python has a few GUI libraries, but my experience with this is limited. And what experience I do have isn't quite pleasant (to be fair, it was only with Tcl). I'm aware there are frameworks to make this easier, but I didn't want to spend time looking and testing them out.
- C++: Similar issue as I have with Python: I'm aware GUI libraries exist, my experience with them are limited (at least from a fresh start), and I don't want to spend too much time learning this.
- C: While the state of each rotors can be separated and business logic can just take in the state of rotors to work with, this would be hard than I'd like. Plus the issue with finding a GUI framework, though it's likely any C code I'd write would be called from C++ GUIs.
C#: I'm sure there's some way of writing and compiling C# in a bare bones manner, but I use Visual Studio for C# work. And having worked with Visual Studio and C# to quickly write tools for work, I decided to go with this.
- Yes I'm aware Visual Studio has C++ support, but I don't have much experience with it. At least for developing Windows Form apps.
There's also another reason why I went with C#: I know it has a lot of data structures that make my life easier, because they come with a bunch of methods that help do what I want. And it's not just the language that has nice features that I want that's included, but setting up a C# development environment is stupid easy. It's just download and install Visual Studio. If I spent a day just setting up my tools, the project would've likely be dead in the water.
I like to think of myself as a lazy developer. Not in that my code is lazily written (most of the time, anyway), but I don't want to spend all day doing something that feels like it should take 10 minutes. The tools exist to make my job easier. If the tool doesn't appear do that, it's a poor tool.
With the planning phase done, the next entry will go over the programming process and how things were built.