enigma

         Enigma--Your mission is a success!

A. Second Edition
This is the second attempt of my Enigma after almost one month later after my first failed attempt. At that time
I was completely buried by my database project. And the most important thing is that I have several wrong concepts
about Enigma. 
1. Input and output array are not symmetric. Here I mean the "rotation" simulated by a shift in "in" array can\
NOT be achieved similarly by the "out" array. The "out" array is a bunch of 26 different arrays. See the rotor
class and try to see that if the "Rotor" is allowed to rotate, it will need 26 arrays for 26 different possible
"advance" number. Each "advance", which means 26 different rotating positions, has an array in "out" arrays. 
2. You cannot allow the three Rotors to rotate during one single alphabet is under processing. I figured out this
after one whole afternoon's painful debugging. You see, 26 different arrays will generated when each rotor rotates.
Then the "mapping" will be completely different. And the key feature of Enigma is that each letter is surely 
encoded to be a definite letter while this encoded letter can also be encoded to that letter. In other words,
if "A" is encoded to be "Q", then before rotating, "Q" can also be encoded as "A". Here "encode" can also be 
considered as "decode". You cannot change the "rotor" setting during the processing of each letter.
Here is a very good link for demo of Enigma:
http://www.enigmaco.de/
B.The problem

Enigma is the encryption machine that seemed to be impossible to decode before the invention of computer. I

write a simple program to simulate it but it only brings me with shame and regret.

1. The rotor is a simply "mapping" function between letters.

But the "reflector" is a little different. You can have whatever mapping between letters for any rotors. The

reflector must have pairs mapping, or in other words: A<-->F; E<-->Z; B<-->D; ...By doing so, you will have a

unique property of reflector: input "A" , output "F" and input "F", output "A"...

So, you see it "reflects" whatever letter you input.

The "stecker" is a partially "reflector". In history, German used 10 pairs of swapped letters and I followed

this design.

2. For the rotating problem, I use a data called "advance" to record how many steps the rotor has already

rotated. It is also a kind of simulation for the Enigma ground setting. You know, each rotor has a letter to

show what setting it has. It was by changing this setting, German created different combinations of cryption

key.

3. To decode a message, you just call "restoreSetting" function to restore the "advance" member data for each

rotor and run the encoded text again through the machine.

 

C.The idea of program
 

Maybe you regard this as trivial, but I think I learned a lot from it. The idea of all encryption is to hide the

pattern of human language. Say, in English all the vowels are used more often than most of consonants. This

gives the code-breaker clues to break code. And by hiding this pattern you need to avoid same letter be

enciphered by same letter. This requires that your encryption key be long enough. Machine is ideal to do this

job. Three rotor Enigma machine has a length of encryption key of 26x26x26=17576.

The Enigma machine was a kind of commercial products with 5 standard rotors. But only three rotors will be

installed with different sequences. So, the total combinations are 5x4x3=60. Each rotor has an indicator which

indicates the starting position of the rotor. So, the combination of three rotors will be 26x26x26=17576

The stecker is consists of 10 cables which will connect 10 pairs of letters from  keyboard to Enigma machines.

The possible combinations are 26!/(6!x2^10x10!)=150 million million

So, the total different possible combination would be 158 million million million.

It is impossible to decode without help of computer!


D.The major functions
There are few points to mention.
 
E.Further improvement
 
F.File listing
1. rotor.h
2. rotor.cpp
3. enigma.h
4. enigma.cpp
5. main.cpp (main)
file name: rotor.h
#ifndef ROTOR_H
#define ROTOR_H

const int RotorSize=26;
const int RotorNumber=9;//the last one is stecker

class Rotor
{
private:
	int in[RotorSize];
	int out[RotorSize][RotorSize];
	int shift;
	int advance;
	int left2right(int number);
	int right2left(int number);
public:	
	bool rotate();
	int operation(int input, bool R2L=true);
	void setAdvance(int theAdvance){advance=theAdvance;}
	void setShift(int theShift){shift=theShift;}
	void set(int settingNumber, int starter, bool rotatable=true);//ground setting
	void reset(){advance=0;}
};
#endif
file name: rotor.cpp
#include "Rotor.h"

