Hi Everyone,
I took something I'm familiar with (German M4 Enigma encryption machine) and implemented it in what I hope is decent form/pattern C#. I've written this many times on many platforms in C/assembly/basic/etc. and it is sort of my "fizz bizz" of can I implement it in a new language. If you want to know about the Enigma, here is a great page with plenty of details:
https://www.cryptomuseum.com/crypto/enigma/m4/index.htm
So what I'm looking for is what C# improvements are there to be made. Being used to C/C++ I tend to think that way and not implement something in the proper way that a C# dev would. Let me know what I missed or did inefficiently.
program.cs
enigma.cs
Example output:
REFL=B
ROTR=B123
RING=AAAA
PLUG=BE ZY
INDC=AAAA
IN:AAAAA
OUT:EDYGO
REFL=B
ROTR=B123
RING=AAAA
PLUG=BE ZY
INDC=AAAF
Press any key to continue . . .
I took something I'm familiar with (German M4 Enigma encryption machine) and implemented it in what I hope is decent form/pattern C#. I've written this many times on many platforms in C/assembly/basic/etc. and it is sort of my "fizz bizz" of can I implement it in a new language. If you want to know about the Enigma, here is a great page with plenty of details:
https://www.cryptomuseum.com/crypto/enigma/m4/index.htm
So what I'm looking for is what C# improvements are there to be made. Being used to C/C++ I tend to think that way and not implement something in the proper way that a C# dev would. Let me know what I missed or did inefficiently.
program.cs
C#:
using System;using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EnigmaTestApp
{
class Program
{
static void ShowEnigmaState(Enigma enigma)
{
Console.WriteLine("REFL=" + enigma.Reflector);
Console.WriteLine("ROTR=" + enigma.Rotors);
Console.WriteLine("RING=" + enigma.Rings);
Console.WriteLine("PLUG=" + enigma.Plugboard);
Console.WriteLine("INDC=" + enigma.Indicators);
}
static void Main(string[] args)
{
string s1;
Enigma enigma = new Enigma();
enigma.Plugboard = "BE ZY";
ShowEnigmaState(enigma);
s1 = "AAAAA";
Console.WriteLine();
Console.WriteLine("IN:"+s1);
s1 =enigma.Cipher(s1);
Console.WriteLine("OUT:"+s1);
Console.WriteLine();
ShowEnigmaState(enigma);
}
}
}
enigma.cs
C#:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EnigmaTestApp
{
class Enigma
{
const int POSITIONS = 26;
const int ROTORS = 4;
const int POS_STEP = 32;
const int POS_ONLY = 31;
enum rotorwiringnames
{
ROTOR_1M,
ROTOR_2M,
ROTOR_3M,
ROTOR_4M,
ROTOR_5M,
ROTOR_6M,
ROTOR_7M,
ROTOR_8M,
ROTOR_BETA,
ROTOR_GAMMA,
ROTOR_REFL4B,
ROTOR_REFL4C,
};
static private readonly int[,] rotorwiring = new int[12, POSITIONS]
{
//"EKMFLGDQVZNTOWYHxUSPAIBRCJ", ROTOR_1M
{4,10,12,5,11,6,3,16,21,25,13,19,14,22,24,7,23|POS_STEP,20,18,15,0,8,1,17,2,9,},
//"AJDKsIRUXBLHWTMCQGZNPYFVOE", ROTOR_2M
{0,9,3,10,18|POS_STEP,8,17,20,23,1,11,7,22,19,12,2,16,6,25,13,15,24,5,21,14,4,},
//"BDFHJLCPRTXVZNYEIWGAKmUSQO", ROTOR_3M
{1,3,5,7,9,11,2,15,17,19,23,21,25,13,24,4,8,22,6,0,10,12|POS_STEP,20,18,16,14,},
//"ESOVPZJAYqUIRHXLNFTGKDCMWB", ROTOR_4M
{4,18,14,21,15,25,9,0,24,16|POS_STEP,20,8,17,7,23,11,13,5,19,6,10,3,2,12,22,1,},
//"VZBRGITYUPSDNHLXAWMJQOFECk", ROTOR_5M
{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|POS_STEP,},
//"JPGVOUMFYQBEnHZRDKASXLICTw", ROTOR_6M
{9,15,6,21,14,20,12,5,24,16,1,4,13|POS_STEP,7,25,17,3,10,0,18,23,11,8,2,19,22|POS_STEP,},
//"NZJHGRCXMYSWbOUFAIVLPEKQDt", ROTOR_7M
{13,25,9,7,6,17,2,23,12,24,18,22,1|POS_STEP,14,20,5,0,8,21,11,15,4,10,16,3,19|POS_STEP,},
//"FKQHTLXOCBJSpDZRAMEWNIUYGv", ROTOR_8M
{5,10,16,7,19,11,23,14,2,1,9,18,15|POS_STEP,3,25,17,0,12,4,22,13,8,20,24,6,21|POS_STEP,},
//"LEYJVCNIXWPBQMDRTAKZGFUHOS", ROTOR_BETA
{11,4,24,9,21,2,13,8,23,22,15,1,16,12,3,17,19,0,10,25,6,5,20,7,14,18,},
//"FSOKANUERHMBTIYCWLQPZXVGJD", ROTOR_GAMMA
{5,18,14,10,0,13,20,4,17,7,12,1,19,8,24,2,22,11,16,15,25,23,21,6,9,3,},
//"ENKQAUYWJICOPBLMDXZVFTHRGS", ROTOR_REFL4B
{4,13,10,16,0,20,24,22,9,8,2,14,15,1,11,12,3,23,25,21,5,19,7,17,6,18,},
//"RDOBJNTKVEHMLFCWZAXGYIPSUQ", ROTOR_REFL4C
{17,3,14,1,9,13,19,10,21,4,7,12,11,5,2,22,25,0,23,6,24,8,15,18,20,16,},
};
private rotorwiringnames reflector;
public string Reflector
{
get
{
if (reflector == rotorwiringnames.ROTOR_REFL4B)
return "B";
else return "C";
}
set
{
switch (value)
{
case "B":
reflector = rotorwiringnames.ROTOR_REFL4B;
break;
case "C":
reflector = rotorwiringnames.ROTOR_REFL4C;
break;
default:
throw new System.ArgumentException("Invalid reflector");
}
}
}
private rotorwiringnames[] rotors = new rotorwiringnames[ROTORS];
public string Rotors
{
get
{
string s1;
//thin rotor 0
if (rotors[0] == rotorwiringnames.ROTOR_BETA)
s1 = "B";
else s1 = "G";
//remaining rotors
for (int i1 = 1; i1 < ROTORS; i1++)
s1 += (char)(rotors[i1] + '1');
return s1;
}
set
{
rotorwiringnames[] rotors2 = new rotorwiringnames[ROTORS];
if (value == null || value.Length != ROTORS)
throw new System.ArgumentException("Invalid rotors");
//thin rotor 0
if (value[0] == 'B')
rotors2[0] = rotorwiringnames.ROTOR_BETA;
else
if (value[0] == 'G')
rotors2[0] = rotorwiringnames.ROTOR_GAMMA;
else throw new System.ArgumentException("Invalid rotors");
//remaining rotors
for (int i1 = 1; i1 < ROTORS; i1++)
if (value[i1] >= '1' && value[i1] <= '8')
rotors2[i1] = (rotorwiringnames)(value[i1] - '1');
else throw new System.ArgumentException("Invalid rotors");
//assign
rotors = rotors2;
}
}
private int[] rings = new int[ROTORS];
public string Rings
{
get
{
string s1 = "";
int i1;
//rotors
for (i1 = 0; i1 < ROTORS; i1++)
s1 += (char)(rings[i1] + 'A');
return s1;
}
set
{
int[] rings2 = new int[ROTORS];
if (value == null || value.Length != ROTORS)
throw new System.ArgumentException("Invalid rings");
//rotors
for (int i1 = 0; i1 < ROTORS; i1++)
if (value[i1] >= 'A' && value[i1] <= 'Z')
rings2[i1] = value[i1] - 'A';
else throw new System.ArgumentException("Invalid rings");
//assign
rings = rings2;
}
}
private int[] indicators = new int[ROTORS];
public string Indicators
{
get
{
string s1 = "";
int i1;
//rotors
for (i1 = 0; i1 < ROTORS; i1++)
s1 += (char)(indicators[i1] + 'A');
return s1;
}
set
{
int[] indicators2 = new int[ROTORS];
if (value == null || value.Length != ROTORS)
throw new System.ArgumentException("Invalid indicators");
//rotors
for (int i1 = 0; i1 < ROTORS; i1++)
if (value[i1] >= 'A' && value[i1] <= 'Z')
indicators2[i1] = value[i1] - 'A';
else throw new System.ArgumentException("Invalid indicators");
//assign
indicators = indicators2;
}
}
private int[,] plugboard = new int[POSITIONS / 2, 2];
private int plugboarditems;
public string Plugboard
{
get
{
string s1 = "";
int i1;
//rotors
for (i1 = 0; i1 < plugboarditems; i1++)
{
if (s1.Length > 0)
s1 += ' ';
for (int i2 = 0; i2 < 2; i2++)
s1 += (char)(plugboard[i1, i2] + 'A');
}
return s1;
}
set
{
int[,] plugboard2 = new int[POSITIONS / 2, 2];
int plugboarditems2;
bool[] used = new bool[POSITIONS];
if (value == null)
throw new System.ArgumentException("Invalid plugboard");
//convert to uppercase and remove all spaces
value = value.ToUpper().Replace(" ", "");
//does it have an even number of characters
if (value.Length % 2 == 1)
throw new System.ArgumentException("Invalid plugboard");
plugboarditems2 = value.Length / 2;
for (int i1 = 0; i1 < plugboarditems2; i1++)
if (value[i1 * 2] >= 'A' && value[i1 * 2] <= 'Z' && !used[value[i1 * 2] - 'A'] &&
value[i1 * 2 + 1] >= 'A' && value[i1 * 2 + 1] <= 'Z' && !used[value[i1 * 2 + 1] - 'A'] &&
value[i1 * 2] != value[i1 * 2 + 1])
{
plugboard2[i1, 0] = value[i1 * 2] - 'A';
used[value[i1 * 2] - 'A'] = true;
plugboard2[i1, 1] = value[i1 * 2 + 1] - 'A';
used[value[i1 * 2 + 1] - 'A'] = true;
}
else throw new System.ArgumentException("Invalid plugboard");
//assign
plugboard = plugboard2;
plugboarditems = plugboarditems2;
}
}
public Enigma()
{
InitializeMachine();
}
public void InitializeMachine()
{
Reflector = "B";
Rotors = "B123";
Rings = "AAAA";
Indicators = "AAAA";
Plugboard = "";
}
public void StepRotors()
{
int[] advance = new int[ROTORS] { 0, 0, 0, 1 };
if ((rotorwiring[(int)rotors[3], indicators[3]] & POS_STEP) == POS_STEP)
advance[2] = 1;
if ((rotorwiring[(int)rotors[2], indicators[2]] & POS_STEP) == POS_STEP)
{
advance[1] = 1;
advance[2] = 1;
}
for (int i1 = 0; i1 < ROTORS; i1++)
if (advance[i1] == 1)
{
indicators[i1]++;
if (indicators[i1] >= POSITIONS)
indicators[i1] = 0;
}
}
private int ForwardThroughRotor(rotorwiringnames ARotor, int AIndicator, int ARing, int AKey)
{
return (((rotorwiring[(int)ARotor, (AIndicator + (POSITIONS - ARing) + AKey) % POSITIONS] & POS_ONLY) + (POSITIONS - AIndicator) + ARing) % POSITIONS);
}
private int ReverseThroughRotor(rotorwiringnames ARotor, int AIndicator, int ARing, int AKey)
{
for (int i1 = 0; i1 < POSITIONS; i1++)
if (AKey == ForwardThroughRotor(ARotor, AIndicator, ARing, i1))
return i1;
throw new System.ArgumentException("Invalid rotorwiring");
}
public int PlugboardTraverse(int AKey)
{
for (int i1 = 0; i1 < plugboarditems; i1++)
if (AKey == plugboard[i1, 0])
return plugboard[i1, 1];
else
if (AKey == plugboard[i1, 1])
return plugboard[i1, 0];
return AKey;
}
public int Cipher(int AKey)
{
//step the rotors properly
StepRotors();
//go through plugboard
AKey = PlugboardTraverse(AKey);
//forward through rotors
for (int i1 = ROTORS - 1; i1 >= 0; i1--)
AKey = ForwardThroughRotor(rotors[i1], indicators[i1], rings[i1], AKey);
//forward through reflector
AKey = ForwardThroughRotor(reflector, 0, 0, AKey);
//reverse through rotors
for (int i1 = 0; i1 < ROTORS; i1++)
AKey = ReverseThroughRotor(rotors[i1], indicators[i1], rings[i1], AKey);
//go through plugboard
AKey = PlugboardTraverse(AKey);
return AKey;
}
public string Cipher(string AString)
{
string s1, s2;
s1 = AString.ToUpper();
s2 = "";
foreach (char c in s1)
if (c >= 'A' && c <= 'Z')
s2 = s2 + (char)(Cipher(c - 'A') + 'A');
return s2;
}
}
}
Example output:
REFL=B
ROTR=B123
RING=AAAA
PLUG=BE ZY
INDC=AAAA
IN:AAAAA
OUT:EDYGO
REFL=B
ROTR=B123
RING=AAAA
PLUG=BE ZY
INDC=AAAF
Press any key to continue . . .