@ondoher/enigma 0.1.0 → 0.1.2

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.
package/README.md ADDED
@@ -0,0 +1,636 @@
1
+ <div style="text-align: right">
2
+ <div><img src="../docs/images/enigma-logo.jpg" height="75"/></div>
3
+ <h1>Toolkit</h1>
4
+ </div>
5
+
6
+ # Getting Started
7
+
8
+ The Enigma toolkit is released as a nodejs ESM module. ESM is a relatively new
9
+ standard for importing modules, and can present challenges to developers who
10
+ need to mix the two. Using CJS modules in an ESM project is pretty straight
11
+ forward, but the opposite is not true. Here is a good page that covers this
12
+ issue [Mixing ESM and CJS](https://adamcoster.com/blog/commonjs-and-esm-importexport-compatibility-examples).
13
+ To work with this code, your best bet is to create your own project also as ESM,
14
+ by either renaming your files with the extension mjs, or adding
15
+ ```"type": "module"``` to your package.js file.
16
+
17
+ To install the module, use the command:
18
+
19
+ ```npm install @ondoher/enigma```
20
+
21
+ You can then import this into your code like this:
22
+
23
+ ```JavaScript
24
+ import {Enigma} from '@ondoher/enigma';
25
+
26
+ var enigma = new Enigma({reflector: 'B'});
27
+ ```
28
+
29
+ The API is broken into two main parts, the simulator and the message generator.
30
+ With the simulator you can construct an entire Enigma, or just create instances
31
+ of the individual components. This API is provided as a working reference that
32
+ can be used to validate the simulator being built. You can match the input and
33
+ output of your simulation against the reference implementation to locate
34
+ failures to be corrected. The API also provides a way to hook into the various
35
+ stages of encoding to observe the transformation of state and data as it occurs.
36
+
37
+ # Simulation
38
+
39
+ ## Events
40
+ Each class below, except Inventory, has a method named `listen`. Call this
41
+ method to pass a function that will be called when significant events happen to
42
+ the class instance. When creating an instance of the Enigma, this callback
43
+ will be passed to every constructed component.
44
+
45
+ The signature of this callback should look like this:
46
+
47
+ `function (event, name, message, info)`
48
+
49
+ ### **Parameters**
50
+ - **event** a string that identifies the specific action being taken.
51
+ - **name** the name of the class instance that has fired this event
52
+ - **message** a string that describes the event taking place
53
+ - **info** an object that contains information relevant to the event
54
+
55
+ The specific events and data are defined in the class documentation that
56
+ follows.
57
+
58
+ ## PlugBoard
59
+ Create an instance of this class to simulate the plug board component of an
60
+ Enigma.
61
+
62
+ ### **Methods**
63
+
64
+ `constructor(name, settings)`
65
+
66
+ This is the constructor for the plugboard class. It takes these parameters:
67
+
68
+ #### **Parameters**
69
+ - **name** each encoder component in the system has a name. There is only one
70
+ plug board in the Enigma, so the name here doesn't really matter
71
+ - **settings**
72
+ - _alphabet_ (optional) set this to a string of letters that are an
73
+ alternative to the standard A-Z. Defaults to A-Z
74
+ - _map_ (optional) set this to a string that will set the mapping between
75
+ the position in the string to the output connector. Defaults to A-Z
76
+
77
+ `configure(settings)`
78
+
79
+ Call this method to configure the plug board. This must be called even if there
80
+ are no plug connections.
81
+
82
+ #### **Parameters**
83
+ - **settings** these are the settings to configure the plug board.
84
+ - _plugs_ (optional) either an array of strings or a single string. If it
85
+ is a string, it must be a space separated list of letter pairs that
86
+ connects one input letter to another. If it is an array then then each item
87
+ is a pair of letters to specify how the plugs are connected
88
+
89
+ `encode(direction, input)`
90
+
91
+ Call this method to encode a value in the given direction, right vs left.
92
+
93
+ #### **Parameters**
94
+ - **direction** `right` when moving towards the reflector `left` when moving
95
+ back
96
+ - **input** this is the input connector.
97
+
98
+ #### **Returns**
99
+ the output connector
100
+
101
+ #### **Events**
102
+
103
+ `encode-right, encode-left`
104
+
105
+ These events will be fired during encoding. The info parameter will have these
106
+ fields.
107
+
108
+ - **input** the number of the connector that received input
109
+ - **output** the number of the connector for the encoded value
110
+
111
+ ## Rotor
112
+
113
+ Create an instance of this class to construct a Rotor object. The Rotor class
114
+ encapsulates many of the peculiar behaviors of the Enigma. All connector values
115
+ here are specified in physical space. See the [documentation](./docs/enigma.md)
116
+ for an explanation.
117
+
118
+ ### **Methods**
119
+
120
+ `constructor(name, settings)`
121
+
122
+ #### **Parameters**
123
+ - **name** the name of the rotor; under normal circumstances this will be the
124
+ string 'rotor-' plus the standard name for the rotor, for example 'rotor-IV'
125
+ - **settings** an object that contains the various options that define the
126
+ the rotor and how it is configured.
127
+ - _alphabet_ (optional) set this to a string of letters that are an
128
+ alternative to the standard A-Z. Defaults to A-Z
129
+ - _map_ a string that defines the mapping between the input and output
130
+ connectors. The index into the string is the input connector and the value
131
+ of this string at that index is the output connector. For example
132
+ 'EKMFLGDQVZNTOWYHXUSPAIBRCJ', which is the map for standard rotor I
133
+ - _ringSetting_ a number that specifies how far forward to offset the
134
+ outer ring relative to the internal wiring.
135
+ - _turnovers_ a string that specifies the relative location of where on the
136
+ rotor turnover will occur. The value here is the rotation value would be
137
+ displayed in the window when turnover happens, expressed as a character.
138
+ The standard rotors VI-VIII, available in the later model M3 had two
139
+ turnover locations, M and Z. Pass an empty string when the rotor does not
140
+ rotate during stepping
141
+
142
+ `setStartPosition(connector)`
143
+
144
+ Call this method to set the starting rotation for encoding.
145
+
146
+ #### **Parameters**
147
+ - **connector** This is a letter value that corresponds to what would appear in
148
+ the rotation window. This value will be adjusted for the ring setting.
149
+
150
+ `encode(direction, input)`
151
+
152
+ Call this method to map an input connector to an output connector when the
153
+ signal is moving in the given direction. The input connector represents a
154
+ physical location in real space. To get the logical connector for the rotor's
155
+ zero point we need to adjust the connector number for the current rotation.
156
+
157
+ #### **Parameters**
158
+ - **direction** `right` when moving towards the reflector `left` when moving
159
+ back
160
+ - **input** the input connector given in physical space.
161
+
162
+ #### **Returns**
163
+ the output connector in physical space
164
+
165
+ `step()`
166
+
167
+ Call this method to step the rotor
168
+
169
+ #### **Returns**
170
+ true if the next rotor should be stepped
171
+
172
+ `willTurnover()`
173
+ Call this method to see if the next step on this rotor will lead to turn over.
174
+ The Enigma class will call this on the middle rotor to handle double stepping.
175
+
176
+ #### **Returns**
177
+ true if the next step will cause turnover
178
+
179
+ `isfixed()`
180
+
181
+ Call this method to find whether this is a fixed rotor.
182
+
183
+ #### **Returns**
184
+ True if this is a fixed rotor.
185
+
186
+ ### **Events**
187
+
188
+ `encode-right, encode-left`
189
+
190
+ These events will be fired during encoding. The info object will contain these
191
+ members
192
+
193
+ - **input** the physical input connector
194
+ - **output** the physical output connector
195
+ - **logicalInput** the logical connector that receives input. This value is
196
+ always relative to the internal wiring.
197
+ - **logicalOutput** the logical connector that gets the output.
198
+ - **rotation** current rotation offset
199
+
200
+ `step`
201
+
202
+ This event will be fired every time a rotor is stepped. The info object will
203
+ contain these members
204
+
205
+ #### **Parameters**
206
+ - **rotation** the current rotation offset
207
+ - **ringSetting** the configured ringSetting for this rotor.
208
+ - **turnover** true if the next rotor should be stepped
209
+
210
+ ## Reflector
211
+ Create an instance of this class to construct a reflector class. Unlike most
212
+ other encoders, the reflector only has a single set of connectors. Input and
213
+ output happen on the same connectors, with pairs of them linked. Because of
214
+ this, reflectors only encode in a single direction.
215
+
216
+ ### **Methods**
217
+
218
+ `constructor(name, settings)`
219
+
220
+ #### **Parameters**
221
+ - **name** the name of the reflector, under normal circumstances this be the
222
+ string 'reflector-' plus the standard name for the reflector, for example
223
+ 'reflector-C'
224
+ - **settings** an object that contains the various options that define the
225
+ the reflector and how it is setup.
226
+ - _alphabet_ (optional) set this to a string of letters that are an
227
+ alternative to the standard A-Z. Defaults to A-Z
228
+ - _map_ a string that defines the mapping between the input and output
229
+ connectors. The index into the string is the input connector and the value
230
+ of this string at that index is the output connector. For example,
231
+ 'YRUHQSLDPXNGOKMIEBFZCWVJAT' which is the map for standard reflector B.
232
+
233
+ `encode(direction, input)`
234
+
235
+ Call this method to encode a value when reversing the encoding direction of the
236
+ Enigma. As the point where direction changes this does not have a distinction
237
+ between a left and right signal path.
238
+
239
+ #### **Parameters**
240
+ - **direction** since this the point where signal direction changes from right
241
+ to left this parameter is not used.
242
+ - **input** this is the input connector
243
+
244
+ #### **Returns**
245
+ the output connector
246
+
247
+ ### **Events**
248
+
249
+ `encode`
250
+
251
+ This event will be fired during encoding. The info parameter will have these
252
+ fields.
253
+
254
+ - **input** the number of the connector that received input
255
+ - **output** the number of the connector for the encoded value
256
+
257
+ ## Enigma
258
+
259
+ Create an instance of this class to construct a full Enigma.
260
+
261
+ ### **Methods**
262
+
263
+ `constructor(settings)`
264
+
265
+ The constructor for the Enigma.
266
+
267
+ #### **Parameters**
268
+ - **settings** The settings here are for the unconfigurable options of the
269
+ device.
270
+ - _alphabet_ (optional) set this to a string of letters that are an
271
+ alternative to the standard A-Z. Defaults to A-Z
272
+ - _entryDisk_ (optional) the name of entry disc in the inventory this
273
+ defaults to 'default'
274
+ - _reflector_ for the Enigma I or M3 this specifies one of three possible
275
+ standard reflectors from the inventory which are A, B, and C. For the M4,
276
+ Thin-B and Thin-C have been defined.
277
+
278
+ `configure(settings)`
279
+
280
+ Call this method to configure the enigma instance for daily setup.
281
+
282
+ #### **Parameters**
283
+ - **settings** the configuration parameters for the device.
284
+ - _plugs_ (optional) this specifies how the plug board should be configured.
285
+ This is either a string with the plugs specified as pairs of letters
286
+ separated by a single space, or an array of letter pairs.
287
+ - _rotors_ this is an array of strings that specifies which rotors should be
288
+ installed on the device and in which order. These rotors have been
289
+ predefined: I-V for the model I, VI-VIII are added for the Model M3, and
290
+ Beta and Gamma are the fixed rotors for the M4. The order here is
291
+ significant and is given in the left to right direction. This means that
292
+ last name in this list is the first rotor used in the forward direction and
293
+ last used in the backward direction. Each element is the name of the rotor
294
+ to use in the corresponding position. Stepping stops at the first fixed
295
+ rotor.
296
+ - _ringSettings_ (optional) This is either a string, or an array of
297
+ numbers. The index of each letter in the alphabet, or the number in the
298
+ array, is the ring setting for a rotor. Like the rotors, these are given
299
+ from left to right.
300
+
301
+ `step()`
302
+
303
+ Call this method to step the Enigma. This will rotate the first rotor to the
304
+ right and step and double step when necessary.
305
+
306
+ `setStart(start)`
307
+
308
+ #### **Parameters**
309
+ - **start** this is either a string of an array of numbers. The length of the
310
+ string or the array should match the number of rotors and are given left to
311
+ right. If start is a string then the letters of the string specify the start
312
+ value seen in the window for the corresponding rotor. If it is an array then
313
+ each number will be the one-based rotation value.
314
+
315
+ `keyPress(letter)`
316
+
317
+ Call this method to encode a single letter. This will step the Enigma before
318
+ encoding the letter.
319
+
320
+ #### **Parameters**
321
+ - **letter** this method will force the letter parameter to uppercase. If it is
322
+ anything except a member of the given alphabet it will return undefined. For
323
+ any other character except a space it will also output a warning to the
324
+ console.
325
+
326
+ #### **Returns**
327
+ undefined or the encoded character.
328
+
329
+ `encode(start, text)`
330
+
331
+ Call this method to encode a whole string.
332
+
333
+ #### **Parameters**
334
+ - **start** the start positions for the rotors. This parameter is the same as
335
+ what's passed to `setStart`.
336
+ - **text** This is the string to be encoded. Any characters in this string that
337
+ are not part of the defined alphabet are ignored.
338
+
339
+ #### **Returns**
340
+ the encoded string. Passing the result of this method back through the encode
341
+ method should produce the original text.
342
+
343
+ ### **Events**
344
+
345
+ In addition to firing all the events from its components, the Enigma will also
346
+ fire these events.
347
+
348
+ `input`
349
+
350
+ This is fired at the beginning of encoding each letter. It is fired after
351
+ verifying the letter, but before stepping. The info parameter contains these
352
+ fields.
353
+
354
+ - **letter** the letter to be encoded
355
+
356
+ `output`
357
+
358
+ This is fired after encoding each letter. The info parameter contains these
359
+ fields.
360
+
361
+ - **letter** the encoded letter.
362
+
363
+ ### **Example**
364
+
365
+ ```javascript
366
+ import {Enigma} from '@ondoher/enigma';
367
+
368
+ var enigma = new Enigma({reflector: 'B'});
369
+
370
+ enigma.configure({
371
+ rotors: ['III', 'VI', 'VIII'],
372
+ ringSetting: [1, 8, 13],
373
+ plugs: 'AN EZ HK IJ LR MQ OT PV SW UX'
374
+ });
375
+
376
+ var message = 'YKAENZAPMSCHZBFOCUVMRMDPYCOFHADZIZMEFXTHFLOLPZLFGGBOTGOXGRETDWTJIQHLMXVJWKZUASTR'
377
+ var decoded = enigma.encode('UZV', message)
378
+
379
+ console.log(decoded)
380
+
381
+ //STEUEREJTANAFJORDJANSTANDORTQUAAACCCVIERNEUNNEUNZWOFAHRTZWONULSMXXSCHARNHORSTHCO
382
+ ```
383
+
384
+ ## Inventory
385
+
386
+ The inventory class is used to save named definitions of different components
387
+ that can be used by the Enigma. The module doesn't export the class, but instead
388
+ exports an instance of it named `inventory`. Components that have been added to
389
+ this inventory can be passed to the Enigma for configuration. By default the
390
+ following components are already defined:
391
+
392
+ - **Rotors** I, II, III, IV, V, VI, VII, VI, Beta, and Gamma. VI, VII, and VIII
393
+ are used in the M3 and M4 and have two turnover points. The last two are
394
+ fixed rotors used in the M4.
395
+ - **Reflectors** A, B, C, Thin-B, and Thin-C. Those last two are the thin
396
+ reflectors used in the M4.
397
+ - **EntryDisc** the system only defines one entry disk, named default. It's just
398
+ a simple pass through.
399
+
400
+ ### **Methods**
401
+
402
+ `addRotor(name, map, turnovers)`
403
+
404
+ Call this method to add a new rotor definition.
405
+
406
+ #### **Parameters**
407
+ - **name** the name of the rotor being added. This name will be used when
408
+ specifying the rotors to use for the Enigma configuration.
409
+ - **map** a string specifying the connector mapping. The index of the string is
410
+ the logical coordinate of the connector, the character at that index is the
411
+ output connector. To be exact, it would be the position of that character in
412
+ the given alphabet. So, in the map 'EKMFLGDQVZNTOWYHXUSPAIBRCJ', input
413
+ connector 0 would map to output connector 4 and input connector 1 would map
414
+ to output connector 10. Remember that the connectors are numbered starting
415
+ at 0.
416
+ - **turnovers** this is a string of characters representing the turnover
417
+ location on the disk. This letter would be the value shown in the window to
418
+ the operator. In Rotor I this is 'Q' in rotors VI, VII, and VIII there are
419
+ two turnover locations, 'M' and 'Z'. Pass an empty string if this is a fixed
420
+ rotor
421
+
422
+ `addReflector(name, map)`
423
+
424
+ Call this method to add a new reflector definition.
425
+
426
+ #### **Parameters**
427
+ - **name** this is the name that will be used to reference this reflector when
428
+ constructing an Enigma class.
429
+ - **map** this uses the same format used in the `addRotor` method
430
+
431
+ `addEntryDisc(name, map)`
432
+
433
+ Call this method to add a new entry disc. There was only one used in the
434
+ standard military models, but there were other versions that defined it
435
+ differently.
436
+
437
+ #### **Parameters**
438
+ - **name** this is the name that will be used to reference this entry disc when
439
+ constructing an Enigma class.
440
+ - **map** this uses the same format used in the `addRotor` method
441
+
442
+ `getRotor(name)`
443
+
444
+ Call this method to get the setup for a defined rotor.
445
+
446
+ #### **Parameters**
447
+ - **name** the name of the rotor as it was added to the inventory.
448
+
449
+ #### **Returns**
450
+ an object with these fields
451
+ - **map** the connection map for the rotor
452
+ - **turnovers** the locations where turnovers happen
453
+
454
+ `getReflector(name)`
455
+
456
+ Call this method to get the setup for a defined reflector.
457
+
458
+ #### **Parameters**
459
+ - **name** the name of the reflector as it was added to the inventory.
460
+
461
+ #### **Returns**
462
+ an object with these fields
463
+ - **map** the connection map for the reflector
464
+
465
+ `getEntryDisc(name)`
466
+
467
+ Call this method to get the setup for a defined entry disc.
468
+
469
+ #### **Parameters**
470
+ - **name** the name of the entry disk as it was added to the inventory.
471
+
472
+ #### **Returns**
473
+ an object with these fields
474
+ - **map** the connection map for the entry disc
475
+
476
+ # Message Generator
477
+
478
+ The message generator API consists of a single class `Generator` which is used
479
+ to generate random test data.
480
+
481
+ ## Generator
482
+
483
+ ### **Methods**
484
+
485
+ `generateEncodedText(settings)`
486
+
487
+ Call this method to generate some random text encoded with a random Enigma
488
+ configuration. The random text will be a few sentences from Hamlet.
489
+
490
+ #### **Parameters**
491
+ - **settings** (optional), alternative configuration settings for the Enigma
492
+ - _rotors_ (optional) alternate list of rotors to choose from. Defaults to
493
+ all defined rotors
494
+ - _fixed_ (optional) an array of fixed rotors to choose from. Defaults to
495
+ an empty list
496
+ - _reflectors_ (optional) an array of reflectors to choose from. Defaults to
497
+ A, B and C
498
+
499
+ #### **Returns**
500
+ the generated text and meta data. This is an object with these fields
501
+
502
+ - **setup** how the Enigma was configured
503
+ - _rotors_ an array of three rotor names, four if a fixed list was given
504
+ in the settings
505
+ - _ringSettings_ an array of offsets for the ring settings
506
+ - _plugs_ 10 pairs of letters that will be used as connections on the plug
507
+ board
508
+ - _reflector_ which reflector was configured
509
+
510
+ - **start** three letter or four string with the starting rotor offsets used to
511
+ encode the text.
512
+ - **message** the encoded text
513
+ - **clear** the unencoded text. This is provided to validate the simulation
514
+ result
515
+
516
+ #### **Example**
517
+
518
+ ```JavaScript
519
+ // Generate messages for the Enigma Model I
520
+ function generateI(count, list) {
521
+ for (let idx = 0; idx < count; idx++) {
522
+ let message = generator.generateEncodedText({
523
+ rotors: ['I', 'II', 'III', 'IV', 'V'],
524
+ reflectors: ['A', 'B', 'C'],
525
+ })
526
+ list.push({model: 'I', ...message});
527
+ }
528
+ }
529
+ ```
530
+
531
+ `generateEnigmaSetup(settings)`
532
+
533
+ Call this method to generate a random Enigma setup. This includes only the
534
+ configurable items, it does not include the details of the machine itself.
535
+
536
+ #### **Parameters**
537
+ - **settings** (optional), alternative configuration settings for the Enigma
538
+ - _rotors_ (optional) alternate list of rotors to choose from. This will
539
+ default to all defined rotors except those that are fixed.
540
+ _fixed_ (optional) an array of fixed rotors to choose one from. Defaults to
541
+ an empty list
542
+
543
+ #### **Returns**
544
+ the generated settings. This is an obejct with these fields
545
+
546
+ - **rotors** an array of three rotor names, four if fixed was given in the
547
+ settings
548
+ - **ringSettings** an array of offsets for the ring settings
549
+ - **plugs** 10 pairs of letters that will be used as connections on the plug
550
+ board
551
+
552
+ `generateKeySheet(days)`
553
+
554
+ Call this method to generate a monthly key sheet. This is the same data that
555
+ would have been used by officers to setup the Enigma every day. The keysheet
556
+ is generated for an M3 (rotors I-VIII) using reflector B
557
+
558
+ #### **Parameters**
559
+ - **days** The number of days to generate data for
560
+
561
+ #### **Returns**
562
+ the key sheet which is an array of objects, each one with these fields
563
+
564
+ - **day** the day of the month
565
+ - **rotors** an array of three rotor names
566
+ - **ringSettings** an array of offsets for the ring settings
567
+ - **plugs** 10 pairs of letters that will be used as connections on the plug
568
+ board
569
+ - **indicators** and array of four three-letter strings. These strings will be
570
+ unique across the key sheet
571
+
572
+ `generateMessages(sheet, count)`
573
+
574
+ Call this method to create an array of messages based off a key sheet. This has
575
+ the same informaton that a message in the field would possess. The construction
576
+ of the message follow the the standards of the German military beginning in
577
+ 1940. They are as follows:
578
+
579
+ >The Wehrmacht radio operator sets each day the rotors, ring settings and
580
+ plugboard according to the key sheet. For each new message, he now selects new
581
+ randomly chosen start position or Grundstellung, say WZA, and a random message
582
+ key or Spruchschlüssel, say SXT. He moves the rotors to the random start
583
+ position WZA and encrypts the random message key SXT...
584
+ >
585
+ >He then sets message key SXT as start position of the rotors and encrypts the
586
+ actual message. Next, he transmits the random start position WZA, the encrypted
587
+ message key RSK and the Kenngruppe FDJKM together with his message.
588
+ >
589
+ >--[Enigma Message Procedures](https://www.ciphermachinesandcryptology.com/en/enigmaproc.htm)
590
+
591
+ The first five characters of each message was used to specify one of the four
592
+ key identifiers from the key sheet that defines the Enigma configuration. The
593
+ first two characters of this group were randomly chosen, and the last three were
594
+ one of the key identifiers for that daily setup. This text was not encrypted.
595
+
596
+ #### **Parameters**
597
+ - **sheet** a key sheet as generated from `generateKeySheet`
598
+ - **count** the number of messages to create
599
+
600
+ #### **Returns**
601
+ an array of messages. Each message is an array of sub messages. A message was
602
+ broken down into text blocks that were no longer than 250 characters and sent
603
+ in multiple parts. These sub messages were sent using a unique key and start
604
+ position. These are the fields in a sub message.
605
+
606
+ - **key** a randomly chosen key, this would be transmitted with the message
607
+ - **enc** the encoded start position for the message. This was encoded using
608
+ the randomly chosen key. This was sent with the message
609
+ - **text** the message text encoded using the unencoded start position. The
610
+ first five letters of this text string included the unencrypted key
611
+ identifier.
612
+ - **start** the unencoded start position. This was not sent with the message but
613
+ is included here to verify an implementation of this method.
614
+ - **clear** the unencrypted message. This can be used to verify an
615
+ implementation of this method.
616
+
617
+ #### **Example Message**
618
+
619
+ ```json
620
+ [
621
+ {
622
+ "key": "YSR",
623
+ "enc": "MHH",
624
+ "start": "GJC",
625
+ "text": "OAYXJ CTCBV BZRBS SORIL YVMMM LLIVS OBUYU VMQTJ GFSZU XYUDR GHKRX KRCDV QEZCH MDTAJ KZUXV TZPOA VSCFH ILWQC DJNAH PILTN MMLHK OULDS QIMCB NMTRZ OQFQY CVWVW QXEHU WCMKJ XGUSA YPBIE EXGKZ LZLUF NMJNB ISUWN DYOWW XUJNK VUYOV SJOSW MQNSP MUTAZ DQIXV RGJXM ",
626
+ "clear": "WHATD EVILW ASTTH ATTHU SHATH COZEN DYOUA THOOD MANBL INDEY ESWIT HOUTF EELIN GFEEL INGWI THOUT SIGHT EARSW ITHOU THAND SOREY ESSME LLING SANSA LLORB UTASI CKLYP ARTOF ONETR UESEN SECOU LDNOT SOMOP EOSHA MEWHE REIST HYBLU SHREB ELLIO USHEL LIFTH"
627
+ },
628
+ {
629
+ "key": "MYR",
630
+ "enc": "AJI",
631
+ "start": "ETH",
632
+ "text": "OAYXJ WPIFA NPUKR ZWSZG GXYZX ZYTMQ PHVNB CPHUA XEUVC VOGUZ LPQSP RFHTK ZNFHL OYGEU ZGOPG EFBTL ORNDH INNGD LDIAT DDPOP QZZKE XBUWI VCJOW LWDJO BLASV JTOMG LUDRC LIISC DJZES QZSSD GBYSG PUGHS EWADO KDSFP ZOLBL RPEYX YKQTF HOI",
633
+ "clear": "OUCAN STMUT INEIN AMATR ONSBO NESTO FLAMI NGYOU THLET VIRTU EBEAS WAXAN DMELT INHER OWNFI REPRO CLAIM NOSHA MEWHE NTHEC OMPUL SIVEA RDOUR GIVES THECH ARGES INCEF ROSTI TSELF ASACT IVELY DOTHB URNAN DREAS ONPAN DERSW ILL"
634
+ }
635
+ ]
636
+ ```
@@ -88,9 +88,22 @@ export const enigmaData = {
88
88
  key: 'RPR',
89
89
  encoded: 'PBQOMEWLLMJFBXKPZNBHRGLUGVHJBXYPSEACOXOTBQRWVTPVVYHLLDOCQQKIWVAMJNFADSUNAVMJGJIBMUGBWWRKJBZNHVELOGZHTISLTUWS',
90
90
  decoded: 'VERWALTUNGSAMTREICHSGERICHTARBEITSLAGERNICHTAUFSCHLAGENVCNSTDMQWZVGNVMBCPDGKPFQZWTRLDMFNGHSRDTFZGLDKCVLMNHGF',
91
-
92
91
  }
93
-
92
+ },
93
+ {
94
+ source: 'https://www.cryptomuseum.com/crypto/enigma/msg/p1030681.htm',
95
+ model: 'M4',
96
+ setup: {
97
+ reflector: 'Thin-C',
98
+ rotors: ['Beta', 'V', 'VI', 'VIII'],
99
+ ringSettings: 'EPEL',
100
+ plugs: 'AE BF CM DQ HU JN LX PR SZ VW'
101
+ },
102
+ message: {
103
+ key: 'CDSZ',
104
+ encoded: 'LANOTCTOUARBBFPMHPHGCZXTDYGAHGUFXGEWKBLKGJWLQXXTGPJJAVTOCKZFSLPPQIHZFXOEBWIIEKFZLCLOAQJULJOYHSSMBBGWHZANVOIIPYRBRTDJQDJJOQKCXWDNBBTYVXLYTAPGVEATXSONPNYNQFUDBBHHVWEPYEYDOHNLXKZDNWRHDUWUJUMWWVIIWZXIVIUQDRHYMNCYEFUAPNHOTKHKGDNPSAKNUAGHJZSMJBMHVTREQEDGXHLZWIFUSKDQVELNMIMITHBHDBWVHDFYHJOQIHORTDJDBWXEMEAYXGYQXOHFDMYUXXNOJAZRSGHPLWMLRECWWUTLRTTVLBHYOORGLGOWUXNXHMHYFAACQEKTHSJW',
105
+ decoded: 'KRKRALLEXXFOLGENDESISTSOFORTBEKANNTZUGEBENXXICHHABEFOLGELNBEBEFEHLERHALTENXXJANSTERLEDESBISHERIGXNREICHSMARSCHALLSJGOERINGJSETZTDERFUEHRERSIEYHVRRGRZSSADMIRALYALSSEINENNACHFOLGEREINXSCHRIFTLSCHEVOLLMACHTUNTERWEGSXABSOFORTSOLLENSIESAEMTLICHEMASSNAHMENVERFUEGENYDIESICHAUSDERGEGENWAERTIGENLAGEERGEBENXGEZXREICHSLEITEIKKTULPEKKJBORMANNJXXOBXDXMMMDURNHFKSTXKOMXADMXUUUBOOIEXKP'
106
+ }
94
107
  }
95
108
  ],