//I got these settings from "Russell Schwager" who saves me the job of 
//"random mapping"
//the last one is stecker
int setting[RotorNumber][RotorSize]= 
{
	{ 
		4, 10, 12, 5, 11, 6, 3, 16, 
		21, 25, 13, 19, 14, 22, 24, 
		7, 23, 20, 18, 15, 0, 8, 1, 
		17, 2, 9 
	},
	{
		0, 9, 3, 10, 18, 8, 17, 
		20, 23, 1, 11, 7, 22, 19, 
		12, 2, 16, 6, 25, 13, 15, 
		24, 5, 21, 14, 4 
	},
	{
		1, 3, 5, 7, 9, 11, 2, 
		15, 17, 19, 23, 21, 25,
		13, 24, 4, 8, 22, 6, 0,
		10, 12, 20, 18, 16, 14 
	}, 

	{ 
		4, 18, 14, 21, 15, 25, 9, 0,
		24, 16, 20, 8, 17, 7, 23, 11,
		13, 5, 19, 6, 10, 3, 2, 12, 22, 1
	},

	{ 
		21, 25, 1, 17, 6, 8, 19, 24, 20,
		15, 18, 3, 13, 7, 11, 23, 0, 22,
		12, 9, 16, 14, 5, 4, 2, 10 
	},

	{ 
		9, 15, 6, 21, 14, 20, 12, 5,
		24, 16, 1, 4, 13, 7, 25, 17,
		3, 10, 0, 18, 23, 11, 8, 2,
		19, 22 
	},
	{ 
		13, 25, 9, 7, 6, 17, 2, 23, 
		12, 24, 18, 22, 1, 14, 20, 5,
		0, 8, 21, 11, 15, 4, 10, 16, 
		3, 19 
	},
	//this is for reflector and reflector doesn't rotate
	//the number are carefully chosen such that they are swapped
	//in pairs: 0<-->5, 1<-->10, 2<-->16...
	{ 
		5, 10, 16, 7, 19, 0, 23, 
		3, 21, 25, 1, 18, 15, 20, 
		17, 12, 2, 14, 11, 4, 13, 
		8, 24, 6, 22, 9 
	},
	//this is stecker, note that it is only "swap" between two characters
	{ 
		9,  20,  12, 3, 18, 
		5,  16,  25, 23, 0, 
		24,  11, 2,  22, 14, 
		1,   6, 17,  4, 19, 
		15, 21,  13,  8, 10, 7 
	}

};

//left2right is considered to be reversed
//and advance+shift gives different mapping
int Rotor::left2right(int number)
{	
	return out[(advance+shift)%RotorSize][number];
}

//r2l is simply one mapping, advance+shift get the offset
int Rotor::right2left(int number)
{
	int index=(number+advance+shift)%RotorSize;
	if (index<0)
	{
		index+=RotorSize;
	}
	return in[index];
}

bool Rotor::rotate()
{
	advance++;
	advance%=RotorSize;
	return advance%RotorSize==0;
}


void Rotor::set(int settingNumber, int starter, bool rotatable)
{
	for (int step=0; step<RotorSize; step++)
	{
		for (int i=0; i<RotorSize; i++)
		{
			if (step==0)
			{
				in[i]=setting[settingNumber][i];
				out[step][in[i]]=i;
			}
			else
			{
				//25 other different mapping
				out[step][in[(i+step)%RotorSize]]=i;
			}			
		}
	}
	shift=0;
	advance=starter;	
}

int Rotor::operation(int input, bool R2L)
{
	if (!R2L)
	{
		return left2right(input);
	}
	else
	{
		return right2left(input);
	}
}


file name: enigma.h

#include "Rotor.h"

const int RotorCount=3;
const int SteckerIndex=8;
const int ReflectorIndex=7;

class Enigma
{
private:
	Rotor rotors[RotorCount];
	Rotor reflector;
	Rotor stecker;
	int advances[RotorCount];
	int shifts[RotorCount];
	void initialize();
	void rotate();
	int operation(int input);
public:
	void encode(char* text);
	void decode(char* text);	
	void restoreSetting();
	void run(char* text);
	Enigma();
};
 

 

file name: enigma.cpp

#include <iostream>
#include "Enigma.h"

using namespace std;

int groundSetting[2][RotorCount]=
{
	{0,1,2},//rotor index
	{25,8,1} //rotor starting position
};

Enigma::Enigma()
{
	initialize();
}

void Enigma::initialize()
{
	for (int i=0; i<RotorCount; i++)
	{
		rotors[i].set(groundSetting[0][i], groundSetting[1][i]);
		//just record the shifts, and it seems useless now.
		shifts[i]=0;
		advances[i]=groundSetting[1][i];
	}
	reflector.set(ReflectorIndex, 0, false);
	stecker.set(SteckerIndex, 0, false);
}

void Enigma::rotate()
{
	int i=0;
	while (i<RotorCount)
	{
		//this is where "enigma" bookkeeping the "advances"		
		if (rotors[i].rotate())	
		{
			//it means this rotor rotates a cycle and 
			//it is turn for next rotor to rotate
			i++;
		}
		else
		{
			//there is no more rotating
			break;
		}
	}
}

int Enigma::operation(int input)
{	
	//here goes the steckers
	input=stecker.operation(input, true);
	for (int i=0; i<RotorCount; i++)
	{
		input=rotors[i].operation(input, true);		
	}
	//input=reflector.operation(input, !isEncoding);
	input=reflector.operation(input, true);
	for (i=RotorCount-1; i>=0; i--)
	{
		input=rotors[i].operation(input, false);
		//input=rotors[i].right2left(input);		
	}
	input=stecker.operation(input, false);
	rotate();
	//rotating
	/*
	while (i<RotorCount)
	{
		//this is where "enigma" bookkeeping the "advances"
		advances[i]++;
		rotors[i].rotate();
		if (advances[i]%RotorSize==0)//like notch
		{
			//it means this rotor rotates a cycle and 
			//it is turn for next rotor to rotate
			i++;
		}
		else
		{
			//there is no more rotating
			break;
		}
	}
	*/
	return input;
}

