The Imitation Game The Imitation Game is an amazing movie. I urge anyone who is interested in computer science, cryptology, or good movies in general to watch this. Glowing reviews aside, the movie is about the Enigma machine, a German-made machine used in World War II to encrypt and decrypt messages sent between German military. It was thought to be uncrackable.

The remarkable thing about the Enigma machine is that it has 158,962,555,217,826,360,000 possible combinations. That’s one hundred fifty-eight quintillion, nine hundred sixty-two quadrillion, five hundred fifty-five trillion, two hundred seventeen billion, eight hundred twenty-six million, three hundred sixty thousand. Trying to crack the Enigma machine by hand is virtually impossible unless you get extremely lucky. How does this machine have such an absurd number of possible combinations?

Enigma machine

This is what an Enigma machine looks like. An Enigma machine has 3 different parts that control the scrambling (encrypting) of your message: a plugboard, three rotors, and a reflector.

Plugboard: The plugboard is basically a switchboard where you physically plug in 10 wires that connect two letters as a pair. When you type a letter, the letter goes through the plugboard, and comes out as the letter it is physically connected to. For example, if Q is plugged to A, when Q is typed, A is returned and vice versa. It will return as itself if it doesn’t to another letter. After the letter get swapped, the resulting letter gets sent to the rotors.

Rotors: Rotors are the gears that are on the top of the machine. There are five rotors in which three are selected and placed into the machine. These three rotors have offsets from 0-25, representing each letter of the alphabet. Each respective rotor placed can be respectively identified as the fast, medium, or slow moving rotor. Typing a letter will rotate the gear by one, so if the keys were mapped A => B, B => C, C => D and so forth, the new mapping would be B => B, C =>C, D => D, then C => B, D => C, E => D. Each rotor has a notch so after a full rotation, that notch triggers the rotation of the rotor to the left of it. If all notches are aligned, the fast rotor will rotate 26 times, which rotates the medium rotor once. After the medium rotor rotates 26 times, the slow rotor will rotate once. The scrambled letter then goes to the reflector.

Reflector: The reflector also has its own mapping of the alphabet. After the letter from the rotor enters the reflector, it swaps with its mapping, then sends that letter back all the way from the reflector, through the rotors (backwards), then through the plugboard. The Engima machine has a light bulb above each key that will light up when a key is sent back, signifying your encrypted or decrypted letter.

Here’s the math for the possible combinations: Rotors: 5 * 4 * 3 = 60 Starting positions: 26 * 26 * 26 = 17,576 Plugboard: 26!/(6!10!(2^10)) = 150,738,274,937,250

150,738,274,937,250 * 17,576 * 60 = 158,962,555,217,826,360,000 possible combinations

How does the receiver know which settings to use to decrypt a message? A letter was distributed at the start of each month with the configurations to use for the Enigma machine.


Creating the Enigma machine in Ruby

Technology has significantly improved since the Engima machine was first used in the1920s. Now we can simulate the Enigma machine quite easily. Inspired by the movie, I decided to take a stab at making my own Enigma machine. This is my in-progress work.

Creating a randomized mapping of the alphabet to different letters is extremely easy.

  def self.generate
    alphabet = ("A".."Z").to_a
    alphabet.zip(alphabet.shuffle).to_h
  end

This results in the following hash:

{"A"=>"F",
 "B"=>"W",
 "C"=>"T",
 "D"=>"R",
 "E"=>"X",
 "F"=>"V",
 "G"=>"S",
 "H"=>"K",
 "I"=>"O",
 "J"=>"P",
 "K"=>"C",
 "L"=>"Z",
 "M"=>"Q",
 "N"=>"M",
 "O"=>"Y",
 "P"=>"N",
 "Q"=>"A",
 "R"=>"D",
 "S"=>"L",
 "T"=>"G",
 "U"=>"J",
 "V"=>"H",
 "W"=>"U",
 "X"=>"B",
 "Y"=>"E",
 "Z"=>"I"}

The only flaw in this method is the possibility of mapping a letter to itself, which can be fixed with a recursive shuffle. This is good enough to be our rotor. The mechanics of the rotate method looks like this:

  def rotate
    self.rotor = rotor.map { |k, v| [k == "Z" ? "A" : k.next, v] }.to_h
    increase_offset
    self
  end

Bam. We have ourselves a rotor. The plugboard and reflector are a little bit trickier, but not tricky at all.

Plugboard: We want to have only 10 plugs in our plugboard so we pick out the first 10 in a generated array. After we pick 10, we merge the associates with the inverse of itself so for example we have both A => B and B => A in our hash.

  def self.generate
    alphabet = ("A".."Z").to_a
    first_plugs = ("A".."Z").to_a.shuffle.first(10)
    second_plugs = (alphabet - first_plugs).first(10).shuffle
    plugs = first_plugs.zip(second_plugs).to_h
    plugs.merge(plugs.invert)
  end

Reflector: Same concept as the plugboard, but we want to map each letter to its inverse instead of only 10.

  def self.generate
    shuffled_alphabet = ("A".."Z").to_a.shuffle
    mapped = shuffled_alphabet.first(13).zip(shuffled_alphabet.last(13)).to_h
    mapped.merge(mapped.invert)
  end

This is all the parts of the entire Enigma machine written in just a few lines of Ruby code. The basis of my code is heavily influenced by Understanding the Enigma machine with 30 lines of Ruby. I’ve added in files that represent the physical parts of the Enigma machine and simulated being able to pick the different components so a message can be encrypted and decrypted between friends who have the same parts. Same as how the original Enigma machine worked. It was a fun project to work on, and I plan on completing the Bombe machine, a machine that decrypts Enigma encoded messages, in the near future.