Header-Bar

June 10, 2013

TryThis0ne - Enigma Code Riddle: Solved in C#

As we all know the Enigma machine is any of a family of related Electro-Mechanical Rotor Cipher machines used for the encryption and decryption of secret messages.
Enigma was invented by a German engineer back in the second decade of the last century, right after the 1st World War.
Adopted by military and governments the Enigma became very popular from the early 20's.


But enough history for now.
A very good friend of mine [cp77fk4r] wrote a very nice challenge based on one variant of the Enigma machine.

Here is a quick snapshot of the challenge:


IMAGE I

**The riddle can be found in: www.TryThis0ne.com

Let's see what it says:

"As you can see by the diagram that our spy achieved, there are 3 boards: A, B and C. After each type, board A will move one level up, and board B will move one level down. Board C is a routine and its a reflector in this machine" 
"We got an encrypted key: XRSPVIQOLWY" (10 chars total)
"We need to pull out the original key"

"Hint:"
"As we know, one of the boards was unplugged"

You can solve this one manually, but it will take you a day or two of frustrating finger to finger walk through. So I've decided to solve this 0ne by writing an automated script that will print the path of each letter in each iteration so I can sit back and enjoy looking at my creation as its solving the cipher in less than 1 seconds.

I've chosen to use C# on Visual Studio 2012 Enterprise Edition, but you can use any language and platform you feel comfortable with. 

How did I do it? you'll be amazed to know how easy it is. Let's start.
First thing you can do is look at the blocks A and B. What do you see?
They are the same. So that means ttthhhhaaatttt... right, the dictionary is also the same.
But wait, let's create a routine just to make sure we are correct about how the path from one letter to another looks like.
Let's for example take 'A' where our counter (the boards are moving on each iteration, right? so the first iteration has 0 moves) equals 0.

IMAGE II

So 'A', while counter equals 0, is pointing to 'B' and as you can see we walked through 5 blocks:
1) A
2) B
3) C
4) B backwards
5) A backwards

But A and B are equal, so how many dictionaries do we need? not 5, right.
Take out a pen and a piece of paper and right down your dictionaries.
After you've manually created a dictionary of the A-Z Key:Value it is now time to write some code!

We know that our Key is changing at each block (reminder: our Key is the letter that starts as a cipher and ends at the final step of the Enigma as text). Furthermore, we need to count our iterations in order to calculate the number of moves (up or down) of each block, A and B.

Example:
If our Cipher is "SECRET" so the 2nd iteration is Key='E' and the counter is 1 (cipher[1]). the function A will add 1 to the Key and the function for B will subtract 1 from the Key (simulating the up & down movement).

static int counter = 0;                                          
static char key;                                                  

Next we need to create this static string being typed by the user. You can improve your code later to be dynamic, but for now we will use a simple array to make sure that the Text becomes Cipher and returns safely as the same Text we sent earlier.
in the main() create the following array:

var textFromUser=new[] {'M', 'Y', 'S', 'E', 'C', 'R', 'E', 'T'};   

and another empty array that will later collect each letter's result into one string.

char[] array = new char[20];                                      

There are many ways to create this script, but one method is to create a function for each block.
Let's see how:

1) create a static void <Block name> function that takes a single char from the Cipher as a variable on each call. 
2) your char is the characters located in your static array i.e. MYSECRET.
3) we would like to make sure that the letter (Key) finds its Value according to the dictionary we built earlier.

Creating the function for each block, we have to remember that the blocks are round. This means if I get to the letter 'A' in block B after one iteration (-1) 'A' will take 'Z's path, but in ASCII 'A'-1 equals '@'

IMAGE III

'@' = 64
'A' = 65

Which means we need to add to the tmp variable ,that stores the the current Key, the size of dictionary to prevent it from getting out of boundaries. Again, there are multiple ways to do it, that's only an example. 
- Dictionary.count = 26 (A-Z)
'@' + 26 => 64 + 26 => 90 => char(90) is 'Z'

Here is a quick snippet:

if (cipher + counter < 'A')                                      
      tmp += (char)dictionary.Count;                             
if (cipher + counter > 'Z')                                      
      tmp -= (char)dictionary.Count;                             

*Use debugging to make sure the round routine is working.

Now that we know we are always within bounds (A-Z) we need to create a Key:Value search inside the dictionary and determine a True/False state. There are other methods in C# that can search within a dictionary in O(1), but I wasn't after improving complexity so I used a foreach loop.

So for each element in the dictionary, we would like to check whether its Key equals to our tmp and a True statement will then store the Value of that Key into the static variable 'key'.
**Remember to add/sub the counter from the value to include the movement of the blocks

To save a bit time in debug mode, break; the foreach after finding the Key.

Here is a quick snippet:
                
foreach (var element in dictionary)                              
{                                                                
                                                                 
   if (element.Key == tmp)                                       
   {                                                             
      key = (char)(element.Value - counter);                     
      if (key < 65)                                              
      key += (char)dictionary.Count;                             
      if (key > 90)                                              
      key -= (char)dictionary.Count;                             
                                                                 
      break;                                                     
   }                                                             
}                                                                


**Notice that A and B are supposed to be the same function, only in Main() - A takes the first char from the textFromUser while B (and the others) takes the Value of the Key that came out of block A.
In our example it is of course the static char key;

After creating all the functions all that is left is to complete the Main() function.
We started with writing 2 arrays, now we need to take each char of the array into the journey of the Enigma machine and check the output as input once more to make sure we're returning back to our textFromUser.

Create a loop that calls the functions one by one (see under IMAGE II), then writes the output of the textFromUser[i]  to the same location [i], but in the empty array.
Your empty array will be used as a container for checking back the cipher created.

If everything was created as it should
MYSECRET should pop out of the machine as PKHAIMOY.

IMAGE VI


Return the cipher back to MYSECRET and your done!

Now place the real cipher in the array.

Ohh and don't forget the Hint (:

No comments:

Post a Comment