├── EnigmaSerial.ino ├── Examples ├── APCMAGEnigma.ino └── EnigmuinoEnigma.ino ├── LICENSE └── README.md /EnigmaSerial.ino: -------------------------------------------------------------------------------- 1 | #define STR_EXPAND(tok) #tok 2 | #define STR(tok) STR_EXPAND(tok) 3 | 4 | #ifndef INT16U 5 | #define INT16U unsigned short 6 | #endif 7 | 8 | // Rotor definitions, first two letters are the letter at which they rotate the one to the 9 | // left, the rest are the output given an input letter 10 | // rotors Beta & Gamma can only be used in the fourth position. 11 | // the wheels go as follow: 12 | 13 | // ABCDEFGHIJKLMNOPQRSTUVWXYZ 14 | #define ROTOR1 R-EKMFLGDQVZNTOWYHXUSPAIBRCJ 15 | #define ROTOR2 F-AJDKSIRUXBLHWTMCQGZNPYFVOE 16 | #define ROTOR3 W-BDFHJLCPRTXVZNYEIWGAKMUSQO 17 | #define ROTOR4 K-ESOVPZJAYQUIRHXLNFTGKDCMWB 18 | #define ROTOR5 A-VZBRGITYUPSDNHLXAWMJQOFECK 19 | #define ROTOR6 ANJPGVOUMFYQBENHZRDKASXLICTW 20 | #define ROTOR7 ANNZJHGRCXMYSWBOUFAIVLPEKQDT 21 | #define ROTOR8 ANFKQHTLXOCBJSPDZRAMEWNIUYGV 22 | #define ROTORB --LEYJVCNIXWPBQMDRTAKZGFUHOS 23 | #define ROTORG --FSOKANUERHMBTIYCWLQPZXVGJD 24 | #define ETW --ABCDEFGHIJKLMNOPQRSTUVWXYZ 25 | #define UKWA --EJMZALYXVBWFCRQUONTSPIKHGD 26 | #define UKWB --YRUHQSLDPXNGOKMIEBFZCWVJAT 27 | #define UKWC --FVPJIAOYEDRZXWGCTKUQSBNMHL 28 | #define UKWBD --ENKQAUYWJICOPBLMDXZVFTHRGS 29 | #define UKWCD --RDOBJNTKVEHMLFCWZAXGYIPSUQ 30 | 31 | const __FlashStringHelper * WHEELSF; 32 | const __FlashStringHelper * UHRSF; 33 | const __FlashStringHelper * UHRPLUGSF; 34 | 35 | char EffSTECKER[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 36 | byte WHEELPOS[4] = {'A', 'A', 'A', 'A'}; 37 | 38 | char KeyPressed = 0; 39 | char EncodedKey = 0; 40 | 41 | byte SerialRead = 0; 42 | byte SerialSetWheels = 0; 43 | byte SerialNewLine = 0; 44 | byte SerialPrintedChars = 0; 45 | 46 | struct enigmaData_t 47 | { 48 | byte SerialFunction; 49 | byte SerialPrinterGroups; 50 | byte Uhr; 51 | char PAIRS[27]; 52 | char STECKER[27]; 53 | byte WHEELTYPE[6]; 54 | byte WHEELPOS[4]; 55 | byte ROTORPOS[4]; 56 | } 57 | EnigmaData; 58 | 59 | 60 | void initEnigma() 61 | { 62 | /* 63 | 64 | http://www.enigma.hoerenberg.com/index.php?cat=The%20U534%20messages&page=P1030681 65 | 66 | Reflector: C 67 | Greek: B 68 | Wheels: 568 69 | 70 | Wheel positions: CDSZ 71 | Rings: EPEL 72 | 73 | Plugs: AE BF CM DQ HU JN LX PR SZ VW 74 | 75 | Message indicator groups: DUHF TETO 76 | 77 | Ciphertext (without indicator groups): 78 | 79 | LANOTCTOUARBBFPMHPHGCZXTDYGAHGUFXGEWKBLKGJWLQXXTGPJ 80 | JAVTOYJFGSLPPQIHZFXOEBWIIEKFZLCLOAQJULJOYHSSMBBGWHZ 81 | ANVOIIPYRBRTDJQDJJOQKCXWDNBBTYVXLYTAPGVEATXSONPNYNQ 82 | FUDBBHHVWEPYEYDOHNLXKZDNWRHDUWUJUMWWVIIWZXIVIUQDRHY 83 | MNCYEFUAPNHOTKHKGDNPSAKNUAGHJZSMJBMHVTREQEDGXHLZWIF 84 | USKDQVELNMIMITHBHDBWVHDFYHJOQIHORTDJDBWXEMEAYXGYQXO 85 | HFDMYUXXNOJAZRSGHPLWMLRECWWUTLRTTVLBHYOORGLGOWUXNXH 86 | MHYFAACQEKTHSJW 87 | 88 | */ 89 | 90 | // set to 1 to monitor or 2 to display encoded character only 91 | EnigmaData.SerialFunction = 2; 92 | 93 | // how many characters to print in a group, set to 0 for no groups 94 | EnigmaData.SerialPrinterGroups = 4; 95 | 96 | //ALL THE STEPS SHOWN BELOW MUST BE DONE TO INITIALIZE THE MACHINE 97 | 98 | //Rotor Types for an M4 machine/ 99 | // 1..8 rotors 9-Beta 10-Gamma 100 | // 11-ABC ETW 12-A reflector 13-B reflector 14-C reflector 101 | // 15-B thin reflector 16-C thin reflector 102 | EnigmaData.WHEELTYPE[0] = 11; // ENTRY CONTACTS: ETW 103 | EnigmaData.WHEELTYPE[1] = 8; // RIGHTMOST ROTOR 104 | EnigmaData.WHEELTYPE[2] = 6; // MIDDLE ROTOR 105 | EnigmaData.WHEELTYPE[3] = 5; // LEFT ROTOR 106 | EnigmaData.WHEELTYPE[4] = 9; // ADDITIONAL WHEEL (M4 only) 107 | EnigmaData.WHEELTYPE[5] = 16; // REFLECTOR: UKW 108 | 109 | //Wheel Positions 110 | EnigmaData.WHEELPOS[0] = 'C'; // LEFTMOST LETTER ON M4 111 | EnigmaData.WHEELPOS[1] = 'D'; // LEFTMOST LETTER ON M3 112 | EnigmaData.WHEELPOS[2] = 'S'; // MIDDLE LETTER 113 | EnigmaData.WHEELPOS[3] = 'Z'; // RIGHTMOST LETTER 114 | 115 | //Ring Settings 116 | EnigmaData.ROTORPOS[0] = 'E' - 64; // LEFTMOST ROTOR SETTING ON M4 117 | EnigmaData.ROTORPOS[1] = 'P' - 64; // LEFTMOST ROTOR SETTING ON M3 118 | EnigmaData.ROTORPOS[2] = 'E' - 64; // MIDDLE ROTOR SETTING 119 | EnigmaData.ROTORPOS[3] = 'L' - 64; // RIGHTMOST ROTOR SETTING 120 | 121 | for (byte i = 0; i < 4; i++) 122 | { 123 | WHEELPOS[i] = EnigmaData.WHEELPOS[i]; 124 | } 125 | 126 | //Initialize stecker with no plugs 127 | RemoveAllPlugs(); 128 | 129 | //ADD ANY PLUG PAIRS HERE USING THE AddPlug function 130 | AddPlug('A', 'E'); 131 | AddPlug('B', 'F'); 132 | AddPlug('C', 'M'); 133 | AddPlug('D', 'Q'); 134 | AddPlug('H', 'U'); 135 | AddPlug('J', 'N'); 136 | AddPlug('L', 'X'); 137 | AddPlug('P', 'R'); 138 | AddPlug('S', 'Z'); 139 | AddPlug('V', 'W'); 140 | 141 | // set the UHR (non zero values used only if 10 plug pairs are installed) 142 | EnigmaData.Uhr = 0; 143 | CalculateUhrStecker(); 144 | } 145 | 146 | 147 | void setup() 148 | { 149 | Serial.begin(9600); 150 | 151 | WHEELSF = F(STR(ROTOR1) STR(ROTOR2) STR(ROTOR3) STR(ROTOR4) STR(ROTOR5) STR(ROTOR6) STR(ROTOR7) STR(ROTOR8) STR(ROTORB) STR(ROTORG) STR(ETW) STR(UKWA) STR(UKWB) STR(UKWC) STR(UKWBD) STR(UKWCD)); 152 | UHRSF = F("\x06\x1F\x04\x1D\x12\x27\x10\x19\x1E\x17\x1C\x01\x26\x0B\x24\x25\x1A\x1B\x18\x15\x0E\x03\x0C\x11\x02\x07\x00\x21\x0A\x23\x08\x05\x16\x13\x14\x0D\x22\x0F\x20\x09"); 153 | UHRPLUGSF = F("\x06\x00\x07\x05\x01\x08\x04\x02\x09\x03"); 154 | 155 | initEnigma(); 156 | ShowRotors(); 157 | } 158 | 159 | 160 | void loop() 161 | { 162 | if (Serial.available()) 163 | { 164 | KeyPressed = Serial.read(); 165 | 166 | if (KeyPressed == '!') 167 | { 168 | SerialNewLine = 1; 169 | if (EnigmaData.WHEELTYPE[4] == 0) 170 | { 171 | SerialSetWheels = 3; 172 | } 173 | else 174 | { 175 | SerialSetWheels = 4; 176 | } 177 | } 178 | 179 | KeyPressed = KeyPressed & (255 - 32); 180 | 181 | if ((KeyPressed > 'A' - 1) && (KeyPressed < 'Z' + 1)) 182 | { 183 | SerialRead = 1; 184 | if (SerialSetWheels) 185 | { 186 | if (WHEELPOS[4 - SerialSetWheels] != KeyPressed) 187 | { 188 | WHEELPOS[4 - SerialSetWheels] = KeyPressed; 189 | } 190 | SerialSetWheels--; 191 | } 192 | else 193 | { 194 | if (SerialNewLine) 195 | { 196 | Serial.println(F("")); 197 | SerialNewLine = 0; 198 | SerialPrintedChars = 0; 199 | } 200 | 201 | MoveWheels(); 202 | EncodedKey = EncodeKey(KeyPressed); 203 | Serial.print(EncodedKey); 204 | 205 | if (EnigmaData.SerialPrinterGroups != 0) 206 | { 207 | SerialPrintedChars++; 208 | if (SerialPrintedChars == EnigmaData.SerialPrinterGroups) 209 | { 210 | Serial.print((char)32); 211 | SerialPrintedChars = 0; 212 | } 213 | } 214 | } 215 | } 216 | } 217 | 218 | if ((SerialRead) && (!Serial.available())) 219 | { 220 | SerialRead = 0; 221 | } 222 | } 223 | 224 | byte SteckerPairs() 225 | { 226 | byte c = 0; 227 | 228 | for (byte i = 0; i < 26; i++) 229 | { 230 | if (EnigmaData.STECKER[i] != (65 + i)) 231 | { 232 | c++; 233 | } 234 | } 235 | 236 | return (c / 2); 237 | } 238 | 239 | void RemoveAllPlugs() 240 | { 241 | for (byte i = 0; i < 27; i++) 242 | { 243 | EnigmaData.PAIRS[i] = 0; 244 | } 245 | 246 | strcpy(EnigmaData.STECKER, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); 247 | EnigmaData.Uhr = 0; 248 | } 249 | 250 | void AddPlug(char PlugKey1, char PlugKey2) 251 | { 252 | if ((SteckerPairs() < 13) && (PlugKey1 != PlugKey2)) 253 | { 254 | EnigmaData.PAIRS[SteckerPairs() * 2] = PlugKey1; 255 | EnigmaData.PAIRS[SteckerPairs() * 2 + 1] = PlugKey2; 256 | } 257 | 258 | EnigmaData.STECKER[PlugKey1 - 65] = PlugKey2; 259 | EnigmaData.STECKER[PlugKey2 - 65] = PlugKey1; 260 | } 261 | 262 | void CalculateUhrStecker() 263 | { 264 | const char PROGMEM *uhrptr = (const char PROGMEM *)UHRSF; 265 | const char PROGMEM *uhrplugptr = (const char PROGMEM *)UHRPLUGSF; 266 | 267 | byte ndx = 0; 268 | 269 | if (SteckerPairs() == 10) 270 | { 271 | for (byte i = 0; i < 26; i++) 272 | { 273 | EffSTECKER[i] = 65 + i; 274 | } 275 | 276 | for (byte i = 0; i < 10; i++) 277 | { 278 | byte pin = 0; 279 | byte pinright = 0; 280 | byte pinleft = 0; 281 | 282 | pin = EnigmaData.Uhr + i * 4; 283 | if (pin > 39) 284 | { 285 | pin -= 40; 286 | } 287 | 288 | for (byte j = 0; j < 40; j++) 289 | { 290 | if (pgm_read_byte(uhrptr + j) == pin) 291 | { 292 | pinleft = j; 293 | } 294 | } 295 | 296 | pinright = pgm_read_byte(uhrptr + pin); 297 | 298 | //these two need to be signed, see <0 below 299 | //char is signed -127..+128 300 | char plugright; 301 | char plugleft; 302 | 303 | plugright = (pinright - (EnigmaData.Uhr + 2)); 304 | if (plugright < 0) 305 | { 306 | plugright += 40; 307 | } 308 | plugright = plugright / 4; 309 | 310 | plugleft = (pinleft - (EnigmaData.Uhr + 2)); 311 | if (plugleft < 0) 312 | { 313 | plugleft += 40; 314 | } 315 | plugleft = plugleft / 4; 316 | 317 | EffSTECKER[EnigmaData.PAIRS[i * 2] - 65] = EnigmaData.PAIRS[pgm_read_byte(uhrplugptr + plugright) * 2 + 1]; 318 | EffSTECKER[EnigmaData.PAIRS[pgm_read_byte(uhrplugptr + i) * 2 + 1] - 65] = EnigmaData.PAIRS[plugleft * 2]; 319 | } 320 | } 321 | else 322 | { 323 | for (byte i = 0; i < 26; i++) 324 | { 325 | EffSTECKER[i] = EnigmaData.STECKER[i]; 326 | } 327 | } 328 | 329 | if (EnigmaData.SerialFunction == 1) 330 | { 331 | Serial.println(F("Stecker/Uhr:")); 332 | Serial.println(EffSTECKER); 333 | } 334 | } 335 | 336 | void MoveWheels() 337 | { 338 | byte i = 4; 339 | bool carry = true; 340 | 341 | do 342 | { 343 | i--; 344 | 345 | if (carry) 346 | { 347 | WHEELPOS[i]++; 348 | if (i > 1) 349 | { 350 | carry = IsCarry(EnigmaData.WHEELTYPE[4 - i], WHEELPOS[i]); 351 | } 352 | else 353 | { 354 | carry = false; 355 | } 356 | } 357 | else 358 | { 359 | // double stepping on second wheel 360 | if (i == 2) 361 | { 362 | byte w2 = WHEELPOS[2] + 1; 363 | 364 | if (w2 > 'Z') 365 | { 366 | w2 = 'A'; 367 | } 368 | 369 | if (IsCarry(EnigmaData.WHEELTYPE[2], w2)) 370 | { 371 | WHEELPOS[2]++; 372 | carry = true; 373 | } 374 | } 375 | } 376 | 377 | if (WHEELPOS[i] > 'Z') 378 | { 379 | WHEELPOS[i] = 'A'; 380 | carry = IsCarry(EnigmaData.WHEELTYPE[4 - i], WHEELPOS[i]) || carry; 381 | if (i == 1) 382 | { 383 | carry = false; 384 | } 385 | } 386 | 387 | } while (i > 0); 388 | 389 | } 390 | 391 | void ShowRotors() 392 | { 393 | const char PROGMEM *charptr = (const char PROGMEM *)WHEELSF; 394 | char k; 395 | INT16U wheeltype; 396 | 397 | if (EnigmaData.SerialFunction == 1) 398 | { 399 | Serial.println(F("Rotors:")); 400 | 401 | for (byte i = 0; i < 6; i++) 402 | { 403 | if (EnigmaData.WHEELTYPE[i] != 0) 404 | { 405 | switch (i) 406 | { 407 | case 0: 408 | { 409 | Serial.println(F("ETW")); 410 | break; 411 | } 412 | 413 | case 1: 414 | case 2: 415 | case 3: 416 | case 4: 417 | { 418 | Serial.print(F("R")); 419 | Serial.println((char)('0' + i)); 420 | break; 421 | } 422 | 423 | case 5: 424 | { 425 | Serial.println(F("UKW")); 426 | break; 427 | } 428 | } 429 | 430 | wheeltype = ((EnigmaData.WHEELTYPE[i] - 1) * 28) + 2; 431 | 432 | for (byte i = 0; i < 26; i++) 433 | { 434 | k = pgm_read_byte(charptr + wheeltype + i); 435 | Serial.print(k); 436 | } 437 | Serial.println(F("")); 438 | } 439 | } 440 | } 441 | } 442 | 443 | byte SerialMonitorStatus; 444 | 445 | void SerialMonitor(char k) 446 | { 447 | if (k == 0) 448 | { 449 | SerialMonitorStatus = 0; 450 | } 451 | else 452 | { 453 | if (EnigmaData.SerialFunction == 1) 454 | { 455 | SerialMonitorStatus++; 456 | 457 | //skip R4 if a three wheel machine 458 | if (((EnigmaData.WHEELTYPE[5] > 11) && (EnigmaData.WHEELTYPE[5] < 15)) && ((SerialMonitorStatus == 6) || (SerialMonitorStatus == 8))) 459 | { 460 | SerialMonitorStatus++; 461 | } 462 | 463 | Serial.print(k); 464 | 465 | switch (SerialMonitorStatus) 466 | { 467 | case 1: 468 | case 13: 469 | { 470 | Serial.print(F(">Stecker>")); 471 | break; 472 | } 473 | 474 | case 2: 475 | case 12: 476 | { 477 | Serial.print(F(">ETW>")); 478 | break; 479 | } 480 | 481 | case 3: 482 | case 11: 483 | { 484 | Serial.print(F(">R1>")); 485 | break; 486 | } 487 | 488 | case 4: 489 | case 10: 490 | { 491 | Serial.print(F(">R2>")); 492 | break; 493 | } 494 | 495 | case 5: 496 | case 9: 497 | { 498 | Serial.print(F(">R3>")); 499 | break; 500 | } 501 | 502 | case 6: 503 | case 8: 504 | { 505 | Serial.print(F(">R4>")); 506 | break; 507 | } 508 | 509 | case 7: 510 | { 511 | Serial.print(F(">UKW>")); 512 | break; 513 | } 514 | default: 515 | { 516 | Serial.println(F("")); 517 | } 518 | } 519 | } 520 | } 521 | } 522 | 523 | bool IsCarry(byte wheelType, byte wheelPos) 524 | { 525 | const char PROGMEM *charptr = (const char PROGMEM *)WHEELSF; 526 | INT16U wheeltype = (wheelType - 1) * 28; 527 | byte k1 = pgm_read_byte(charptr + wheeltype); 528 | byte k2 = pgm_read_byte(charptr + wheeltype + 1); 529 | bool v = false; 530 | 531 | if ((wheelPos == k1) || (wheelPos == k2)) 532 | { 533 | v = true; 534 | } 535 | 536 | return v; 537 | } 538 | 539 | char EncodeKey(char key) 540 | { 541 | const char PROGMEM *charptr = (const char PROGMEM *)WHEELSF; 542 | char k, k1; 543 | INT16U wheeltype; 544 | 545 | SerialMonitor(0); 546 | SerialMonitor(key); 547 | 548 | k = EffSTECKER[key - 'A']; 549 | 550 | SerialMonitor(k); 551 | 552 | for (byte i = 0; i < 6; i++) 553 | { 554 | if (EnigmaData.WHEELTYPE[i] != 0) 555 | { 556 | if ((i > 0) && (i < 5)) 557 | { 558 | byte p = WHEELPOS[4 - i] - (EnigmaData.ROTORPOS[4 - i] - 1); 559 | if (p < 'A') 560 | { 561 | p += 26; 562 | } 563 | 564 | k = k + (p - 'A'); 565 | } 566 | 567 | if (k > 'Z') 568 | { 569 | k = k - ('Z' + 1); 570 | } 571 | else 572 | { 573 | k = k - 'A'; 574 | } 575 | 576 | wheeltype = ((EnigmaData.WHEELTYPE[i] - 1) * 28) + k + 2; 577 | k = pgm_read_byte(charptr + wheeltype); 578 | 579 | if ((i > 0) && (i < 5)) 580 | { 581 | byte p = WHEELPOS[4 - i] - (EnigmaData.ROTORPOS[4 - i] - 1); 582 | if (p < 'A') 583 | { 584 | p += 26; 585 | } 586 | 587 | k = k - (p - 'A'); 588 | } 589 | 590 | if (k < 'A') 591 | { 592 | k = k + 26; 593 | } 594 | 595 | SerialMonitor(k); 596 | } 597 | } 598 | 599 | //after reflector 600 | 601 | for (byte i = 0; i < 5; i++) 602 | { 603 | if (EnigmaData.WHEELTYPE[4 - i] != 0) 604 | { 605 | if (i < 4) 606 | { 607 | byte p = WHEELPOS[i] - (EnigmaData.ROTORPOS[i] - 1); 608 | if (p < 'A') 609 | { 610 | p += 26; 611 | } 612 | 613 | k = k + (p - 'A'); 614 | } 615 | 616 | if (k > 'Z') 617 | { 618 | k = k - 26; 619 | } 620 | 621 | wheeltype = (EnigmaData.WHEELTYPE[4 - i] - 1) * 28; 622 | for (byte j = 0; j < 26; j++) 623 | { 624 | if ((pgm_read_byte(charptr + wheeltype + j + 2)) == k) 625 | { 626 | k1 = 'A' + j; 627 | } 628 | } 629 | 630 | k = k1; 631 | 632 | if (i < 4) 633 | { 634 | byte p = WHEELPOS[i] - (EnigmaData.ROTORPOS[i] - 1); 635 | if (p < 'A') 636 | { 637 | p += 26; 638 | } 639 | 640 | k = k - (p - 'A'); 641 | } 642 | 643 | if (k < 'A') 644 | { 645 | k = k + 26; 646 | } 647 | 648 | SerialMonitor(k); 649 | } 650 | 651 | } 652 | 653 | for (byte j = 0; j < 26; j++) 654 | { 655 | if (EffSTECKER[j] == k) 656 | { 657 | k1 = 'A' + j; 658 | } 659 | } 660 | k = k1; 661 | 662 | SerialMonitor(k); 663 | 664 | return k; 665 | } 666 | 667 | -------------------------------------------------------------------------------- /Examples/APCMAGEnigma.ino: -------------------------------------------------------------------------------- 1 | //this configuration decodes the encrypted text at 2 | //http://apcmag.com/arduino-projects-enigma-cipher-machine.htm 3 | 4 | #define STR_EXPAND(tok) #tok 5 | #define STR(tok) STR_EXPAND(tok) 6 | 7 | #ifndef INT16U 8 | #define INT16U unsigned short 9 | #endif 10 | 11 | // Rotor definitions, first two letters are the letter at which they rotate the one to the 12 | // left, the rest are the output given an input letter 13 | // rotors Beta & Gamma can only be used in the fourth position. 14 | // the wheels go as follow: 15 | // UKW,ROTOR,ROTOR,ROTOR,ROTOR,EKW 16 | // M3 17 | // byte WHEELTYPE[5] = {11, 1, 2, 3, 0, 12}; 18 | // M4 compatible with M3, set wheel 4 to A 19 | // byte WHEELTYPE[5] = {11, 1, 2, 3, 4, 12}; 20 | 21 | // ABCDEFGHIJKLMNOPQRSTUVWXYZ 22 | #define ROTOR1 R-EKMFLGDQVZNTOWYHXUSPAIBRCJ 23 | #define ROTOR2 F-AJDKSIRUXBLHWTMCQGZNPYFVOE 24 | #define ROTOR3 W-BDFHJLCPRTXVZNYEIWGAKMUSQO 25 | #define ROTOR4 K-ESOVPZJAYQUIRHXLNFTGKDCMWB 26 | #define ROTOR5 A-VZBRGITYUPSDNHLXAWMJQOFECK 27 | #define ROTOR6 ANJPGVOUMFYQBENHZRDKASXLICTW 28 | #define ROTOR7 ANNZJHGRCXMYSWBOUFAIVLPEKQDT 29 | #define ROTOR8 ANFKQHTLXOCBJSPDZRAMEWNIUYGV 30 | #define ROTORB --LEYJVCNIXWPBQMDRTAKZGFUHOS 31 | #define ROTORG --FSOKANUERHMBTIYCWLQPZXVGJD 32 | #define ETW --ABCDEFGHIJKLMNOPQRSTUVWXYZ 33 | #define UKWA --EJMZALYXVBWFCRQUONTSPIKHGD 34 | #define UKWB --YRUHQSLDPXNGOKMIEBFZCWVJAT 35 | #define UKWC --FVPJIAOYEDRZXWGCTKUQSBNMHL 36 | #define UKWBD --ENKQAUYWJICOPBLMDXZVFTHRGS 37 | #define UKWCD --RDOBJNTKVEHMLFCWZAXGYIPSUQ 38 | 39 | const __FlashStringHelper * WHEELSF; 40 | const __FlashStringHelper * UHRSF; 41 | const __FlashStringHelper * UHRPLUGSF; 42 | 43 | char EffSTECKER[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 44 | byte WHEELPOS[4] = {'A', 'A', 'A', 'A'}; 45 | 46 | // wheel types, first entry is for rightmost wheel, last is reflector 47 | // fifth entry can be 0 for a three rotor machine. 48 | //byte WHEELTYPE[6] = {11, 3, 2, 1, 0, 12}; 49 | //byte WHEELTYPE[6] = {11, 3, 2, 1, 9, 15}; 50 | 51 | //default M3 1939 in enigma simulator app 52 | //byte WHEELTYPE[6] = {11, 3, 2, 1, 0, 12}; 53 | //byte WHEELPOS[4] = {0, 'A', 'A', 'A'}; 54 | 55 | //default M4 1942 in enigma simulator app 56 | //byte WHEELTYPE[6] = {11, 3, 2, 1, 9, 15}; 57 | //byte WHEELPOS[4] = {'A', 'A', 'A', 'A'}; 58 | 59 | // test machine 60 | //byte WHEELTYPE[6] = {11, 1, 1, 1, 1, 15}; 61 | //byte WHEELPOS[4] = {'A', 'A', 'A', 'A'}; 62 | 63 | char KeyPressed = 0; 64 | char EncodedKey = 0; 65 | 66 | byte SerialRead = 0; 67 | byte SerialSetWheels = 0; 68 | 69 | struct enigmaData_t 70 | { 71 | byte SerialFunction; 72 | byte Uhr; 73 | char PAIRS[27]; 74 | char STECKER[27]; 75 | byte WHEELTYPE[6]; 76 | byte WHEELPOS[4]; 77 | byte ROTORPOS[4]; 78 | } 79 | EnigmaData; 80 | 81 | 82 | void initEnigma() 83 | { 84 | // set to 1 to monitor or 2 to display encoded character only 85 | EnigmaData.SerialFunction = 2; 86 | 87 | //ALL THE STEPS SHOWN BELOW MUST BE DONE TO INITIALIZE THE MACHINE 88 | 89 | //Rotor Types for an M4 machine, see more examples above 90 | EnigmaData.WHEELTYPE[0] = 11; // ENTRY CONTACTS: ETW 91 | EnigmaData.WHEELTYPE[1] = 3; // RIGHTMOST ROTOR 92 | EnigmaData.WHEELTYPE[2] = 2; // MIDDLE ROTOR 93 | EnigmaData.WHEELTYPE[3] = 1; // LEFT ROTOR 94 | EnigmaData.WHEELTYPE[4] = 0; // ADDITIONAL WHEEL (M4 only) 95 | EnigmaData.WHEELTYPE[5] = 13; // REFLECTOR: UKW 96 | 97 | //Wheel Positions 98 | EnigmaData.WHEELPOS[0] = 0; // LEFTMOST LETTER ON M4 99 | EnigmaData.WHEELPOS[1] = 'A'; // LEFTMOST LETTER ON M3 100 | EnigmaData.WHEELPOS[2] = 'P'; // MIDDLE LETTER 101 | EnigmaData.WHEELPOS[3] = 'C'; // RIGHTMOST LETTER 102 | 103 | //Ring Settings 104 | EnigmaData.ROTORPOS[0] = 0; // LEFTMOST ROTOR SETTING ON M4 105 | EnigmaData.ROTORPOS[1] = 13; // LEFTMOST ROTOR SETTING ON M3 106 | EnigmaData.ROTORPOS[2] = 1; // MIDDLE ROTOR SETTING 107 | EnigmaData.ROTORPOS[3] = 7; // RIGHTMOST ROTOR SETTING 108 | 109 | for (byte i = 0; i < 4; i++) 110 | { 111 | WHEELPOS[i] = EnigmaData.WHEELPOS[i]; 112 | } 113 | 114 | //Initialize stecker with no plugs 115 | RemoveAllPlugs(); 116 | 117 | //ADD ANY PLUG PAIRS HERE USING THE AddPlug function 118 | AddPlug('D', 'Y'); 119 | AddPlug('A', 'P'); 120 | AddPlug('C', 'M'); 121 | 122 | // set the UHR (non zero values used only if 10 plug pairs are installed) 123 | EnigmaData.Uhr = 0; 124 | CalculateUhrStecker(); 125 | } 126 | 127 | void setup() 128 | { 129 | Serial.begin(9600); 130 | 131 | WHEELSF = F(STR(ROTOR1) STR(ROTOR2) STR(ROTOR3) STR(ROTOR4) STR(ROTOR5) STR(ROTOR6) STR(ROTOR7) STR(ROTOR8) STR(ROTORB) STR(ROTORG) STR(ETW) STR(UKWA) STR(UKWB) STR(UKWC) STR(UKWBD) STR(UKWCD)); 132 | UHRSF = F("\x06\x1F\x04\x1D\x12\x27\x10\x19\x1E\x17\x1C\x01\x26\x0B\x24\x25\x1A\x1B\x18\x15\x0E\x03\x0C\x11\x02\x07\x00\x21\x0A\x23\x08\x05\x16\x13\x14\x0D\x22\x0F\x20\x09"); 133 | UHRPLUGSF = F("\x06\x00\x07\x05\x01\x08\x04\x02\x09\x03"); 134 | 135 | initEnigma(); 136 | ShowRotors(); 137 | } 138 | 139 | 140 | void loop() 141 | { 142 | if (Serial.available()) 143 | { 144 | KeyPressed = Serial.read(); 145 | 146 | if (KeyPressed == '!') 147 | { 148 | if (EnigmaData.WHEELTYPE[4] == 0) 149 | { 150 | SerialSetWheels = 3; 151 | } 152 | else 153 | { 154 | SerialSetWheels = 4; 155 | } 156 | } 157 | 158 | KeyPressed = KeyPressed & (255 - 32); 159 | 160 | if ((KeyPressed > 'A' - 1) && (KeyPressed < 'Z' + 1)) 161 | { 162 | SerialRead = 1; 163 | if (SerialSetWheels) 164 | { 165 | if (WHEELPOS[4 - SerialSetWheels] != KeyPressed) 166 | { 167 | WHEELPOS[4 - SerialSetWheels] = KeyPressed; 168 | } 169 | SerialSetWheels--; 170 | } 171 | else 172 | { 173 | MoveWheels(); 174 | EncodedKey = EncodeKey(KeyPressed); 175 | if (EnigmaData.SerialFunction == 2) 176 | { 177 | Serial.print(EncodedKey); 178 | } 179 | } 180 | } 181 | } 182 | 183 | if ((SerialRead) && (!Serial.available())) 184 | { 185 | SerialRead = 0; 186 | } 187 | } 188 | 189 | byte SteckerPairs() 190 | { 191 | byte c = 0; 192 | 193 | for (byte i = 0; i < 26; i++) 194 | { 195 | if (EnigmaData.STECKER[i] != (65 + i)) 196 | { 197 | c++; 198 | } 199 | } 200 | 201 | return (c / 2); 202 | } 203 | 204 | void RemoveAllPlugs() 205 | { 206 | for (byte i = 0; i < 27; i++) 207 | { 208 | EnigmaData.PAIRS[i] = 0; 209 | } 210 | 211 | strcpy(EnigmaData.STECKER, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); 212 | EnigmaData.Uhr = 0; 213 | } 214 | 215 | void AddPlug(char PlugKey1, char PlugKey2) 216 | { 217 | if ((SteckerPairs() < 13) && (PlugKey1 != PlugKey2)) 218 | { 219 | EnigmaData.PAIRS[SteckerPairs() * 2] = PlugKey1; 220 | EnigmaData.PAIRS[SteckerPairs() * 2 + 1] = PlugKey2; 221 | } 222 | 223 | EnigmaData.STECKER[PlugKey1 - 65] = PlugKey2; 224 | EnigmaData.STECKER[PlugKey2 - 65] = PlugKey1; 225 | } 226 | 227 | void CalculateUhrStecker() 228 | { 229 | const char PROGMEM *uhrptr = (const char PROGMEM *)UHRSF; 230 | const char PROGMEM *uhrplugptr = (const char PROGMEM *)UHRPLUGSF; 231 | 232 | byte ndx = 0; 233 | 234 | if (SteckerPairs() == 10) 235 | { 236 | for (byte i = 0; i < 26; i++) 237 | { 238 | EffSTECKER[i] = 65 + i; 239 | } 240 | 241 | for (byte i = 0; i < 10; i++) 242 | { 243 | byte pin = 0; 244 | byte pinright = 0; 245 | byte pinleft = 0; 246 | 247 | pin = EnigmaData.Uhr + i * 4; 248 | if (pin > 39) 249 | { 250 | pin -= 40; 251 | } 252 | 253 | for (byte j = 0; j < 40; j++) 254 | { 255 | if (pgm_read_byte(uhrptr + j) == pin) 256 | { 257 | pinleft = j; 258 | } 259 | } 260 | 261 | pinright = pgm_read_byte(uhrptr + pin); 262 | 263 | //these two need to be signed, see <0 below 264 | //char is signed -127..+128 265 | char plugright; 266 | char plugleft; 267 | 268 | plugright = (pinright - (EnigmaData.Uhr + 2)); 269 | if (plugright < 0) 270 | { 271 | plugright += 40; 272 | } 273 | plugright = plugright / 4; 274 | 275 | plugleft = (pinleft - (EnigmaData.Uhr + 2)); 276 | if (plugleft < 0) 277 | { 278 | plugleft += 40; 279 | } 280 | plugleft = plugleft / 4; 281 | 282 | EffSTECKER[EnigmaData.PAIRS[i * 2] - 65] = EnigmaData.PAIRS[pgm_read_byte(uhrplugptr + plugright) * 2 + 1]; 283 | EffSTECKER[EnigmaData.PAIRS[pgm_read_byte(uhrplugptr + i) * 2 + 1] - 65] = EnigmaData.PAIRS[plugleft * 2]; 284 | } 285 | } 286 | else 287 | { 288 | for (byte i = 0; i < 26; i++) 289 | { 290 | EffSTECKER[i] = EnigmaData.STECKER[i]; 291 | } 292 | } 293 | 294 | if (EnigmaData.SerialFunction == 1) 295 | { 296 | Serial.println(F("Stecker/Uhr:")); 297 | Serial.println(EffSTECKER); 298 | } 299 | } 300 | 301 | void MoveWheels() 302 | { 303 | byte i = 4; 304 | bool carry = true; 305 | 306 | do 307 | { 308 | i--; 309 | 310 | if (carry) 311 | { 312 | WHEELPOS[i]++; 313 | if (i > 1) 314 | { 315 | carry = IsCarry(EnigmaData.WHEELTYPE[4 - i], WHEELPOS[i]); 316 | } 317 | else 318 | { 319 | carry = false; 320 | } 321 | } 322 | else 323 | { 324 | // double stepping on second wheel 325 | if (i == 2) 326 | { 327 | byte w2 = WHEELPOS[2] + 1; 328 | 329 | if (w2 > 'Z') 330 | { 331 | w2 = 'A'; 332 | } 333 | 334 | if (IsCarry(EnigmaData.WHEELTYPE[2], w2)) 335 | { 336 | WHEELPOS[2]++; 337 | carry = true; 338 | } 339 | } 340 | } 341 | 342 | if (WHEELPOS[i] > 'Z') 343 | { 344 | WHEELPOS[i] = 'A'; 345 | carry = IsCarry(EnigmaData.WHEELTYPE[4 - i], WHEELPOS[i]) || carry; 346 | if (i == 1) 347 | { 348 | carry = false; 349 | } 350 | } 351 | 352 | } while (i > 0); 353 | 354 | } 355 | 356 | void ShowRotors() 357 | { 358 | const char PROGMEM *charptr = (const char PROGMEM *)WHEELSF; 359 | char k; 360 | INT16U wheeltype; 361 | 362 | if (EnigmaData.SerialFunction == 1) 363 | { 364 | Serial.println(F("Rotors:")); 365 | 366 | for (byte i = 0; i < 6; i++) 367 | { 368 | if (EnigmaData.WHEELTYPE[i] != 0) 369 | { 370 | switch (i) 371 | { 372 | case 0: 373 | { 374 | Serial.println(F("ETW")); 375 | break; 376 | } 377 | 378 | case 1: 379 | case 2: 380 | case 3: 381 | case 4: 382 | { 383 | Serial.print(F("R")); 384 | Serial.println((char)('0' + i)); 385 | break; 386 | } 387 | 388 | case 5: 389 | { 390 | Serial.println(F("UKW")); 391 | break; 392 | } 393 | } 394 | 395 | wheeltype = ((EnigmaData.WHEELTYPE[i] - 1) * 28) + 2; 396 | 397 | for (byte i = 0; i < 26; i++) 398 | { 399 | k = pgm_read_byte(charptr + wheeltype + i); 400 | Serial.print(k); 401 | } 402 | Serial.println(F("")); 403 | } 404 | } 405 | } 406 | } 407 | 408 | byte SerialMonitorStatus; 409 | 410 | void SerialMonitor(char k) 411 | { 412 | if (k == 0) 413 | { 414 | SerialMonitorStatus = 0; 415 | } 416 | else 417 | { 418 | if (EnigmaData.SerialFunction == 1) 419 | { 420 | SerialMonitorStatus++; 421 | 422 | //skip R4 if a three wheel machine 423 | if (((EnigmaData.WHEELTYPE[5] > 11) && (EnigmaData.WHEELTYPE[5] < 15)) && ((SerialMonitorStatus == 6) || (SerialMonitorStatus == 8))) 424 | { 425 | SerialMonitorStatus++; 426 | } 427 | 428 | Serial.print(k); 429 | 430 | switch (SerialMonitorStatus) 431 | { 432 | case 1: 433 | case 13: 434 | { 435 | Serial.print(F(">Stecker>")); 436 | break; 437 | } 438 | 439 | case 2: 440 | case 12: 441 | { 442 | Serial.print(F(">ETW>")); 443 | break; 444 | } 445 | 446 | case 3: 447 | case 11: 448 | { 449 | Serial.print(F(">R1>")); 450 | break; 451 | } 452 | 453 | case 4: 454 | case 10: 455 | { 456 | Serial.print(F(">R2>")); 457 | break; 458 | } 459 | 460 | case 5: 461 | case 9: 462 | { 463 | Serial.print(F(">R3>")); 464 | break; 465 | } 466 | 467 | case 6: 468 | case 8: 469 | { 470 | Serial.print(F(">R4>")); 471 | break; 472 | } 473 | 474 | case 7: 475 | { 476 | Serial.print(F(">UKW>")); 477 | break; 478 | } 479 | default: 480 | { 481 | Serial.println(F("")); 482 | } 483 | } 484 | } 485 | } 486 | } 487 | 488 | bool IsCarry(byte wheelType, byte wheelPos) 489 | { 490 | const char PROGMEM *charptr = (const char PROGMEM *)WHEELSF; 491 | INT16U wheeltype = (wheelType - 1) * 28; 492 | byte k1 = pgm_read_byte(charptr + wheeltype); 493 | byte k2 = pgm_read_byte(charptr + wheeltype + 1); 494 | bool v = false; 495 | 496 | if ((wheelPos == k1) || (wheelPos == k2)) 497 | { 498 | v = true; 499 | } 500 | 501 | return v; 502 | } 503 | 504 | char EncodeKey(char key) 505 | { 506 | const char PROGMEM *charptr = (const char PROGMEM *)WHEELSF; 507 | char k, k1; 508 | INT16U wheeltype; 509 | 510 | SerialMonitor(0); 511 | SerialMonitor(key); 512 | 513 | k = EffSTECKER[key - 'A']; 514 | 515 | SerialMonitor(k); 516 | 517 | for (byte i = 0; i < 6; i++) 518 | { 519 | if (EnigmaData.WHEELTYPE[i] != 0) 520 | { 521 | if ((i > 0) && (i < 5)) 522 | { 523 | byte p = WHEELPOS[4 - i] - (EnigmaData.ROTORPOS[4 - i] - 1); 524 | if (p < 'A') 525 | { 526 | p += 26; 527 | } 528 | 529 | k = k + (p - 'A'); 530 | } 531 | 532 | if (k > 'Z') 533 | { 534 | k = k - ('Z' + 1); 535 | } 536 | else 537 | { 538 | k = k - 'A'; 539 | } 540 | 541 | wheeltype = ((EnigmaData.WHEELTYPE[i] - 1) * 28) + k + 2; 542 | k = pgm_read_byte(charptr + wheeltype); 543 | 544 | if ((i > 0) && (i < 5)) 545 | { 546 | byte p = WHEELPOS[4 - i] - (EnigmaData.ROTORPOS[4 - i] - 1); 547 | if (p < 'A') 548 | { 549 | p += 26; 550 | } 551 | 552 | k = k - (p - 'A'); 553 | } 554 | 555 | if (k < 'A') 556 | { 557 | k = k + 26; 558 | } 559 | 560 | SerialMonitor(k); 561 | } 562 | } 563 | 564 | //after reflector 565 | 566 | for (byte i = 0; i < 5; i++) 567 | { 568 | if (EnigmaData.WHEELTYPE[4 - i] != 0) 569 | { 570 | if (i < 4) 571 | { 572 | byte p = WHEELPOS[i] - (EnigmaData.ROTORPOS[i] - 1); 573 | if (p < 'A') 574 | { 575 | p += 26; 576 | } 577 | 578 | k = k + (p - 'A'); 579 | } 580 | 581 | if (k > 'Z') 582 | { 583 | k = k - 26; 584 | } 585 | 586 | wheeltype = (EnigmaData.WHEELTYPE[4 - i] - 1) * 28; 587 | for (byte j = 0; j < 26; j++) 588 | { 589 | if ((pgm_read_byte(charptr + wheeltype + j + 2)) == k) 590 | { 591 | k1 = 'A' + j; 592 | } 593 | } 594 | 595 | k = k1; 596 | 597 | if (i < 4) 598 | { 599 | byte p = WHEELPOS[i] - (EnigmaData.ROTORPOS[i] - 1); 600 | if (p < 'A') 601 | { 602 | p += 26; 603 | } 604 | 605 | k = k - (p - 'A'); 606 | } 607 | 608 | if (k < 'A') 609 | { 610 | k = k + 26; 611 | } 612 | 613 | SerialMonitor(k); 614 | } 615 | 616 | } 617 | 618 | for (byte j = 0; j < 26; j++) 619 | { 620 | if (EffSTECKER[j] == k) 621 | { 622 | k1 = 'A' + j; 623 | } 624 | } 625 | k = k1; 626 | 627 | SerialMonitor(k); 628 | 629 | return k; 630 | } 631 | -------------------------------------------------------------------------------- /Examples/EnigmuinoEnigma.ino: -------------------------------------------------------------------------------- 1 | //this configuration decodes the encrypted texts at 2 | //http://forum.arduino.cc/index.php?topic=52283.0 3 | //after decoding the first text, issue the command !GMA to reset the wheels to the starting position of GMA again 4 | //then the reply text can be decoded 5 | 6 | #define STR_EXPAND(tok) #tok 7 | #define STR(tok) STR_EXPAND(tok) 8 | 9 | #ifndef INT16U 10 | #define INT16U unsigned short 11 | #endif 12 | 13 | // Rotor definitions, first two letters are the letter at which they rotate the one to the 14 | // left, the rest are the output given an input letter 15 | // rotors Beta & Gamma can only be used in the fourth position. 16 | // the wheels go as follow: 17 | // UKW,ROTOR,ROTOR,ROTOR,ROTOR,EKW 18 | // M3 19 | // byte WHEELTYPE[5] = {11, 1, 2, 3, 0, 12}; 20 | // M4 compatible with M3, set wheel 4 to A 21 | // byte WHEELTYPE[5] = {11, 1, 2, 3, 4, 12}; 22 | 23 | // ABCDEFGHIJKLMNOPQRSTUVWXYZ 24 | #define ROTOR1 R-EKMFLGDQVZNTOWYHXUSPAIBRCJ 25 | #define ROTOR2 F-AJDKSIRUXBLHWTMCQGZNPYFVOE 26 | #define ROTOR3 W-BDFHJLCPRTXVZNYEIWGAKMUSQO 27 | #define ROTOR4 K-ESOVPZJAYQUIRHXLNFTGKDCMWB 28 | #define ROTOR5 A-VZBRGITYUPSDNHLXAWMJQOFECK 29 | #define ROTOR6 ANJPGVOUMFYQBENHZRDKASXLICTW 30 | #define ROTOR7 ANNZJHGRCXMYSWBOUFAIVLPEKQDT 31 | #define ROTOR8 ANFKQHTLXOCBJSPDZRAMEWNIUYGV 32 | #define ROTORB --LEYJVCNIXWPBQMDRTAKZGFUHOS 33 | #define ROTORG --FSOKANUERHMBTIYCWLQPZXVGJD 34 | #define ETW --ABCDEFGHIJKLMNOPQRSTUVWXYZ 35 | #define UKWA --EJMZALYXVBWFCRQUONTSPIKHGD 36 | #define UKWB --YRUHQSLDPXNGOKMIEBFZCWVJAT 37 | #define UKWC --FVPJIAOYEDRZXWGCTKUQSBNMHL 38 | #define UKWBD --ENKQAUYWJICOPBLMDXZVFTHRGS 39 | #define UKWCD --RDOBJNTKVEHMLFCWZAXGYIPSUQ 40 | 41 | const __FlashStringHelper * WHEELSF; 42 | const __FlashStringHelper * UHRSF; 43 | const __FlashStringHelper * UHRPLUGSF; 44 | 45 | char EffSTECKER[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 46 | byte WHEELPOS[4] = {'A', 'A', 'A', 'A'}; 47 | 48 | // wheel types, first entry is for rightmost wheel, last is reflector 49 | // fifth entry can be 0 for a three rotor machine. 50 | //byte WHEELTYPE[6] = {11, 3, 2, 1, 0, 12}; 51 | //byte WHEELTYPE[6] = {11, 3, 2, 1, 9, 15}; 52 | 53 | //default M3 1939 in enigma simulator app 54 | //byte WHEELTYPE[6] = {11, 3, 2, 1, 0, 12}; 55 | //byte WHEELPOS[4] = {0, 'A', 'A', 'A'}; 56 | 57 | //default M4 1942 in enigma simulator app 58 | //byte WHEELTYPE[6] = {11, 3, 2, 1, 9, 15}; 59 | //byte WHEELPOS[4] = {'A', 'A', 'A', 'A'}; 60 | 61 | // test machine 62 | //byte WHEELTYPE[6] = {11, 1, 1, 1, 1, 15}; 63 | //byte WHEELPOS[4] = {'A', 'A', 'A', 'A'}; 64 | 65 | char KeyPressed = 0; 66 | char EncodedKey = 0; 67 | 68 | byte SerialRead = 0; 69 | byte SerialSetWheels = 0; 70 | 71 | struct enigmaData_t 72 | { 73 | byte SerialFunction; 74 | byte Uhr; 75 | char PAIRS[27]; 76 | char STECKER[27]; 77 | byte WHEELTYPE[6]; 78 | byte WHEELPOS[4]; 79 | byte ROTORPOS[4]; 80 | } 81 | EnigmaData; 82 | 83 | 84 | void initEnigma() 85 | { 86 | // set to 1 to monitor or 2 to display encoded character only 87 | EnigmaData.SerialFunction = 2; 88 | 89 | //ALL THE STEPS SHOWN BELOW MUST BE DONE TO INITIALIZE THE MACHINE 90 | 91 | //Rotor Types for an M4 machine, see more examples above 92 | EnigmaData.WHEELTYPE[0] = 11; // ENTRY CONTACTS: ETW 93 | EnigmaData.WHEELTYPE[1] = 8; // RIGHTMOST ROTOR 94 | EnigmaData.WHEELTYPE[2] = 2; // MIDDLE ROTOR 95 | EnigmaData.WHEELTYPE[3] = 3; // LEFT ROTOR 96 | EnigmaData.WHEELTYPE[4] = 0; // ADDITIONAL WHEEL (M4 only) 97 | EnigmaData.WHEELTYPE[5] = 14; // REFLECTOR: UKW 98 | 99 | //Wheel Positions 100 | EnigmaData.WHEELPOS[0] = 0; // LEFTMOST LETTER ON M4 101 | EnigmaData.WHEELPOS[1] = 'G'; // LEFTMOST LETTER ON M3 102 | EnigmaData.WHEELPOS[2] = 'M'; // MIDDLE LETTER 103 | EnigmaData.WHEELPOS[3] = 'A'; // RIGHTMOST LETTER 104 | 105 | //Ring Settings 106 | EnigmaData.ROTORPOS[0] = 0; // LEFTMOST ROTOR SETTING ON M4 107 | EnigmaData.ROTORPOS[1] = 'E'-64; // LEFTMOST ROTOR SETTING ON M3 108 | EnigmaData.ROTORPOS[2] = 'N'-64; // MIDDLE ROTOR SETTING 109 | EnigmaData.ROTORPOS[3] = 'I'-64; // RIGHTMOST ROTOR SETTING 110 | 111 | for (byte i = 0; i < 4; i++) 112 | { 113 | WHEELPOS[i] = EnigmaData.WHEELPOS[i]; 114 | } 115 | 116 | //Initialize stecker with no plugs 117 | RemoveAllPlugs(); 118 | 119 | //ADD ANY PLUG PAIRS HERE USING THE AddPlug function 120 | AddPlug('E', 'Q'); 121 | AddPlug('N', 'R'); 122 | AddPlug('I', 'S'); 123 | AddPlug('G', 'T'); 124 | AddPlug('M', 'U'); 125 | AddPlug('A', 'V'); 126 | 127 | // set the UHR (non zero values used only if 10 plug pairs are installed) 128 | EnigmaData.Uhr = 0; 129 | CalculateUhrStecker(); 130 | } 131 | 132 | void setup() 133 | { 134 | Serial.begin(9600); 135 | 136 | WHEELSF = F(STR(ROTOR1) STR(ROTOR2) STR(ROTOR3) STR(ROTOR4) STR(ROTOR5) STR(ROTOR6) STR(ROTOR7) STR(ROTOR8) STR(ROTORB) STR(ROTORG) STR(ETW) STR(UKWA) STR(UKWB) STR(UKWC) STR(UKWBD) STR(UKWCD)); 137 | UHRSF = F("\x06\x1F\x04\x1D\x12\x27\x10\x19\x1E\x17\x1C\x01\x26\x0B\x24\x25\x1A\x1B\x18\x15\x0E\x03\x0C\x11\x02\x07\x00\x21\x0A\x23\x08\x05\x16\x13\x14\x0D\x22\x0F\x20\x09"); 138 | UHRPLUGSF = F("\x06\x00\x07\x05\x01\x08\x04\x02\x09\x03"); 139 | 140 | initEnigma(); 141 | ShowRotors(); 142 | } 143 | 144 | 145 | void loop() 146 | { 147 | if (Serial.available()) 148 | { 149 | KeyPressed = Serial.read(); 150 | 151 | if (KeyPressed == '!') 152 | { 153 | if (EnigmaData.WHEELTYPE[4] == 0) 154 | { 155 | SerialSetWheels = 3; 156 | } 157 | else 158 | { 159 | SerialSetWheels = 4; 160 | } 161 | } 162 | 163 | KeyPressed = KeyPressed & (255 - 32); 164 | 165 | if ((KeyPressed > 'A' - 1) && (KeyPressed < 'Z' + 1)) 166 | { 167 | SerialRead = 1; 168 | if (SerialSetWheels) 169 | { 170 | if (WHEELPOS[4 - SerialSetWheels] != KeyPressed) 171 | { 172 | WHEELPOS[4 - SerialSetWheels] = KeyPressed; 173 | } 174 | SerialSetWheels--; 175 | } 176 | else 177 | { 178 | MoveWheels(); 179 | EncodedKey = EncodeKey(KeyPressed); 180 | if (EnigmaData.SerialFunction == 2) 181 | { 182 | Serial.print(EncodedKey); 183 | } 184 | } 185 | } 186 | } 187 | 188 | if ((SerialRead) && (!Serial.available())) 189 | { 190 | SerialRead = 0; 191 | } 192 | } 193 | 194 | byte SteckerPairs() 195 | { 196 | byte c = 0; 197 | 198 | for (byte i = 0; i < 26; i++) 199 | { 200 | if (EnigmaData.STECKER[i] != (65 + i)) 201 | { 202 | c++; 203 | } 204 | } 205 | 206 | return (c / 2); 207 | } 208 | 209 | void RemoveAllPlugs() 210 | { 211 | for (byte i = 0; i < 27; i++) 212 | { 213 | EnigmaData.PAIRS[i] = 0; 214 | } 215 | 216 | strcpy(EnigmaData.STECKER, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); 217 | EnigmaData.Uhr = 0; 218 | } 219 | 220 | void AddPlug(char PlugKey1, char PlugKey2) 221 | { 222 | if ((SteckerPairs() < 13) && (PlugKey1 != PlugKey2)) 223 | { 224 | EnigmaData.PAIRS[SteckerPairs() * 2] = PlugKey1; 225 | EnigmaData.PAIRS[SteckerPairs() * 2 + 1] = PlugKey2; 226 | } 227 | 228 | EnigmaData.STECKER[PlugKey1 - 65] = PlugKey2; 229 | EnigmaData.STECKER[PlugKey2 - 65] = PlugKey1; 230 | } 231 | 232 | void CalculateUhrStecker() 233 | { 234 | const char PROGMEM *uhrptr = (const char PROGMEM *)UHRSF; 235 | const char PROGMEM *uhrplugptr = (const char PROGMEM *)UHRPLUGSF; 236 | 237 | byte ndx = 0; 238 | 239 | if (SteckerPairs() == 10) 240 | { 241 | for (byte i = 0; i < 26; i++) 242 | { 243 | EffSTECKER[i] = 65 + i; 244 | } 245 | 246 | for (byte i = 0; i < 10; i++) 247 | { 248 | byte pin = 0; 249 | byte pinright = 0; 250 | byte pinleft = 0; 251 | 252 | pin = EnigmaData.Uhr + i * 4; 253 | if (pin > 39) 254 | { 255 | pin -= 40; 256 | } 257 | 258 | for (byte j = 0; j < 40; j++) 259 | { 260 | if (pgm_read_byte(uhrptr + j) == pin) 261 | { 262 | pinleft = j; 263 | } 264 | } 265 | 266 | pinright = pgm_read_byte(uhrptr + pin); 267 | 268 | //these two need to be signed, see <0 below 269 | //char is signed -127..+128 270 | char plugright; 271 | char plugleft; 272 | 273 | plugright = (pinright - (EnigmaData.Uhr + 2)); 274 | if (plugright < 0) 275 | { 276 | plugright += 40; 277 | } 278 | plugright = plugright / 4; 279 | 280 | plugleft = (pinleft - (EnigmaData.Uhr + 2)); 281 | if (plugleft < 0) 282 | { 283 | plugleft += 40; 284 | } 285 | plugleft = plugleft / 4; 286 | 287 | EffSTECKER[EnigmaData.PAIRS[i * 2] - 65] = EnigmaData.PAIRS[pgm_read_byte(uhrplugptr + plugright) * 2 + 1]; 288 | EffSTECKER[EnigmaData.PAIRS[pgm_read_byte(uhrplugptr + i) * 2 + 1] - 65] = EnigmaData.PAIRS[plugleft * 2]; 289 | } 290 | } 291 | else 292 | { 293 | for (byte i = 0; i < 26; i++) 294 | { 295 | EffSTECKER[i] = EnigmaData.STECKER[i]; 296 | } 297 | } 298 | 299 | if (EnigmaData.SerialFunction == 1) 300 | { 301 | Serial.println(F("Stecker/Uhr:")); 302 | Serial.println(EffSTECKER); 303 | } 304 | } 305 | 306 | void MoveWheels() 307 | { 308 | byte i = 4; 309 | bool carry = true; 310 | 311 | do 312 | { 313 | i--; 314 | 315 | if (carry) 316 | { 317 | WHEELPOS[i]++; 318 | if (i > 1) 319 | { 320 | carry = IsCarry(EnigmaData.WHEELTYPE[4 - i], WHEELPOS[i]); 321 | } 322 | else 323 | { 324 | carry = false; 325 | } 326 | } 327 | else 328 | { 329 | // double stepping on second wheel 330 | if (i == 2) 331 | { 332 | byte w2 = WHEELPOS[2] + 1; 333 | 334 | if (w2 > 'Z') 335 | { 336 | w2 = 'A'; 337 | } 338 | 339 | if (IsCarry(EnigmaData.WHEELTYPE[2], w2)) 340 | { 341 | WHEELPOS[2]++; 342 | carry = true; 343 | } 344 | } 345 | } 346 | 347 | if (WHEELPOS[i] > 'Z') 348 | { 349 | WHEELPOS[i] = 'A'; 350 | carry = IsCarry(EnigmaData.WHEELTYPE[4 - i], WHEELPOS[i]) || carry; 351 | if (i == 1) 352 | { 353 | carry = false; 354 | } 355 | } 356 | 357 | } while (i > 0); 358 | 359 | } 360 | 361 | void ShowRotors() 362 | { 363 | const char PROGMEM *charptr = (const char PROGMEM *)WHEELSF; 364 | char k; 365 | INT16U wheeltype; 366 | 367 | if (EnigmaData.SerialFunction == 1) 368 | { 369 | Serial.println(F("Rotors:")); 370 | 371 | for (byte i = 0; i < 6; i++) 372 | { 373 | if (EnigmaData.WHEELTYPE[i] != 0) 374 | { 375 | switch (i) 376 | { 377 | case 0: 378 | { 379 | Serial.println(F("ETW")); 380 | break; 381 | } 382 | 383 | case 1: 384 | case 2: 385 | case 3: 386 | case 4: 387 | { 388 | Serial.print(F("R")); 389 | Serial.println((char)('0' + i)); 390 | break; 391 | } 392 | 393 | case 5: 394 | { 395 | Serial.println(F("UKW")); 396 | break; 397 | } 398 | } 399 | 400 | wheeltype = ((EnigmaData.WHEELTYPE[i] - 1) * 28) + 2; 401 | 402 | for (byte i = 0; i < 26; i++) 403 | { 404 | k = pgm_read_byte(charptr + wheeltype + i); 405 | Serial.print(k); 406 | } 407 | Serial.println(F("")); 408 | } 409 | } 410 | } 411 | } 412 | 413 | byte SerialMonitorStatus; 414 | 415 | void SerialMonitor(char k) 416 | { 417 | if (k == 0) 418 | { 419 | SerialMonitorStatus = 0; 420 | } 421 | else 422 | { 423 | if (EnigmaData.SerialFunction == 1) 424 | { 425 | SerialMonitorStatus++; 426 | 427 | //skip R4 if a three wheel machine 428 | if (((EnigmaData.WHEELTYPE[5] > 11) && (EnigmaData.WHEELTYPE[5] < 15)) && ((SerialMonitorStatus == 6) || (SerialMonitorStatus == 8))) 429 | { 430 | SerialMonitorStatus++; 431 | } 432 | 433 | Serial.print(k); 434 | 435 | switch (SerialMonitorStatus) 436 | { 437 | case 1: 438 | case 13: 439 | { 440 | Serial.print(F(">Stecker>")); 441 | break; 442 | } 443 | 444 | case 2: 445 | case 12: 446 | { 447 | Serial.print(F(">ETW>")); 448 | break; 449 | } 450 | 451 | case 3: 452 | case 11: 453 | { 454 | Serial.print(F(">R1>")); 455 | break; 456 | } 457 | 458 | case 4: 459 | case 10: 460 | { 461 | Serial.print(F(">R2>")); 462 | break; 463 | } 464 | 465 | case 5: 466 | case 9: 467 | { 468 | Serial.print(F(">R3>")); 469 | break; 470 | } 471 | 472 | case 6: 473 | case 8: 474 | { 475 | Serial.print(F(">R4>")); 476 | break; 477 | } 478 | 479 | case 7: 480 | { 481 | Serial.print(F(">UKW>")); 482 | break; 483 | } 484 | default: 485 | { 486 | Serial.println(F("")); 487 | } 488 | } 489 | } 490 | } 491 | } 492 | 493 | bool IsCarry(byte wheelType, byte wheelPos) 494 | { 495 | const char PROGMEM *charptr = (const char PROGMEM *)WHEELSF; 496 | INT16U wheeltype = (wheelType - 1) * 28; 497 | byte k1 = pgm_read_byte(charptr + wheeltype); 498 | byte k2 = pgm_read_byte(charptr + wheeltype + 1); 499 | bool v = false; 500 | 501 | if ((wheelPos == k1) || (wheelPos == k2)) 502 | { 503 | v = true; 504 | } 505 | 506 | return v; 507 | } 508 | 509 | char EncodeKey(char key) 510 | { 511 | const char PROGMEM *charptr = (const char PROGMEM *)WHEELSF; 512 | char k, k1; 513 | INT16U wheeltype; 514 | 515 | SerialMonitor(0); 516 | SerialMonitor(key); 517 | 518 | k = EffSTECKER[key - 'A']; 519 | 520 | SerialMonitor(k); 521 | 522 | for (byte i = 0; i < 6; i++) 523 | { 524 | if (EnigmaData.WHEELTYPE[i] != 0) 525 | { 526 | if ((i > 0) && (i < 5)) 527 | { 528 | byte p = WHEELPOS[4 - i] - (EnigmaData.ROTORPOS[4 - i] - 1); 529 | if (p < 'A') 530 | { 531 | p += 26; 532 | } 533 | 534 | k = k + (p - 'A'); 535 | } 536 | 537 | if (k > 'Z') 538 | { 539 | k = k - ('Z' + 1); 540 | } 541 | else 542 | { 543 | k = k - 'A'; 544 | } 545 | 546 | wheeltype = ((EnigmaData.WHEELTYPE[i] - 1) * 28) + k + 2; 547 | k = pgm_read_byte(charptr + wheeltype); 548 | 549 | if ((i > 0) && (i < 5)) 550 | { 551 | byte p = WHEELPOS[4 - i] - (EnigmaData.ROTORPOS[4 - i] - 1); 552 | if (p < 'A') 553 | { 554 | p += 26; 555 | } 556 | 557 | k = k - (p - 'A'); 558 | } 559 | 560 | if (k < 'A') 561 | { 562 | k = k + 26; 563 | } 564 | 565 | SerialMonitor(k); 566 | } 567 | } 568 | 569 | //after reflector 570 | 571 | for (byte i = 0; i < 5; i++) 572 | { 573 | if (EnigmaData.WHEELTYPE[4 - i] != 0) 574 | { 575 | if (i < 4) 576 | { 577 | byte p = WHEELPOS[i] - (EnigmaData.ROTORPOS[i] - 1); 578 | if (p < 'A') 579 | { 580 | p += 26; 581 | } 582 | 583 | k = k + (p - 'A'); 584 | } 585 | 586 | if (k > 'Z') 587 | { 588 | k = k - 26; 589 | } 590 | 591 | wheeltype = (EnigmaData.WHEELTYPE[4 - i] - 1) * 28; 592 | for (byte j = 0; j < 26; j++) 593 | { 594 | if ((pgm_read_byte(charptr + wheeltype + j + 2)) == k) 595 | { 596 | k1 = 'A' + j; 597 | } 598 | } 599 | 600 | k = k1; 601 | 602 | if (i < 4) 603 | { 604 | byte p = WHEELPOS[i] - (EnigmaData.ROTORPOS[i] - 1); 605 | if (p < 'A') 606 | { 607 | p += 26; 608 | } 609 | 610 | k = k - (p - 'A'); 611 | } 612 | 613 | if (k < 'A') 614 | { 615 | k = k + 26; 616 | } 617 | 618 | SerialMonitor(k); 619 | } 620 | 621 | } 622 | 623 | for (byte j = 0; j < 26; j++) 624 | { 625 | if (EffSTECKER[j] == k) 626 | { 627 | k1 = 'A' + j; 628 | } 629 | } 630 | k = k1; 631 | 632 | SerialMonitor(k); 633 | 634 | return k; 635 | } 636 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 arduinoenigma 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ArduinoEnigmaEngineAndUhr 2 | A FOSS Enigma encryption engine for the Arduino Platform. Implements the Enigma I, M3, M4 machines, the Plugboard and the Uhr Switch 3 | --------------------------------------------------------------------------------