96
109
  sampleVerifiedMessages: [
@@ -136,7 +149,7 @@ export const enigmaData = {
136
149
  reflector: 'B'
137
150
  },
138
151
  message: {
139
- start: 'OEC',
152
+ key: 'OEC',
140
153
  encoded: 'WCOJLTOXJZSYRDRGPLWJJOXWFCCISIRBMEHOKYWDFNJFWXCWATBJJTJLTMEQMWBIFXVIBJJOPAYKSUZIFATKZLMMVHNIYOPHBYKBAAHCYPKELSEWGKBHAHROMIGPBRYQXFCRJGUXWHFKBGTECDZDZLWVIHXKOFBXWJKETDLBLWKDTPPFUFKPKMROJHZMDDBHTKXSWMPNRYOVWEEUIMKYBGVSQJCFNBKKLVYZGKQQRTMMPTWJAMJQPGDCGHLUNQKSVWOAALTXS',
141
154
  decoded: 'HOWDANGEROUSISITTHATTHISMANGOESLOOSEYETMUSTNOTWEPUTTHESTRONGLAWONHIMHESLOVEDOFTHEDISTRACTEDMULTITUDEWHOLIKENOTINTHEIRJUDGMENTBUTTHEIREYESANDWHERETISSOTHEOFFENDERSSCOURGEISWEIGHDBUTNEVERTHEOFFENCEAMINOTITHERIGHTOLDJEPHTHAHAHMYGOODLORDWHATHAVEISEENTONIGHTWHATGERTRUDE'
142
155
  }
@@ -152,7 +165,7 @@ export const enigmaData = {
152
165
  reflector: 'B'
153
166
  },
154
167
  message: {
155
- start: 'HMP',
168
+ key: 'HMP',
156
169
  encoded: 'PDWBCHJGYPCHHUXNDVUGEZSYIUATENCFMYUIQPWIBBIELWXUNAWZNPVNKTBOJTHEDWDJJKQEOEPSMJBRGTWJGNURUXXEFYGJKUSHYPFZIDEWODCRKXFFLQKVLRLXNIACDAZEIFJXTLZXUSJRLQIDBJTIDUAFRJAYTSNFBJBXKVLASUZQMPCJJLCOZDMDIRPEJANYQCIUPLAPSMQMXXXHSMMNEDCSDDILZOWGPXVWKWKHKYLXEOYFHMNBPURLKA',
157
170
  decoded: 'COMEHITHERGENTLEMENANDLAYYOURHANDSAGAINUPONMYSWORDNEVERTOSPEAKOFTHISTHATYOUHAVEHEARDSWEARBYMYSWORDAREYOUFAIRNOMOREBEDONEWESHOULDPROFANETHESERVICEOFTHEDEADTOSINGAREQUIEMANDSUCHRESTTOHERASTOPEACEPARTEDSOULSNIGGARDOFQUESTIONBUTOFOURDEMANDSMOSTFREEINHISREPLY'
158
171
  }
@@ -13,7 +13,7 @@ describe('Enigma Test Cases', function() {
13
13
  */
14
14
 
15
15
  function messageLoop(messages, which, cb) {
16
- messages.find(function(message) {
16
+ return messages.find(function(message) {
17
17
  var enigma = new Enigma({
18
18
  reflector: message.setup.reflector
19
19
  });
@@ -26,6 +26,7 @@ describe('Enigma Test Cases', function() {
26
26
 
27
27
  var toEncode = message.message[which]
28
28
  var encoded = enigma.encode(message.message.key,toEncode);
29
+
29
30
  return cb(message, encoded);
30
31
  })
31
32
  }
@@ -83,7 +84,7 @@ describe('Enigma Test Cases', function() {
83
84
  var messages = enigmaData.sampleFieldMessages;
84
85
 
85
86
  var fail = messageLoop(messages, 'decoded', function(message, decoded) {
86
- return decoded !== message.encoded;
87
+ return decoded !== message.message.encoded;
87
88
  })
88
89
 
89
90
  expect(fail).toBeUndefined();
@@ -93,7 +94,7 @@ describe('Enigma Test Cases', function() {
93
94
  var messages = enigmaData.sampleFieldMessages;
94
95
 
95
96
  var fail = messageLoop(messages, 'encoded', function(message, decoded) {
96
- return decoded !== message.decoded;
97
+ return decoded !== message.message.decoded;
97
98
  })
98
99
 
99
100
  expect(fail).toBeUndefined();
@@ -103,7 +104,7 @@ describe('Enigma Test Cases', function() {
103
104
  var messages = enigmaData.sampleVerifiedMessages;
104
105
 
105
106
  var fail = messageLoop(messages, 'decoded', function(message, decoded) {
106
- return decoded !== message.encoded;
107
+ return decoded !== message.message.encoded;
107
108
  })
108
109
 
109
110
  expect(fail).toBeUndefined();
@@ -113,7 +114,7 @@ describe('Enigma Test Cases', function() {
113
114
  var messages = enigmaData.sampleVerifiedMessages;
114
115
 
115
116
  var fail = messageLoop(messages, 'encoded', function(message, decoded) {
116
- return decoded !== message.decoded;
117
+ return decoded !== message.message.decoded;
117
118
  })
118
119
 
119
120
  expect(fail).toBeUndefined();
package/package.json CHANGED
@@ -1,13 +1,19 @@
1
1
  {
2
2
  "name": "@ondoher/enigma",
3
- "version": "0.1.0",
4
- "description": "",
3
+ "version": "0.1.2",
4
+ "description": "Tools and documentation to help in building and testing an Enigma Machine simulator.",
5
5
  "main": "./lib/index.js",
6
6
  "scripts": {
7
7
  "test": "jasmine"
8
8
  },
9
9
  "author": "Glenn Anderson",
10
10
  "license": "MIT",
11
+ "keywords": ["enigma", "enigma-machine", "enigma machine", "simulation", "cryptography"],
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "https://github.com/Ondoher/enigma.git"
15
+ },
16
+ "homepage": "https://github.com/Ondoher/enigma#readme",
11
17
  "type": "module",
12
18
  "devDependencies": {
13
19
  "jasmine": "^4.5.0",