#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 lcd(19, 18, 17, 16, 15, 14); const int LCD_COLS = 16; const int LCD_ROWS = 2; 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 { "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 { "VI", "VI", "JPGVOUMFYQBENHZRDKASXLICTW", "ZM" }, // 6 { "VII", "VII", "NZJHGRCXMYSWBOUFAIVLPEKQDT", "ZM" }, // 7 { "VIII", "VIII", "FKQHTLXOCBJSPDZRAMEWNIUYGV", "ZM" }, // 8 { "beta", "Beta", "LEYJVCNIXWPBQMDRTAKZGFUHOS", "" }, // 9 { "gamma", "Gamma", "FSOKANUERHMBTIYCWLQPZXVGJD", "" }, // 10 { "UKW-A", "UKW A", "EJMZALYXVBWFCRQUONTSPIKHGD", "" }, // 11 reflectors { "UKW-B", "UKW B", "YRUHQSLDPXNGOKMIEBFZCWVJAT", "" }, // 12 { "UKW-C", "UKW C", "FVPJIAOYEDRZXWGCTKUQSBNMHL", "" }, // 13 { "UKW-B-thin", "UKW B thin", "ENKQAUYWJICOPBLMDXZVFTHRGS", "" }, // 14 { "UKW-C-thin", "UKW C thin", "RDOBJNTKVEHMLFCWZAXGYIPSUQ", "" } // 15 }; // entry wheel "EintrittswalzeEintrittswalze" byte entry_wheel_type = 0; // // rotor types byte rotor_type [] = { 1, 2, 3 }; // reflector "UmkehrwalzeUmkehrwalze" byte reflector_type = 12; char plugboard [10][2] = { {'-','-'}, {'-','-'}, {'-','-'}, {'-','-'}, {'-','-'}, {'-','-'}, {'-','-'}, {'-','-'}, {'-','-'}, {'-','-'} }; // 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) { Serial.print("->"); Serial.print(AZ[pin]); 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(" "); } } // plugboard // TODO 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=0; --i) { disp_rotor(i); } } void setup () { kbd.begin(); lcd.begin(16, 2); // test(); init_buf(input_buf); init_buf(encoded_buf); disp_rotors(); } void loop () { 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); }