@ondoher/enigma 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,170 @@
1
+ import Encoder from "./Encoder.js";
2
+
3
+ /**
4
+ * Create an instance of this class to construct a Rotor object. The Rotor class
5
+ * encapsulates many of the peculiar behaviors of the Enigma. All connector
6
+ * values here are specified in physical space.
7
+ */
8
+ export default class Rotor extends Encoder {
9
+
10
+ /*
11
+
12
+ - **name**
13
+ - **settings**
14
+ - _alphabet_ (optional)
15
+ - _map_
16
+ - _ringSetting_
17
+ - _turnovers_
18
+
19
+ */
20
+
21
+
22
+
23
+
24
+
25
+ /**
26
+ * This is the constructor for the rotor.
27
+ *
28
+ * @param {String} name the name of the rotor; under normal circumstances
29
+ * this will be the string 'rotor-' plus the standard name for the rotor,
30
+ * for example 'rotor-IV'
31
+ * @param {Object} settings an object that contains the various options that
32
+ * define the the rotor and how it is configured.
33
+ * @property [alphabet] set this to a string of letters that are an
34
+ * alternative to the standard A-Z. Defaults to A-Z
35
+ * @property {String} map a string that defines the mapping between the
36
+ * input and output connectors. The index into the string is the input
37
+ * connector and the value of this string at that index is the output
38
+ * connector. For example 'EKMFLGDQVZNTOWYHXUSPAIBRCJ', which is the map
39
+ * for standard rotor I.
40
+ * @property {Number} [ringSetting] a number that specifies how far forward
41
+ * to offset the outer ring relative to the internal wiring.
42
+ * @property {String} turnovers a string that specifies the relative
43
+ * location of where on the rotor turnover will occur. The value here is the
44
+ * rotation value would be displayed in the window when turnover happens,
45
+ * expressed as a character. The standard rotors VI-VIII, available in the
46
+ * later model M3 had two turnover locations, M and Z. Pass an empty string
47
+ * when the rotor does not rotate during stepping
48
+ */
49
+ constructor(name, settings) {
50
+ super(name, settings);
51
+ var { map, turnovers = '', ringSetting = 0} = settings
52
+
53
+ this.map = [...map];
54
+ this.rightMap = this.makeMap(map);
55
+ this.leftMap = this.makeReverseMap(this.rightMap);
56
+ this.length = map.length;
57
+ this.ringOffset = ringSetting;
58
+
59
+ this.turnoverLookup = this.makeMap(turnovers);
60
+ this.offset = 0;
61
+ if (turnovers === '') this.fixed = true;
62
+ this.turnovers = this.turnoverLookup.reduce(function(turnovers, turnover) {
63
+ turnovers[turnover] = true;
64
+ return turnovers;
65
+ }.bind(this), {});
66
+ }
67
+
68
+ /**
69
+ * Call this method to select the initial rotation of the rotor. This is a
70
+ * letter offset from the logical 0 connector. The initial rotation will
71
+ * also take into account the ring setting
72
+ *
73
+ * @param {String} connector This is a letter value that corresponds to what
74
+ * would appear in the rotation window. This value will be adjusted for the
75
+ * ring setting.
76
+ */
77
+ setStartPosition(connector) {
78
+ var pos = this.alphabet.indexOf(connector);
79
+ this.offset = this.normalize(pos - this.ringOffset);
80
+ }
81
+
82
+ /**
83
+ * Call this method to map an input connector to an output connector when
84
+ * the signal is moving in the given direction. The input connector
85
+ * represents a physical location in real space. To get the logical
86
+ * connector for the rotor's zero point we need to adjust the connector
87
+ * number for the current rotation.
88
+ *
89
+ * @param {String} direction either right for moving towards the reflector or
90
+ * left if moving back
91
+ * @param {Number} input the connector in physical space
92
+ *
93
+ * @returns {Number} the output connector in physical space.
94
+ */
95
+ encode(direction, input) {
96
+ var map = direction === 'right' ? this.rightMap : this.leftMap;
97
+ var evName = direction === 'right' ? 'encode-right' : 'encode-left';
98
+
99
+ //find the logical position of the input connector in the wiring map
100
+ var index = this.normalize(input + this.offset);
101
+
102
+ // get the logical output connector and convert that to the physical
103
+ // output connector
104
+ var output = map[index];
105
+ var result = this.normalize(output - this.offset);
106
+
107
+ this.fire(evName, this.name,
108
+ `${evName} ${this.name}, input: ${input} ouput: ${result} relative input: ${index}, relative output: ${output} rotation: ${this.offset}`,
109
+ {
110
+ input : input,
111
+ output: result,
112
+ logicalInput: index,
113
+ logicalOutput: output,
114
+ rotation: this.offset,
115
+ }
116
+ );
117
+
118
+ return result;
119
+ }
120
+
121
+ /**
122
+ * Call this method to step the rotor
123
+ *
124
+ * @returns {Boolean} true true if the next rotor should be stepped
125
+ */
126
+ step() {
127
+ // Because the turnover notch is attached to the outer ring, and the
128
+ // logical coordinates is based on the wiring, the logical position of
129
+ // the notch for turnover needs to be adjusted to remove the ring offset.
130
+ this.offset = this.normalize(this.offset + 1);
131
+ var turnoverOffset = this.normalize(this.offset + this.ringOffset);
132
+
133
+ // turnover happens when we step past the turnover point
134
+ var turnover = this.turnovers[this.normalize(turnoverOffset - 1)];
135
+
136
+ this.fire('step', this.name,
137
+ `step ${this.name}, ${this.offset} ${this.normalize(this.offset + this.ringOffset)} ${turnoverOffset} ${Boolean(turnover)}`,
138
+ {
139
+ rotation: this.offset,
140
+ ringSetting: this.ringOffset,
141
+ turnover: Boolean(turnover),
142
+ }
143
+ );
144
+
145
+ return turnover;
146
+ }
147
+
148
+ /**
149
+ * Call this method to see if the next step on this rotor will lead to
150
+ * turnover. The Enigma class will call this on the middle rotor to handle
151
+ * double stepping.
152
+ *
153
+ * @returns true if this rotor will turnover on the next step
154
+ */
155
+ willTurnover() {
156
+ var turnoverOffset = this.normalize(this.offset + this.ringOffset);
157
+
158
+ // double stepping happens when we step to the turnover point
159
+ return this.turnovers[turnoverOffset];
160
+ }
161
+
162
+ /**
163
+ * Call this method to find whether this is a fixed rotor. This is used for
164
+ * the non stepping rotors--beta and gamma--that are used in the M4
165
+ * @returns
166
+ */
167
+ isFixed() {
168
+ return this.fixed;
169
+ }
170
+ }
@@ -0,0 +1 @@
1
+ export var STANDARD_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
@@ -0,0 +1,7 @@
1
+ export {default as Enigma} from './Enigma.js';
2
+ export {default as EntryDisc} from './EntryDisk.js';
3
+ export {default as inventory} from './Inventory.js';
4
+ export {default as PlugBoard} from './PlugBoard.js';
5
+ export {default as Reflector} from './Rotor.js';
6
+
7
+ import './standardInventory.js'
@@ -0,0 +1,95 @@
1
+ import inventory from'./Inventory.js';
2
+
3
+ /**
4
+ * This module adds all the standard inventory components to simulate models
5
+ * I, M3 and M4
6
+ */
7
+
8
+ export var entryDiscDefintions = {
9
+ default: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
10
+ };
11
+
12
+ export var rotorDefinitions = {
13
+ I: {
14
+ map: 'EKMFLGDQVZNTOWYHXUSPAIBRCJ', //p->q
15
+ turnovers: 'Q'
16
+ },
17
+ II: {
18
+ map: 'AJDKSIRUXBLHWTMCQGZNPYFVOE', //d->e
19
+ turnovers: 'E'
20
+ },
21
+ III: {
22
+ map: 'BDFHJLCPRTXVZNYEIWGAKMUSQO', // u->v
23
+ turnovers: 'V'
24
+ },
25
+ IV: {
26
+ map: 'ESOVPZJAYQUIRHXLNFTGKDCMWB', // i-> j
27
+ turnovers: 'J'
28
+ },
29
+
30
+ V: {
31
+ map: 'VZBRGITYUPSDNHLXAWMJQOFECK', //y->z
32
+ turnovers: 'Z'
33
+ },
34
+
35
+ VI: {
36
+ map: 'JPGVOUMFYQBENHZRDKASXLICTW', // l->m, y-z
37
+ turnovers: 'ZM'
38
+ },
39
+
40
+ VII: {
41
+ map: 'NZJHGRCXMYSWBOUFAIVLPEKQDT', //l-m
42
+ turnovers: 'ZM'
43
+ },
44
+
45
+ VIII: {
46
+ map: 'FKQHTLXOCBJSPDZRAMEWNIUYGV',
47
+ turnovers: 'ZM'
48
+ },
49
+
50
+ Beta: {
51
+ map: 'LEYJVCNIXWPBQMDRTAKZGFUHOS',
52
+ turnovers: ''
53
+ },
54
+ Gamma: {
55
+ map: 'FSOKANUERHMBTIYCWLQPZXVGJD',
56
+ turnovers: ''
57
+ }
58
+ };
59
+
60
+ export var reflectorDefinitions = {
61
+ A: 'EJMZALYXVBWFCRQUONTSPIKHGD',
62
+ B: 'YRUHQSLDPXNGOKMIEBFZCWVJAT',
63
+ C: 'FVPJIAOYEDRZXWGCTKUQSBNMHL',
64
+ 'Thin-B': 'ENKQAUYWJICOPBLMDXZVFTHRGS',
65
+ 'Thin-C': 'RDOBJNTKVEHMLFCWZAXGYIPSUQ'
66
+ };
67
+
68
+
69
+ function addRotor(name) {
70
+ inventory.addRotor(name, rotorDefinitions[name].map, rotorDefinitions[name].turnovers);;
71
+ }
72
+
73
+ function addReflector(name) {
74
+ inventory.addReflector(name, reflectorDefinitions[name]);
75
+ }
76
+
77
+ inventory.addEntryDisc('default', entryDiscDefintions.default);
78
+
79
+ addRotor('I');
80
+ addRotor('II');
81
+ addRotor('III');
82
+ addRotor('IV');
83
+ addRotor('V');
84
+ addRotor('VI');
85
+ addRotor('VII');
86
+ addRotor('VIII');
87
+
88
+ addRotor('Beta');
89
+ addRotor('Gamma');
90
+
91
+ addReflector('A');
92
+ addReflector('B');
93
+ addReflector('C');
94
+ addReflector('Thin-B');
95
+ addReflector('Thin-C');
@@ -0,0 +1,236 @@
1
+ export const enigmaData = {
2
+ sampleFieldMessages: [
3
+ {
4
+ source: 'http://wiki.franklinheath.co.uk/index.php/Enigma/Sample_Decrypts#Operation_Barbarossa.2C_1941',
5
+ model: 'I/M3',
6
+ setup: {
7
+ reflector: 'B',
8
+ rotors: ['II', 'IV', 'V'],
9
+ ringSettings: [2, 21, 12],
10
+ plugs: 'AV BS CG DL FU HZ IN KM OW RX'
11
+ },
12
+ message: {
13
+ key: 'BLA',
14
+ encoded: 'EDPUDNRGYSZRCXNUYTPOMRMBOFKTBZREZKMLXLVEFGUEYSIOZVEQMIKUBPMMYLKLTTDEISMDICAGYKUACTCDOMOHWXMUUIAUBSTSLRNBZSZWNRFXWFYSSXJZVIJHIDISHPRKLKAYUPADTXQSPINQMATLPIFSVKDASCTACDPBOPVHJK',
15
+ decoded: 'AUFKLXABTEILUNGXVONXKURTINOWAXKURTINOWAXNORDWESTLXSEBEZXSEBEZXUAFFLIEGERSTRASZERIQTUNGXDUBROWKIXDUBROWKIXOPOTSCHKAXOPOTSCHKAXUMXEINSAQTDREINULLXUHRANGETRETENXANGRIFFXINFXRGTX',
16
+ }
17
+ },
18
+ {
19
+ source: 'http://wiki.franklinheath.co.uk/index.php/Enigma/Sample_Messages#U-264_.28Kapit.C3.A4nleutnant_Hartwig_Looks.29.2C_1942',
20
+ model: 'M4',
21
+ setup: {
22
+ reflector: 'Thin-B',
23
+ rotors: ['Beta', 'II', 'IV', 'I'],
24
+ ringSettings: [1, 1, 1, 22],
25
+ plugs: 'AT BL DF GJ HM NW OP QY RZ VX',
26
+ },
27
+ message: {
28
+ key: 'VJNA',
29
+ encoded: 'NCZWVUSXPNYMINHZXMQXSFWXWLKJAHSHNMCOCCAKUQPMKCSMHKSEINJUSBLKIOSXCKUBHMLLXCSJUSRRDVKOHULXWCCBGVLIYXEOAHXRHKKFVDREWEZLXOBAFGYUJQUKGRTVUKAMEURBVEKSUHHVOYHABCJWMAKLFKLMYFVNRIZRVVRTKOFDANJMOLBGFFLEOPRGTFLVRHOWOPBEKVWMUQFMPWPARMFHAGKXIIBG',
30
+ decoded: 'VONVONJLOOKSJHFFTTTEINSEINSDREIZWOYYQNNSNEUNINHALTXXBEIANGRIFFUNTERWASSERGEDRUECKTYWABOSXLETZTERGEGNERSTANDNULACHTDREINULUHRMARQUANTONJOTANEUNACHTSEYHSDREIYZWOZWONULGRADYACHTSMYSTOSSENACHXEKNSVIERMBFAELLTYNNNNNNOOOVIERYSICHTEINSNULL',
31
+ }
32
+ },
33
+ {
34
+ source: 'http://wiki.franklinheath.co.uk/index.php/Enigma/Sample_Messages#Scharnhorst_.28Konteradmiral_Erich_Bey.29.2C_1943',
35
+ model: 'M3',
36
+ setup: {
37
+ reflector: 'B',
38
+ rotors: ['III', 'VI', 'VIII'],
39
+ ringSettings: [1, 8, 13],
40
+ plugs: 'AN EZ HK IJ LR MQ OT PV SW UX',
41
+ },
42
+ message: {
43
+ key: 'UZV',
44
+ encoded: 'YKAENZAPMSCHZBFOCUVMRMDPYCOFHADZIZMEFXTHFLOLPZLFGGBOTGOXGRETDWTJIQHLMXVJWKZUASTR',
45
+ decoded: 'STEUEREJTANAFJORDJANSTANDORTQUAAACCCVIERNEUNNEUNZWOFAHRTZWONULSMXXSCHARNHORSTHCO',
46
+ }
47
+ },
48
+ {
49
+ source: 'https://enigma.hoerenberg.com/index.php?cat=The%20U534%20messages&page=P1030662',
50
+ model: 'M4',
51
+ setup: {
52
+ reflector: 'Thin-C',
53
+ rotors: ['Beta', 'V', 'VI', 'VIII'],
54
+ ringSettings: 'AAEL',
55
+ plugs: 'AE BF CM DQ HU JN LX PR SZ VW',
56
+ },
57
+ message: {
58
+ key: 'WIIJ',
59
+ encoded: 'LIRZMLWRCDMSNKLKBEBHRMFQFEQAZWXBGBIEXJPYFCQAAWSEKDEACOHDZKCZTOVSYHFNSCMAIMIMMAVJNLFXEWNPUIRINOZNCRVDHCGKCYRVUJQPVKEUIVVXGLQMKRJMDMLXLLRLYBKJWRXBQRZWGCCNDOPMGCKJ',
60
+ decoded: 'UUUVIRSIBENNULEINSYNACHRXUUUSTUETZPUNKTLUEBECKVVVCHEFVIERXUUUFLOTTXXMITUUUVIERSIBENNULZWOUNDUUUVIERSIBENNULDREIZURFLENDERWERFTLUEBECKGEHENXFONDORTFOLGTWEITERESX',
61
+ }
62
+ },
63
+ {
64
+ source: 'https://enigma.hoerenberg.com/index.php?cat=Norrk%C3%B6ping%20messages&page=PAGE_47_DOEP',
65
+ model: 'M3',
66
+ setup: {
67
+ reflector: 'B',
68
+ rotors: ['VII', 'IV', 'VI'],
69
+ ringSettings: 'AGW',
70
+ plugs: 'BM DX EW GP JO KV NZ RT',
71
+ },
72
+ message: {
73
+ key: 'NSH',
74
+ encoded: 'YEWZANTGDXWUVDSSYQELAMUOAMBVFZAJWFATABRMMBWXWTLFIOYBTEXXFFAOHADDXWWGBEROYDWLEUTP',
75
+ decoded: 'KOFFERGRAMOPHONKEINSINNKTZCMYQWPJDZXQLXGJXKWXLQDHYKCMIRBYKFHCMQWHVXLRHGDXMQWCHYK',
76
+ }
77
+ },
78
+ {
79
+ source: 'https://enigma.hoerenberg.com/index.php?cat=Norrk%C3%B6ping%20messages&page=PAGE_49_KRLR',
80
+ model: 'M3',
81
+ setup: {
82
+ reflector: 'B',
83
+ rotors: ['VII', 'IV', 'VI'],
84
+ ringSettings: 'AGW',
85
+ plugs: 'BM DX EW GP JO KV NZ RT',
86
+ },
87
+ message: {
88
+ key: 'RPR',
89
+ encoded: 'PBQOMEWLLMJFBXKPZNBHRGLUGVHJBXYPSEACOXOTBQRWVTPVVYHLLDOCQQKIWVAMJNFADSUNAVMJGJIBMUGBWWRKJBZNHVELOGZHTISLTUWS',
90
+ decoded: 'VERWALTUNGSAMTREICHSGERICHTARBEITSLAGERNICHTAUFSCHLAGENVCNSTDMQWZVGNVMBCPDGKPFQZWTRLDMFNGHSRDTFZGLDKCVLMNHGF',
91
+
92
+ }
93
+
94
+ }
95
+ ],
96
+ sampleVerifiedMessages: [
97
+ {
98
+ verified: ['https://cryptii.com/pipes/enigma-machine', ],
99
+ model: 'I',
100
+ setup: {
101
+ rotors: ['II', 'IV', 'III'],
102
+ plugs: 'IU ZM NK YH SJ DB TX RF OG QE',
103
+ ringSettings: [22, 26, 26],
104
+ reflector: 'A'
105
+ },
106
+ message: {
107
+ key: 'ZAE',
108
+ encoded: 'EICSSVSACTFYCNWRBCXMELAKMTBDSSPAIHMUKGFDPVEUHUDWRKOTITUTNWCEJTGUUGVVBOSVOYIDXHBRFYNOAJWISOZDIOPIXJDJJXBUYJWQRMMACUDGZCVHIFPRPCUDDWTXLCEUEASBRVOUFRTQDDOWWGCIEQSAYEXYHLCJHKWRMNQUHERAEGUXBQQDWIZYQHFJZRBZBNGWPUGLUYMUCXFKPPBWXAPRRXZLWBOFPWQHKVXWKHTNJXQCZZROWMYPLSMJINVBUCIPVYZGZXMONPMEIFWALQFEKJRRJYXVRNUFWNMPMIYBCQCJNSLNHIHOESEVNFMBKPPQTWQXQMCKIMQNPGOOTKNJDBKKHTWDUSJJGTSFJJLQ',
109
+ decoded: 'HOWOTHERWISETHEKINGSIRHATHLAIDTHATINADOZENPASSESBETWEENYOURSELFANDHIMHESHALLNOTEXCEEDYOUTHREEHITSHEHATHLAIDONTWELVEFORNINEANDITWOULDCOMETOIMMEDIATETRIALIFYOURLORDSHIPWOULDVOUCHSAFETHEANSWERBYTHELORDHORATIOTHESETHREEYEARSIHAVETAKENANOTEOFITTHEAGEISGROWNSOPICKEDTHATTHETOEOFTHEPEASANTCOMESSONEARTHEHEELOFTHECOURTIERHEGAFFSHISKIBETHYSTATEISTHEMOREGRACIOUSFORTISAVICETOKNOWHIM'
110
+ }
111
+
112
+ },
113
+ {
114
+ verified: ['https://cryptii.com/pipes/enigma-machine', 'http://people.physik.hu-berlin.de/~palloks/js/enigma/enigma-u_v26_en.html'],
115
+ model: 'I',
116
+ setup: {
117
+ rotors: ['III', 'IV', 'I'],
118
+ plugs: 'EL ID YR QP FX HO KJ NS BV WU',
119
+ ringSettings: [10, 22, 8],
120
+ reflector: 'B'
121
+ },
122
+ message: {
123
+ key: 'OAK',
124
+ encoded: 'RXDVNGAFUCJOOJHUZZKLZLCIVQZQUJYGRAQSUQWSWFCGJXGDGWWQMTYTLLLGTLWVCSQQITTKGOEDMERMCMPERRYAZKEDRFSDKWVQUSMGFXLJFOWKIUMTJXKQDBHGPJUKQRTSBTZ',
125
+ decoded: 'GOODEVENSIRMAYONEBEPARDONDANDRETAINTHEOFFENCEHOWLONGHATHSHEBEENTHUSTHOUGHTANDAFFLICTIONPASSIONHELLITSELFSHETURNSTOFAVOURANDTOPRETTINESS'
126
+ }
127
+
128
+ },
129
+ {
130
+ verified: ['https://cryptii.com/pipes/enigma-machine', 'http://people.physik.hu-berlin.de/~palloks/js/enigma/enigma-u_v26_en.html'],
131
+ model: 'I',
132
+ setup: {
133
+ rotors: ['III', 'I', 'II'],
134
+ plugs: 'EJ ZX TU KV MI DB NW GQ LR FO',
135
+ ringSettings: [4, 5, 7],
136
+ reflector: 'B'
137
+ },
138
+ message: {
139
+ start: 'OEC',
140
+ encoded: 'WCOJLTOXJZSYRDRGPLWJJOXWFCCISIRBMEHOKYWDFNJFWXCWATBJJTJLTMEQMWBIFXVIBJJOPAYKSUZIFATKZLMMVHNIYOPHBYKBAAHCYPKELSEWGKBHAHROMIGPBRYQXFCRJGUXWHFKBGTECDZDZLWVIHXKOFBXWJKETDLBLWKDTPPFUFKPKMROJHZMDDBHTKXSWMPNRYOVWEEUIMKYBGVSQJCFNBKKLVYZGKQQRTMMPTWJAMJQPGDCGHLUNQKSVWOAALTXS',
141
+ decoded: 'HOWDANGEROUSISITTHATTHISMANGOESLOOSEYETMUSTNOTWEPUTTHESTRONGLAWONHIMHESLOVEDOFTHEDISTRACTEDMULTITUDEWHOLIKENOTINTHEIRJUDGMENTBUTTHEIREYESANDWHERETISSOTHEOFFENDERSSCOURGEISWEIGHDBUTNEVERTHEOFFENCEAMINOTITHERIGHTOLDJEPHTHAHAHMYGOODLORDWHATHAVEISEENTONIGHTWHATGERTRUDE'
142
+ }
143
+
144
+ },
145
+ {
146
+ verified: ['https://cryptii.com/pipes/enigma-machine', 'http://people.physik.hu-berlin.de/~palloks/js/enigma/enigma-u_v26_en.html'],
147
+ model: 'M3',
148
+ setup: {
149
+ rotors: ['IV', 'VII', 'I'],
150
+ plugs: 'NI RM AH VQ UL FD GS WY JE TX',
151
+ ringSettings: [23, 13, 3],
152
+ reflector: 'B'
153
+ },
154
+ message: {
155
+ start: 'HMP',
156
+ encoded: 'PDWBCHJGYPCHHUXNDVUGEZSYIUATENCFMYUIQPWIBBIELWXUNAWZNPVNKTBOJTHEDWDJJKQEOEPSMJBRGTWJGNURUXXEFYGJKUSHYPFZIDEWODCRKXFFLQKVLRLXNIACDAZEIFJXTLZXUSJRLQIDBJTIDUAFRJAYTSNFBJBXKVLASUZQMPCJJLCOZDMDIRPEJANYQCIUPLAPSMQMXXXHSMMNEDCSDDILZOWGPXVWKWKHKYLXEOYFHMNBPURLKA',
157
+ decoded: 'COMEHITHERGENTLEMENANDLAYYOURHANDSAGAINUPONMYSWORDNEVERTOSPEAKOFTHISTHATYOUHAVEHEARDSWEARBYMYSWORDAREYOUFAIRNOMOREBEDONEWESHOULDPROFANETHESERVICEOFTHEDEADTOSINGAREQUIEMANDSUCHRESTTOHERASTOPEACEPARTEDSOULSNIGGARDOFQUESTIONBUTOFOURDEMANDSMOSTFREEINHISREPLY'
158
+ }
159
+ },
160
+ {
161
+ verified: ['https://cryptii.com/pipes/enigma-machine', 'http://people.physik.hu-berlin.de/~palloks/js/enigma/enigma-u_v26_en.html'],
162
+ model: 'M3',
163
+ setup: {
164
+ rotors: ['VI', 'IV', 'II'],
165
+ plugs: 'QZ DK LA MX ET BG VO SH YP WJ',
166
+ ringSettings: [4, 15, 21],
167
+ reflector: 'B'
168
+ },
169
+ message: {
170
+ key: 'ASA',
171
+ encoded: 'URVTSTZATDUFQLGIUJKVRRVJZHSHDOGEKHREOYECTDTBUYZACWNGMHTUGWNUIUJMKHQQAPAKQIQYDHXWBRILLAURPOYTGNYUDANCLJCKSIPCJWLCLBHVXKNNRXPHHJUQJMRBZZASHQLCLQMMTYOA',
172
+ decoded: 'EXCHANGEFORGIVENESSWITHMENOBLEHAMLETMINEANDMYFATHERSDEATHCOMENOTUPONTHEENORTHINEONMEHORATIOIAMDEADTHOULIVESTREPORTMEANDMYCAUSEARIGHTTOTHEUNSATISFIED'
173
+ }
174
+ },
175
+ {
176
+ verified: ['https://cryptii.com/pipes/enigma-machine', 'http://people.physik.hu-berlin.de/~palloks/js/enigma/enigma-u_v26_en.html'],
177
+ model: 'M3',
178
+ setup: {
179
+ rotors: ['II', 'I', 'VII'],
180
+ plugs: 'BL SK WD FN HZ IX QU EJ PC OM',
181
+ ringSettings: [19, 20, 14],
182
+ reflector: 'B'
183
+ },
184
+ message: {
185
+ key: 'HRO',
186
+ encoded: 'LJVBCURJWLPLFSYKZNBEXTUHTPCWRQTOKBRBCDMAMQCDMIXIOMVCVKBVDXMXIJVELDNRBXPWCCICPEHAXTVZYV',
187
+ decoded: 'WHYONEFAIRDAUGHTERANDNOMORETHEWHICHHELOVEDPASSINGWELLYOUTOLDUSOFSOMESUITWHATISTLAERTES'
188
+ }
189
+ },
190
+ {
191
+ verified: ['https://cryptii.com/pipes/enigma-machine', 'https://people.physik.hu-berlin.de/~palloks/js/enigma/enigma-m4_v16_en.html'],
192
+ model: 'M4',
193
+ setup: {
194
+ rotors: ['Beta', 'II', 'VII', 'V'],
195
+ plugs: 'YL SF VO AI BX WC KD MT JN PH',
196
+ ringSettings: [9, 18, 12, 8],
197
+ reflector: 'Thin-B'
198
+ },
199
+ message: {
200
+ key: 'MKDM',
201
+ encoded: 'KEKZCUAFFTWOHZURZPCTWWCICFOGAXBTCTPHMAIFXEEBAYFCQOOAGFKWAHOFEUYWBUEZIWADYATCTLEOUGRPSQDTBZCHIGQGBCXBRYDSGFDBEURKHUKFUYHALYROROKIZWFTPEJJUIRGBIQFGPLGWXJPMNPSEHYSGITZCGSMZXVVJCRXZQWGMOKNBTYVRMYHPWMEXGPUSHYQEWIDZTITRUFXLPYAQUCZVDCAVCMWGGQMXEQDFPTBLOJDEGTGKXXWFIGASTKMLWHFOPPXNBVDYUHDNOJNATOTMWLJGLSTJXDDHGKOBZCPNTPLPKINICEWVJUUNVKDYWGVFFJE',
202
+ decoded: 'YOUNGFORTINBRASWITHCONQUESTCOMEFROMPOLANDTOTHEAMBASSADORSOFENGLANDGIVESTHISWARLIKEVOLLEYNOUPSWORDANDKNOWTHOUAMOREHORRIDHENTWHENHEISDRUNKASLEEPORINHISRAGEORINTHEINCESTUOUSPLEASUREOFHISBEDATGAMINGSWEARINGORABOUTSOMEACTTHATHASNORELISHOFSALVATIONINTTHENTRIPHIMTHATHISHEELSMAYKICKATHEAVENANDTHATHISSOULMAYBEASDAMNDANDBLACKASHELLWHERETOITGOES'
203
+ }
204
+ },
205
+ {
206
+ verified: ['https://cryptii.com/pipes/enigma-machine', 'https://people.physik.hu-berlin.de/~palloks/js/enigma/enigma-m4_v16_en.html'],
207
+ model: 'M4',
208
+ setup: {
209
+ rotors: ['Gamma', 'VIII', 'VI', 'V'],
210
+ plugs: 'RX VA HE ST QL UK PG DB JZ OC',
211
+ ringSettings: [7, 14, 19, 26],
212
+ reflector: 'Thin-C'
213
+ },
214
+ message: {
215
+ key: 'IBFP',
216
+ encoded: 'PUEDVIRAVXYTNFBCUGMSVLVZYRREYMERJCSCKSCACKBZNZNNLYFAAUIKFRMIIUPWBFSFWVKRYLMKHXKXGJXRFQJNRSLSFGFBBKEVQPWCLKUBMNUUKWIYSUQXAXOGZKSBVCRXMIMNJKOXCUBFXSGYQVUXSAWOFQVDQIYTULXKZXEKCQGXQXFVADTSSVZZGQMHBBMJQBYLUWAJELOIYICWTDZQAQYPBCAGKHTICILGFKMNRRXGRUTADCIOCQBXHODIRWXARKENICHVMVHWRRIVWWDCG',
217
+ decoded: 'IFYOUDOMEETHORATIOANDMARCELLUSTHERIVALSOFMYWATCHBIDTHEMMAKEHASTETHEGREATMANDOWNYOUMARKHISFAVOURITEFLIESTHEPOORADVANCEDMAKESFRIENDSOFENEMIESOWONDERFULGOODMYLORDTELLITFORGIVEMETHISMYVIRTUEFORINTHEFATNESSOFTHESEPURSYTIMESVIRTUEITSELFOFVICEMUSTPARDONBEGYEACURBANDWOOFORLEAVETODOHIMGOOD'
218
+ }
219
+ },
220
+ {
221
+ verified: ['https://cryptii.com/pipes/enigma-machine', 'https://people.physik.hu-berlin.de/~palloks/js/enigma/enigma-m4_v16_en.html'],
222
+ model: 'M4',
223
+ setup: {
224
+ rotors: ['Gamma', 'II', 'VIII', 'VII'],
225
+ plugs: 'SA LM XY CV ER GB KT PJ WH DU',
226
+ ringSettings: [25, 21, 11, 2],
227
+ reflector: 'Thin-B'
228
+ },
229
+ message: {
230
+ key: 'TQXV',
231
+ encoded: 'NWWKWEOXQKVGAFEMANRTAEGIZIROXKLPEFTWZJEHQVXDIDDXYIDASSXZJUSZTDHEUKPUVNTOONBYOZJAGCMTEFYHCSJCHOHGMXWHLZAVCBRVNGAMTFUNZNVWPAWBXUICZCYKDBSKJZBQPOMBJCJVKSIGJXAXBDZLYAGPSVATCLXXEQVIWUKBOP',
232
+ decoded: 'COMEHITHERGENTLEMENANDLAYYOURHANDSAGAINUPONMYSWORDNEVERTOSPEAKOFTHISTHATYOUHAVEHEARDSWEARBYMYSWORDSEEITSTALKSAWAYSTAYSPEAKSPEAKICHARGETHEESPEAKTISGONEANDWILLNOTANSWERISHALLOBEYMYLORD'
233
+ }
234
+ }
235
+ ]
236
+ }
@@ -0,0 +1,123 @@
1
+
2
+ import '../standardInventory.js';
3
+ import Enigma from "../Enigma.js";
4
+
5
+ import { enigmaData } from './EnigmaData.js';
6
+
7
+ describe('Enigma Test Cases', function() {
8
+ var enigma;
9
+ /*
10
+ describe('Configuration', function() {
11
+
12
+ })
13
+ */
14
+
15
+ function messageLoop(messages, which, cb) {
16
+ messages.find(function(message) {
17
+ var enigma = new Enigma({
18
+ reflector: message.setup.reflector
19
+ });
20
+
21
+ enigma.configure({
22
+ plugs: message.setup.plugs,
23
+ rotors: message.setup.rotors,
24
+ ringSettings: message.setup.ringSettings
25
+ })
26
+
27
+ var toEncode = message.message[which]
28
+ var encoded = enigma.encode(message.message.key,toEncode);
29
+ return cb(message, encoded);
30
+ })
31
+ }
32
+
33
+ describe('Stepping', function() {
34
+ var steps = {}
35
+ beforeEach(function() {
36
+ enigma = new Enigma({
37
+ reflector: 'B',
38
+ });
39
+
40
+ enigma.configure({rotors: ['I', 'II', 'III']});
41
+
42
+ enigma.listen(function(event, name, message, info) {
43
+ if (event === 'step') {
44
+ steps[name] = steps[name] || [];
45
+ steps[name].push(info);
46
+ }
47
+ })
48
+
49
+ });
50
+
51
+ it ('should step only the right-most rotor when not at turnover', function() {
52
+ steps = {};
53
+ enigma.encode('AAA', 'A');
54
+ var stepped = Object.keys(steps);
55
+ expect(stepped.length).toBe(1);
56
+ expect(stepped[0]).toBe('rotor-III');
57
+ });
58
+
59
+ it ('should step the next rotor when the previous turns over', function() {
60
+ steps = {};
61
+ enigma.encode('AAV', 'A');
62
+ expect(steps['rotor-II'].length).toBe(1);
63
+ });
64
+
65
+ it ('should double step when reaching the turn over', function() {
66
+ steps = {};
67
+ enigma.encode('ADV', 'AA');
68
+ expect(steps['rotor-II'].length).toBe(2);
69
+ });
70
+
71
+ it ('should double step on first step', function() {
72
+ steps = {};
73
+
74
+ enigma.configure({rotors: ['III', 'VI', 'VIII'], ringSettings: [1, 8, 13]});
75
+
76
+ enigma.encode('UZV', 'AA');
77
+ expect(steps['rotor-VI'].length).toBe(1);
78
+ });
79
+ })
80
+
81
+ describe('Encoding', function() {
82
+ it('Should encode sample field messages', function() {
83
+ var messages = enigmaData.sampleFieldMessages;
84
+
85
+ var fail = messageLoop(messages, 'decoded', function(message, decoded) {
86
+ return decoded !== message.encoded;
87
+ })
88
+
89
+ expect(fail).toBeUndefined();
90
+ });
91
+
92
+ it('Should decode sample field messages', function() {
93
+ var messages = enigmaData.sampleFieldMessages;
94
+
95
+ var fail = messageLoop(messages, 'encoded', function(message, decoded) {
96
+ return decoded !== message.decoded;
97
+ })
98
+
99
+ expect(fail).toBeUndefined();
100
+ })
101
+
102
+ it('Should encode sample verified messages', function() {
103
+ var messages = enigmaData.sampleVerifiedMessages;
104
+
105
+ var fail = messageLoop(messages, 'decoded', function(message, decoded) {
106
+ return decoded !== message.encoded;
107
+ })
108
+
109
+ expect(fail).toBeUndefined();
110
+ });
111
+
112
+ it('Should decode sample verified messages', function() {
113
+ var messages = enigmaData.sampleVerifiedMessages;
114
+
115
+ var fail = messageLoop(messages, 'encoded', function(message, decoded) {
116
+ return decoded !== message.decoded;
117
+ })
118
+
119
+ expect(fail).toBeUndefined();
120
+ })
121
+
122
+ })
123
+ })
@@ -0,0 +1,4 @@
1
+ export const plugBoardData = {
2
+ alphabet: 'ABCDEFG',
3
+ plugSettings: 'AB FG',
4
+ }
@@ -0,0 +1,46 @@
1
+ import PlugBoard from "../PlugBoard.js";
2
+ import { plugBoardData } from './PlugBoardData.js';
3
+
4
+ describe('PlugBoard Test Cases', function() {
5
+ var plugBoard;
6
+
7
+ describe('Encode', function() {
8
+ beforeEach(function() {
9
+ plugBoard = new PlugBoard('test-plugboard', {
10
+ alphabet: plugBoardData.alphabet,
11
+ });
12
+ })
13
+
14
+ it('passes through if no plugs defined', function() {
15
+ plugBoard.configure()
16
+ var alphabet = [...plugBoardData.alphabet];
17
+ alphabet.forEach(function(letter) {
18
+ var input = plugBoardData.alphabet.indexOf(letter);
19
+ var output = plugBoard.encode('right', input);
20
+ expect(output).toBe(input);
21
+ var output = plugBoard.encode('left', input);
22
+ expect(output).toBe(input);
23
+ })
24
+ });
25
+
26
+ it('should link cabled pairs', function() {
27
+ plugBoard.configure({plugs: plugBoardData.plugSettings});
28
+ var pairs = plugBoardData.plugSettings.split(' ');
29
+ var alphabet = plugBoardData.alphabet;
30
+ pairs.forEach(function(pair) {
31
+ var left = alphabet.indexOf(pair[0]);
32
+ var right = alphabet.indexOf(pair[1]);
33
+
34
+ var output = plugBoard.encode('right', left);
35
+ expect(output).toBe(right);
36
+ var output = plugBoard.encode('right', right);
37
+ expect(output).toBe(left);
38
+
39
+ var output = plugBoard.encode('left', right);
40
+ expect(output).toBe(left);
41
+ var output = plugBoard.encode('left', left);
42
+ expect(output).toBe(right);
43
+ })
44
+ })
45
+ })
46
+ })