/*
void Enigma::encode(char* text)
{
	char *src=text;
	int input;
	while (*src!='\0')
	{
		if (isalpha(*src))
		{
			input=toupper(*src)-'A';
			input=operation(input, true);
			*src=input+'A';		
		}
		src++;
	}
}
	
void Enigma::encode(char* text)
{
	char *src=text;
	int input;
	while (*src!='\0')
	{
		if (isalpha(*src))
		{
			input=toupper(*src)-'A';
			input=operation(input, true);
			*src=input+'A';		
		}
		src++;
	}
}
*/

void Enigma::run(char* text)
{
	char *src=text;
	int input;
	while (*src!='\0')
	{
		if (isalpha(*src))
		{
			input=toupper(*src)-'A';
			input=operation(input);
			*src=input+'A';		
		}
		src++;
	}
}

void Enigma::restoreSetting()
{
	for (int i=0; i<RotorCount; i++)
	{
		rotors[i].setAdvance(advances[i]);
		rotors[i].setShift(shifts[i]);	
	}
}

file name: main.cpp
#include <iostream>
#include "Enigma.h"
#include "Rotor.h"

using namespace std;


int main()
{
	char buffer[256];
	Enigma E;
	FILE* in, *out;
	in=fopen("source.txt", "r");
	out=fopen("target.txt", "w");
	while (!feof(in))
	{
		//you know "fgets" will return NULL when eof is met,
		//but why "feof" not return false? maybe it is because
		//that feof only return non-zero after it PASSES eof.
		if (fgets(buffer, 256, in)==NULL)
		{
			break;
		}
		cout<<"before encoding, let's see the input text\n"<<buffer<<endl;
		E.run(buffer);
		cout<<"this is the encoded\n"<<buffer<<endl;

		cout<<"now write into file\n";
		fputs(buffer, out);
	}
	fclose(in);
	fclose(out);
	cout<<"now lets decode the file\n";
	E.restoreSetting();
	in=fopen("target.txt", "r");
	out=fopen("plain.txt", "w");
	while (!feof(in))
	{
		if (fgets(buffer, 255, in)==NULL)
		{
			break;
		}
		//strcpy(buffer, "ABCDEFG");
		cout<<"before decoding, let's see the input text\n"<<buffer<<endl;
		E.run(buffer);
		cout<<"this is the decoded\n"<<buffer<<endl;

		cout<<"now write to file plain.txt\n";
		fputs(buffer, out);
	}

/*
	int input[3]={0,1,2};
	Rotor test;
	test.set(0,0);
	
	for (int i=0; i<3; i++)
	{
		cout<<"step "<<i<<endl;
		for (int j=0; j<RotorSize; j++)
		{
			cout<<test.operation(j, true)<<", ";
		}
		cout<<"\nnow is left2right\n";
		for (j=0; j<RotorSize; j++)
		{
			cout<<test.operation(j, false)<<", ";
		}
		cout<<"\ninput["<<i<<"]="<<(input[i]=test.operation(input[i], true))<<endl;
		cout<<endl;
		test.rotate();
	}


	//test.rotate(false);
	test.reset();
	cout<<"\nnow rotate reversely\n";
	for (i=0; i<3; i++)
	{
		cout<<"step "<<i<<endl;
		for (int j=0; j<RotorSize; j++)
		{
			cout<<test.operation(j, true)<<", ";
		}
		cout<<"\nnow is left2right\n";
		for (j=0; j<RotorSize; j++)
		{
			cout<<test.operation(j, false)<<", ";
		}
		cout<<"\ninput["<<i<<"]="<<(input[i]=test.operation(input[i], false))<<endl;
		cout<<endl;
		test.rotate();
	}
*/	
	return 0;
}



The result is like following:
The original text file: "source.txt"
Hello qingzhe

Welcome To SendMoreInfo.com. Be sure to save this email. It
contains your ID number and Password. (Included below)

Password: pphwrz
The encoded text file: "target.txt"


EGMRP FTEKTLO

RFULIJT SW XKBMPBAIDMWT.OHE. KS FHAZ IQ UTAO ZYVG YQGGX. GY
TNXIGNVI PQIG QT YNTWQF HBB VIBODIQR. (ERNVAPXF XCRKI)

LSEFFIYB: AEZECT
The decoded text file: "plain.txt"






HELLO QINGZHE

WELCOME TO SENDMOREINFO.COM. BE SURE TO SAVE THIS EMAIL. IT
CONTAINS YOUR ID NUMBER AND PASSWORD. (INCLUDED BELOW)

PASSWORD: PPHWRZ
				


			
				 back.gif (341 bytes)       up.gif (335 bytes)         next.gif (337 bytes)