2020-09-23 20:16:06 +00:00
|
|
|
#include "Adafruit_Keypad.h"
|
|
|
|
|
|
|
|
const byte KBD_ROWS = 3; // rows
|
|
|
|
const byte KBD_COLS = 9; // columns
|
|
|
|
|
|
|
|
char keys[KBD_ROWS][KBD_COLS] = {
|
|
|
|
{'Q','W','E','R','T','Z','U','I','O'},
|
|
|
|
{'A','S','D','F','G','H','J','K','*'},
|
|
|
|
{'P','Y','X','C','V','B','N','M','L'}
|
|
|
|
};
|
|
|
|
|
|
|
|
byte rowPins[KBD_ROWS] = {10,11,12}; //connect to the row pinouts of the keypad
|
|
|
|
byte colPins[KBD_COLS] = {13,2,3,4,5,6,7,8,9}; //connect to the column pinouts of the keypad
|
|
|
|
|
|
|
|
Adafruit_Keypad kbd = Adafruit_Keypad( makeKeymap(keys), rowPins, colPins, KBD_ROWS, KBD_COLS);
|
|
|
|
|
|
|
|
#include <LiquidCrystal.h>
|
|
|
|
LiquidCrystal lcd(19, 18, 17, 16, 15, 14);
|
|
|
|
|
2020-09-24 01:05:03 +00:00
|
|
|
const int LCD_COLS = 20;
|
|
|
|
const int LCD_ROWS = 4;
|
2020-09-23 20:16:06 +00:00
|
|
|
|
|
|
|
bool debug_mode = false;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
char *id;
|
|
|
|
char *name;
|
|
|
|
char wiring[26];
|
|
|
|
char *notch;
|
|
|
|
} Rotor;
|
|
|
|
|
|
|
|
Rotor rotors [] = {
|
|
|
|
// Enigma I, M3, M4
|
|
|
|
// id name wiring notch
|
|
|
|
// == ==== ====== =====
|
|
|
|
{ "ABC", "ABC", "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "" }, // 0 alphabet
|
2020-09-27 15:43:58 +00:00
|
|
|
|
|
|
|
//
|
2020-09-23 20:16:06 +00:00
|
|
|
{ "I", "I", "EKMFLGDQVZNTOWYHXUSPAIBRCJ", "Q" }, // 1
|
|
|
|
{ "II", "II", "AJDKSIRUXBLHWTMCQGZNPYFVOE", "E" }, // 2
|
|
|
|
{ "III", "III", "BDFHJLCPRTXVZNYEIWGAKMUSQO", "V" }, // 3
|
|
|
|
{ "IV", "IV", "ESOVPZJAYQUIRHXLNFTGKDCMWB", "J" }, // 4
|
|
|
|
{ "V", "V", "VZBRGITYUPSDNHLXAWMJQOFECK", "Z" }, // 5
|
2020-09-27 15:43:58 +00:00
|
|
|
|
|
|
|
//
|
2020-09-23 20:16:06 +00:00
|
|
|
{ "VI", "VI", "JPGVOUMFYQBENHZRDKASXLICTW", "ZM" }, // 6
|
|
|
|
{ "VII", "VII", "NZJHGRCXMYSWBOUFAIVLPEKQDT", "ZM" }, // 7
|
|
|
|
{ "VIII", "VIII", "FKQHTLXOCBJSPDZRAMEWNIUYGV", "ZM" }, // 8
|
2020-09-27 15:43:58 +00:00
|
|
|
{ "beta", "Beta", "LEYJVCNIXWPBQMDRTAKZGFUHOS", "" }, // 9 M4 only
|
|
|
|
{ "gamma", "Gamma", "FSOKANUERHMBTIYCWLQPZXVGJD", "" }, // 10 M4 only
|
|
|
|
|
|
|
|
// reflectors
|
|
|
|
{ "UKW-A", "UKW A", "EJMZALYXVBWFCRQUONTSPIKHGD", "" }, // 11
|
2020-09-23 20:16:06 +00:00
|
|
|
{ "UKW-B", "UKW B", "YRUHQSLDPXNGOKMIEBFZCWVJAT", "" }, // 12
|
|
|
|
{ "UKW-C", "UKW C", "FVPJIAOYEDRZXWGCTKUQSBNMHL", "" }, // 13
|
2020-09-27 15:43:58 +00:00
|
|
|
{ "UKW-B-thin", "UKW B thin", "ENKQAUYWJICOPBLMDXZVFTHRGS", "" }, // 14 M4 only
|
|
|
|
{ "UKW-C-thin", "UKW C thin", "RDOBJNTKVEHMLFCWZAXGYIPSUQ", "" } // 15 M4 only
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
char *name;
|
|
|
|
char *description;
|
|
|
|
Rotor rotor_types[];
|
|
|
|
Rotor reflector_types[];
|
|
|
|
} EnigmaType;
|
|
|
|
|
|
|
|
EnigmaType enigma_types[] = {
|
|
|
|
{
|
|
|
|
"M3",
|
|
|
|
"Army",
|
|
|
|
{ rotors[1], rotors[2], rotors[3], rotors[4], rotors[5] },
|
|
|
|
{ rotors[11], rotors[12] }
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
"M4",
|
|
|
|
"Navy",
|
|
|
|
// work out thin rotors
|
|
|
|
{ rotors[1], rotors[2], rotors[3], rotors[4], rotors[5], rotors[6], rotors[7], rotors[8] },
|
|
|
|
{ rotors[11], rotors[12] }
|
|
|
|
}
|
2020-09-23 20:16:06 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// entry wheel "EintrittswalzeEintrittswalze"
|
|
|
|
byte entry_wheel_type = 0; //
|
|
|
|
|
|
|
|
// rotor types
|
|
|
|
byte rotor_type [] = { 1, 2, 3 };
|
|
|
|
|
|
|
|
// reflector "UmkehrwalzeUmkehrwalze"
|
|
|
|
byte reflector_type = 12;
|
2020-09-24 01:05:03 +00:00
|
|
|
const int PLUGBOARD_SIZE = 10;
|
|
|
|
char plugboard [PLUGBOARD_SIZE][2] = {
|
|
|
|
{'A','B'}, {'.','.'}, {'.','.'}, {'.','.'}, {'R','Z'},
|
|
|
|
{'C','D'}, {'.','.'}, {'.','.'}, {'.','.'}, {'G','H'}
|
2020-09-23 20:16:06 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// track rotor positions
|
|
|
|
byte rotor_pos [] = { 0, 0, 0 };
|
|
|
|
|
|
|
|
#define ROTOR_COUNT (sizeof(rotor_type)/sizeof(rotor_type[0]))
|
|
|
|
|
|
|
|
// compute alphabet size
|
|
|
|
#define AZ (rotors[entry_wheel_type].wiring)
|
|
|
|
#define AZ_LEN sizeof(rotors[0].wiring)
|
|
|
|
#define AZ_MAX_INDEX (AZ_LEN-1)
|
|
|
|
|
|
|
|
int wrap_pos (int pos) {
|
|
|
|
if (pos<0) {
|
|
|
|
return wrap_pos(pos+AZ_LEN); // TODO: optimization opportunity
|
|
|
|
} else {
|
|
|
|
return pos % AZ_LEN;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void rotate (byte rotor) {
|
|
|
|
rotor_pos[rotor] = wrap_pos(rotor_pos[rotor]+1);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool at_notch (byte rotor) {
|
|
|
|
return NULL != strchr(rotors[rotor_type[rotor]].notch, AZ[rotor_pos[rotor]]);
|
|
|
|
}
|
|
|
|
|
|
|
|
void print_rotor (int rotor) {
|
|
|
|
Serial.print(at_notch(rotor) ? '(' : '[');
|
|
|
|
Serial.print(AZ[rotor_pos[rotor]]);
|
|
|
|
Serial.print(at_notch(rotor) ? ')' : ']');
|
|
|
|
}
|
|
|
|
|
|
|
|
void print_rotors () {
|
|
|
|
for (int i=ROTOR_COUNT-1; i>=0; --i) {
|
|
|
|
print_rotor(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int stridx(char *str, char c) {
|
|
|
|
return strchr(str, c) - str;
|
|
|
|
}
|
|
|
|
|
|
|
|
char encode (char c) {
|
|
|
|
bool
|
|
|
|
rotated1 = false,
|
|
|
|
rotated2 = false;
|
|
|
|
|
|
|
|
print_rotors();
|
|
|
|
|
|
|
|
// rotate left rotor if middle rotor is at notch
|
|
|
|
if (at_notch(1)) {
|
|
|
|
rotated2 = true;
|
|
|
|
rotate(2);
|
|
|
|
}
|
|
|
|
|
|
|
|
// rotate middle rotor only if both right and middle are at notch
|
|
|
|
if (at_notch(0) || at_notch(1)) {
|
|
|
|
rotated1 = true;
|
|
|
|
rotate(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// always rotate the right rotor
|
|
|
|
rotate(0);
|
|
|
|
|
|
|
|
if (debug_mode) {
|
|
|
|
// did any of the rotors (except for the rightmost) rotate?
|
|
|
|
Serial.print(rotated2? '>' : '-');
|
|
|
|
Serial.print(rotated1? '>' : '-');
|
|
|
|
Serial.print('>');
|
|
|
|
}
|
|
|
|
|
|
|
|
print_rotors();
|
|
|
|
|
|
|
|
if (debug_mode)
|
|
|
|
Serial.print(' ');
|
|
|
|
|
|
|
|
// going from rightmost rotor to the left
|
|
|
|
int pin = stridx(AZ, c);
|
|
|
|
int pos;
|
|
|
|
char *wiring;
|
|
|
|
for (int rotor = 0; rotor < ROTOR_COUNT; ++rotor) {
|
|
|
|
pos = rotor_pos[rotor];
|
|
|
|
wiring = rotors[rotor_type[rotor]].wiring;
|
|
|
|
if (debug_mode)
|
|
|
|
Serial.print(AZ[pin]);
|
|
|
|
|
|
|
|
pin = wrap_pos(stridx(AZ, wiring[wrap_pos(pin + pos)]) - pos);
|
|
|
|
if (debug_mode) {
|
|
|
|
Serial.print("->");
|
|
|
|
Serial.print(AZ[pin]);
|
|
|
|
Serial.print(" ");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// reflector
|
|
|
|
if (debug_mode) {
|
|
|
|
Serial.print(" ");
|
|
|
|
Serial.print(AZ[pin]);
|
|
|
|
}
|
|
|
|
pin = stridx(AZ, rotors[reflector_type].wiring[pin]);
|
|
|
|
if (debug_mode) {
|
2020-09-27 15:43:58 +00:00
|
|
|
Serial.print("->");
|
|
|
|
Serial.print(AZ[pin]);
|
2020-09-23 20:16:06 +00:00
|
|
|
Serial.print(" ");
|
|
|
|
}
|
|
|
|
|
|
|
|
// returning back from leftmost to the right
|
|
|
|
for (int rotor = ROTOR_COUNT-1; rotor >= 0; --rotor) {
|
|
|
|
if (debug_mode)
|
|
|
|
Serial.print(AZ[pin]);
|
|
|
|
pos = rotor_pos[rotor];
|
|
|
|
wiring = rotors[rotor_type[rotor]].wiring;
|
|
|
|
pin = wrap_pos(pin + pos);
|
|
|
|
char ch = AZ[pin];
|
|
|
|
ch = AZ[stridx(wiring, ch)];
|
|
|
|
pin = stridx(AZ, ch);
|
|
|
|
pin = wrap_pos(pin - pos);
|
|
|
|
if (debug_mode) {
|
|
|
|
Serial.print("->");
|
|
|
|
Serial.print(AZ[pin]);
|
|
|
|
Serial.print(" ");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-24 01:05:03 +00:00
|
|
|
char plug_c = AZ[pin];
|
|
|
|
|
2020-09-23 20:16:06 +00:00
|
|
|
// plugboard
|
2020-09-24 01:05:03 +00:00
|
|
|
for (int i=0; i<PLUGBOARD_SIZE; ++i) {
|
|
|
|
if (AZ[pin] == plugboard[i][0]) {
|
|
|
|
return plugboard[i][1];
|
|
|
|
}
|
|
|
|
}
|
2020-09-23 20:16:06 +00:00
|
|
|
|
|
|
|
return AZ[pin];
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *plain = "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
|
|
const char *cipher = "FUVEPUMWARVQKEFGHGDIJFMFXIMRENATHDMCEVOQHIUWXXGYSJADEGKHYJETLBLWVZNUXFNSPICQFGZCZJKYWLLGPXJKBYTNNEFYKQTCJOLGCWHGXUEYOQXDNIGIDEMBXACVPAVYUQCGPXILERRSJSBOOKJW";
|
|
|
|
int const PLAIN_LEN = strlen(plain);
|
|
|
|
|
|
|
|
void test () {
|
|
|
|
Serial.begin(115200);
|
|
|
|
Serial.print("Testing "); Serial.print(PLAIN_LEN); Serial.println(" chars.");
|
|
|
|
|
|
|
|
bool failed = false;
|
|
|
|
|
|
|
|
debug_mode = true;
|
|
|
|
|
|
|
|
for (byte i=0; i<PLAIN_LEN; ++i) {
|
|
|
|
if (i<10) Serial.print(' ');
|
|
|
|
if (i<100) Serial.print(' ');
|
|
|
|
Serial.print(i, DEC);
|
|
|
|
Serial.print(": ");
|
|
|
|
char encoded = encode(plain[i]);
|
|
|
|
if (cipher[i] != encoded) {
|
|
|
|
failed = true;
|
|
|
|
Serial.print(" (Expected: ");
|
|
|
|
Serial.print(cipher[i]);
|
|
|
|
Serial.print(")");
|
|
|
|
}
|
|
|
|
Serial.println("");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (failed) {
|
|
|
|
Serial.println("\n"
|
|
|
|
"\n* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *"
|
|
|
|
"\nOne or more characters did not encrypt correctly. See messages above."
|
|
|
|
"\n* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *"
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-09-24 01:05:03 +00:00
|
|
|
const int BUF_SIZE = LCD_COLS - ROTOR_COUNT*3 - 1;
|
2020-09-23 20:16:06 +00:00
|
|
|
char input_buf [BUF_SIZE];
|
|
|
|
char encoded_buf [BUF_SIZE];
|
|
|
|
int buf_pos = 0;
|
|
|
|
|
|
|
|
void init_buf (char *buf) {
|
|
|
|
for (int i=0; i<BUF_SIZE; ++i) {
|
|
|
|
buf[i] = ' ';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void add_to_buf (char *buf, char c) {
|
|
|
|
for (int i=0; i<BUF_SIZE-1; ++i) {
|
|
|
|
buf[i] = buf[i+1];
|
|
|
|
}
|
|
|
|
buf[BUF_SIZE-1] = c;
|
|
|
|
}
|
|
|
|
|
|
|
|
void disp_buf (char *buf, int lcd_row) {
|
|
|
|
lcd.setCursor(LCD_COLS-BUF_SIZE,lcd_row);
|
|
|
|
for (int i=0; i<BUF_SIZE; ++i) {
|
|
|
|
lcd.print(buf[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void disp_rotor (int rotor) {
|
|
|
|
lcd.setCursor((ROTOR_COUNT-rotor-1)*3,0);
|
|
|
|
lcd.print(at_notch(rotor) ? '(' : '[');
|
|
|
|
lcd.print(AZ[rotor_pos[rotor]]);
|
|
|
|
lcd.print(at_notch(rotor) ? ')' : ']');
|
|
|
|
}
|
|
|
|
|
|
|
|
void disp_rotors () {
|
|
|
|
for (int i=ROTOR_COUNT-1; i>=0; --i) {
|
|
|
|
disp_rotor(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-24 01:05:03 +00:00
|
|
|
void disp_plugboard () {
|
|
|
|
if (LCD_ROWS > 2) {
|
|
|
|
for (int i=0; i<PLUGBOARD_SIZE/2; ++i) {
|
|
|
|
lcd.setCursor(i*3+(LCD_COLS-PLUGBOARD_SIZE/2*3+1),2);
|
|
|
|
lcd.print(plugboard[i][0]);
|
|
|
|
lcd.print(plugboard[i][1]);
|
|
|
|
if (i<PLUGBOARD_SIZE/2-1) {
|
|
|
|
lcd.print(' ');
|
|
|
|
}
|
|
|
|
lcd.setCursor(i*3+(LCD_COLS-PLUGBOARD_SIZE/2*3+1),3);
|
|
|
|
lcd.print(plugboard[i+PLUGBOARD_SIZE/2][0]);
|
|
|
|
lcd.print(plugboard[i+PLUGBOARD_SIZE/2][1]);
|
|
|
|
if (i<PLUGBOARD_SIZE/2-1) {
|
|
|
|
lcd.print(' ');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-27 15:43:58 +00:00
|
|
|
// config:
|
|
|
|
|
|
|
|
// reset
|
|
|
|
// enigma type
|
|
|
|
// for each rotor
|
|
|
|
// - ringsetting
|
|
|
|
// - rotor selection
|
|
|
|
// plugboard
|
|
|
|
// - clear
|
|
|
|
// - set pair
|
|
|
|
|
2020-09-23 20:16:06 +00:00
|
|
|
void setup () {
|
2020-09-24 01:05:03 +00:00
|
|
|
// Serial.begin(115200);
|
2020-09-23 20:16:06 +00:00
|
|
|
kbd.begin();
|
2020-09-24 01:05:03 +00:00
|
|
|
lcd.begin(LCD_COLS, LCD_ROWS);
|
|
|
|
|
|
|
|
lcd.setCursor(0,1);
|
2020-09-27 15:43:58 +00:00
|
|
|
lcd.print("Enigma");
|
|
|
|
lcd.setCursor(0,2);
|
|
|
|
lcd.print("M3");
|
2020-09-23 20:16:06 +00:00
|
|
|
|
2020-09-27 15:43:58 +00:00
|
|
|
test();
|
2020-09-23 20:16:06 +00:00
|
|
|
init_buf(input_buf);
|
|
|
|
init_buf(encoded_buf);
|
|
|
|
disp_rotors();
|
2020-09-24 01:05:03 +00:00
|
|
|
disp_plugboard();
|
2020-09-23 20:16:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-09-27 15:43:58 +00:00
|
|
|
bool demo_mode = false;
|
|
|
|
bool config_mode = true;
|
|
|
|
|
|
|
|
void enigma () {
|
2020-09-23 20:16:06 +00:00
|
|
|
kbd.tick();
|
|
|
|
|
|
|
|
while (kbd.available()) {
|
|
|
|
keypadEvent e = kbd.read();
|
|
|
|
if (e.bit.EVENT == KEY_JUST_PRESSED) {
|
|
|
|
char plain_c = (char)e.bit.KEY;
|
|
|
|
char encoded_c = encode(plain_c);
|
|
|
|
|
|
|
|
disp_rotors();
|
|
|
|
|
|
|
|
add_to_buf(input_buf, plain_c);
|
|
|
|
add_to_buf(encoded_buf, encoded_c);
|
|
|
|
disp_buf(input_buf, 0);
|
|
|
|
disp_buf(encoded_buf, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
delay(10);
|
|
|
|
}
|
2020-09-27 15:43:58 +00:00
|
|
|
|
|
|
|
void demo () {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void config () {
|
|
|
|
// demo? y/n -> demo_mode
|
|
|
|
// enigma type? menu -> enigma_type
|
|
|
|
// rotor[
|
|
|
|
}
|
|
|
|
|
|
|
|
void loop () {
|
|
|
|
if (config_mode) {
|
|
|
|
config();
|
|
|
|
} else if (demo_mode) {
|
|
|
|
demo();
|
|
|
|
} else {
|
|
|
|
enigma();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
Eintrittwalze entry wheel (stator)
|
|
|
|
Greek wheels Beta and Gamma [for obvious reasons] used in the M4
|
|
|
|
Grundstellung ground setting
|
|
|
|
Ringstellung ring setting
|
|
|
|
Stecker plug
|
|
|
|
Steckerbrett plugboard [sometimes referred to as "Stecker board"]
|
|
|
|
Umkehrwalze reflector
|
|
|
|
Walzen wheels
|
|
|
|
Walzenlage wheel order
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
https://cryptocellar.org/Enigma/index.html
|
|
|
|
http://www.mlb.co.jp/linux/science/genigma/enigma-referat/node4.html#SECTION00043000000000000000
|
|
|
|
|
|
|
|
*/
|