-
Notifications
You must be signed in to change notification settings - Fork 0
/
enigma.js
158 lines (134 loc) · 4.47 KB
/
enigma.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
// number of stepping rotors
var NUM_ROTORS = 3;
// rotor wirings
// rotors I-VIII taken from wikipedia
var wirings = [ "EKMFLGDQVZNTOWYHXUSPAIBRCJ",
"AJDKSIRUXBLHWTMCQGZNPYFVOE",
"BDFHJLCPRTXVZNYEIWGAKMUSQO",
"ESOVPZJAYQUIRHXLNFTGKDCMWB",
"VZBRGITYUPSDNHLXAWMJQOFECK",
"JPGVOUMFYQBENHZRDKASXLICTW",
"NZJHGRCXMYSWBOUFAIVLPEKQDT",
"FKQHTLXOCBJSPDZRAMEWNIUYGV" ];
// reflectors A,B,C from wikipedia
var reflectors = [ "EJMZALYXVBWFCRQUONTSPIKHGD",
"YRUHQSLDPXNGOKMIEBFZCWVJAT",
"FVPJIAOYEDRZXWGCTKUQSBNMHL" ];
// rotor notches
var notches = [ [16],
[4],
[0] ]; //third notch not used
// converts "A" into 0, "B" into 1, etc.
var charToInt = function ( character ) {
return character.charCodeAt() - "A".charCodeAt();
};
// converts "EKMF..." into [4, 10, 12, 5, ...]
var charStringToIntArray = function ( charString ) {
return charString.split('').map( charToInt );
};
// converts 4 into E
var intToChar = function ( intIn ) {
return String.fromCharCode(
intIn + "A".charCodeAt() );
};
// converts [4, 10, 12, 5] into "EKMF"
var intArrayToCharString = function ( intArray ) {
return intArray.map( intToChar ).join('');
};
// converts [2,1,3,0] to [3,1,0,2]
var makeInverseRotor = function ( rotor ) {
var irotor = []
for (var i=0; i<rotor.length; i++) {
irotor.push( rotor.indexOf(i) );
}
return irotor;
};
// select rotors and make inverses
// (I'm just taking I,II,III for now)
var rotors = [];
var irotors = [];
for (var i=0; i<NUM_ROTORS; i++) {
rotors.push( charStringToIntArray(wirings[i]) );
irotors.push( makeInverseRotor( rotors[i] ) );
}
// select the reflector
// (here, I want just B for now)
var reflector = charStringToIntArray(reflectors[1]);
var reflPos = 0;
// initial rotor positions
var positions = [0, 0, 0];
// compute next rotor positions
// first, set first rotor to always step,
// then go through middle rotors, which step when
// either they or the previous rotor are at a notch,
// then do the last rotor, which only steps when the
// previous rotor is at a notch.
var rotorStep = function (rotors, positions, notches) {
var max = rotors.length-1;
// first rotor always steps
var stepB = [1];
// now do the middle rotors
for (var r=1; r<max; r++) {
stepB.push(0);
// step if previous rotor is at a notch
if(notches[r-1].indexOf( positions[r-1] ) != -1){
stepB[r] = 1;
}
// step if this rotor is at a notch
// ("double stepping")
if(notches[r].indexOf( positions[r] ) != -1){
stepB[r] = 1;
}
}
// now do the last rotor
// step is previous rotor is at a notch
stepB.push(0);
if(notches[max-1].indexOf( positions[max-1] ) != -1){
stepB[max] = 1;
}
console.log(stepB);
// do the actual stepping
for (var r=0; r<rotors.length; r++) {
if(stepB[r]) {
positions[r] = (positions[r] + 1) % 26;
}
}
return positions;
};
// send char through the device
// "letter" is actually an integer
var encryptLetter = function (letter, rotors, reflector, positions, reflPos) {
var x = letter;
console.log("before 0th rotor, x is %s",intToChar(x));
// go through all rotors
for(var r=0; r<rotors.length; r++) {
x = (rotors[r][(x + positions[r]) % 26] + 26 - positions[r]) % 26;
console.log("after forward rotor %d, x is %s",r,
intToChar(x) );
}
// go through reflector
x = reflector[(x + reflPos) % 26];
console.log("after reflector, x is %s",intToChar(x));
// inverse through the rotors
for(var r=rotors.length-1; r>=0; r--) {
x = (rotors[r].indexOf( (x + positions[r]) % 26 ) -
positions[r] + 26) % 26;
console.log("after reverse rotor %d, x is %s",r,
intToChar(x) );
}
console.log("---");
return x;
};
// take a plaintext string, return cipher string
var encryptString = function (string) {
// first get intArray from string
var letters = charStringToIntArray(string);
// encrypt each letter
var ciphers = [];
for(var i=0; i<letters.length; i++) {
rotorStep(rotors,positions,notches);
ciphers.push( encryptLetter(letters[i],
rotors, reflector, positions, reflPos));
}
return intArrayToCharString(ciphers);
};