-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathenigma.cpp
More file actions
376 lines (290 loc) · 9.88 KB
/
Copy pathenigma.cpp
File metadata and controls
376 lines (290 loc) · 9.88 KB
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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
#include <bits/stdc++.h>
#include "parser.h"
using namespace std;
int inputToInteger(char c);
/*
Rotors are the main agents in Enigma encryption. They work as following:
Based on a given wiring, it maps the input signal with an output signal.
*OBS: This signal usually flows through 3 to 4 rotors, that may have different wirings.
*Hint: the wiring patterns are specified in rotor-wiring.txt, a file that contains 3+ models.
Besides, everytime a key is pressed, the right-most rotor rotates, what creates an offset in the wiring pattern.
*OBS: A rotor is simulated as a deque, what makes this operation more intuitive.
When the right-most rotor performs a full spin, the rotor in its left rotates once. And the same goes for every rotors.
*OBS: This is simulated by the function rotate().
EXAMPLE:
In a Enigma machine that is designed to support 3 rotors, let's call the right one A, the center one B, and the left-most one C.
At every keypress, A performs a single spin.
At every full spin of A (26 keypresses), B performs a single spin.
This means that C spins once at every 676 keypresses.
*/
class Rotor
{
private:
// Constructor elements. Rotors includes a type (a.k.a model), a wiring configuration (see wirings.txt) and an initial offset.
string type;
string wiring;
int offset;
int rotation_amount;
deque<int> deque_wiring;
public:
// Constructor method
Rotor(string t, string w, int off)
{
type = t;
wiring = w;
offset = off;
rotation_amount = 0;
createDeque(wiring);
applyOffset();
}
// Get type
string getType()
{
return type;
}
// Get offset
int getOffset()
{
return offset;
}
// Get deque
deque<int> getDeque()
{
return deque_wiring;
}
// Set the type (also referenced as a model in this code) of the rotor, tipically a string.
void setType(string s)
{
type = s;
}
// Set the initial offset of a rotor
void setOffset(int off)
{
offset = off;
}
// Creates a deque, based on the given wiring. This is defined by the model of the rotor, and can be analyzed with Rotor class getters, or in wirings.txt.
void createDeque(string s)
{
for (int i = 0; i < s.length(); i++)
{
deque_wiring.push_back(s[i]);
}
}
// Applies the initial offset to the queue. This is equivalent to configuring the initial position of a rotor on a real Enigma machine.
void applyOffset()
{
for (int i = 0; i < offset; i++)
{
deque_wiring.push_front(deque_wiring.back());
deque_wiring.pop_back();
}
}
// Simulates a rotation of the rotor
int rotate()
{
char deque_back = deque_wiring.back();
deque_wiring.pop_back();
deque_wiring.push_front(deque_back);
int flag_full_turn = 0;
if (rotation_amount == 25)
{
rotation_amount = 0;
flag_full_turn = 1;
}
else
rotation_amount++;
return flag_full_turn;
}
};
class Reflector
{
private:
// Constructor elements. Rotors includes a type (a.k.a model), a wiring configuration (see wirings.txt) and an initial offset.
string type;
string wiring;
public:
Reflector(string t, string w)
{
type = t;
wiring = w;
}
char reflect(char input_c)
{
char output_c = wiring[inputToInteger(input_c) - 1];
return output_c;
}
};
// Enigma class
class Enigma
{
private:
// An enigma include a set of rotors.
vector<Rotor> rotors;
Reflector reflector;
public:
Enigma(vector<Rotor> v, Reflector r) : rotors(v), reflector(r) {}
vector<Rotor> getRotors()
{
return rotors;
}
Rotor getSingleRotor(int pos)
{
return rotors[pos];
}
int encrypt(int code)
{
code = signal_flow(code, 1);
code = reflector.reflect(code);
code = signal_flow(code, 2);
int idx = 0; // Variable that stores a temporary counter.
// Whenever a char is pressed, rotates the first rotor, before the encryption is made.
int flag_full_turn = rotors[idx].rotate();
// Perform the full rotation of rotors, whenever flag_full_turn is activated
while (flag_full_turn == 1 && idx < rotors.size())
{
idx++;
flag_full_turn = rotors[idx].rotate();
}
return code;
}
// This functions sends the input signal through the rotors.
int signal_flow(int code, int mode)
{
vector<Rotor> rotors_list = rotors;
if (mode == 2)
{
reverse(rotors_list.begin(), rotors_list.end());
}
for (int i = 0; i < rotors_list.size(); i++)
{
Rotor current_rotor = rotors_list[i];
deque<int> current_rotor_wiring = current_rotor.getDeque();
if (mode == 1)
code = current_rotor_wiring.at(inputToInteger(code) - 1);
else if (mode == 2)
{
for (int i = 0; i < 26; i++)
{
if (current_rotor_wiring.at(i) == code)
{
// Converts the integer i to an upper letter.
code = i + 65;
break;
}
}
}
}
return code;
}
};
// Gets user input, based on the index of the rotor to be scanned. TODO: Handle unsupported inputs.
int getInput(int index)
{
int input;
switch (index)
{
case 1:
cout << "Set the model of the right rotor: ";
break;
case 2:
cout << "Set the model of the center rotor: ";
break;
case 3:
cout << "Set the model of the left rotor: ";
break;
}
cin >> input;
return input;
}
// Scans the rotor's model and wiring from the file "wirings.txt", and its initial offset.
tuple<string, string, int> scanRotor(int index)
{
int idx_rotor = getInput(index);
// This pair is used as an auxiliar variable to store returns from searchRotor() function.
pair<string, string> pair_model_wiring = searchRotor(idx_rotor);
// Assign each variable stored in the pair to a specific string (Rule #1: ALWAYS use mnemonic variable names).
string model = pair_model_wiring.first;
string wiring = pair_model_wiring.second;
// Scans the initial offset. TODO: Handle exceptions, and support both letters or numbers.
int offset;
// Scans the offset
cout << "Set the initial offset for this rotor: ";
cin >> offset;
// Returns a tuple consisting off all the information needed to create a Rotor-type object.
return make_tuple(model, wiring, offset);
}
pair<string, string> scanReflector(int index)
{
int idx_reflector = index;
pair<string, string> pair_model_wiring = searchReflector(idx_reflector);
return pair_model_wiring;
}
/*
This function calls the procedure to scan the model of the desired rotor (passed as argument of this function).
Then, it generates a Rotor object with that info.
*/
Rotor createRotor(int index)
{
// Receives a tuple with the following format <MODEL, WIRING, OFFSET>
tuple<string, string, int> tuple = scanRotor(index);
// Finally, creates an object and returns it.
Rotor rotor(get<0>(tuple), get<1>(tuple), get<2>(tuple));
return rotor;
}
Reflector createReflector(int index)
{
pair<string, string> pair = scanReflector(index);
Reflector reflector(pair.first, pair.second);
return reflector;
}
// Sets an enigma machine. This is done by filling it slots (vector of Rotors -> dinamically allocated) with rotors.
Enigma setEnigma()
{
// Creates all the 3 rotors. TODO: Setup a way to allow user to include any amount of rotors.
Rotor right_rotor = createRotor(1);
Rotor center_rotor = createRotor(2);
Rotor left_rotor = createRotor(3);
vector<Rotor> set_of_rotors{right_rotor, center_rotor, left_rotor};
Reflector reflector = createReflector(1);
Enigma enigma(set_of_rotors, reflector);
return enigma;
}
// The implemented logic uses numbers to identify each letter (range 1-26). This function does a simple conversion between char and integer types, using ASCII codes.
int inputToInteger(char c)
{
char lower_c = tolower(c);
int code = lower_c - 96;
return code;
}
void step()
{
char input;
while (true)
{
}
}
int main()
{
int count = 1;
string s;
Enigma enigma = setEnigma();
cout << endl;
cout << "Type your text: ";
std::getline(std::cin >> ws, s);
// Check if Enigma class and its objects are working correctly.
// cout << enigma.getSingleRotor(0).getType() << endl;
//cout << count << ". " << c << " -> " << (char) enigma.encrypt(c) << endl;
cout << endl;
cout << "Encrypted text: ";
s.erase(remove(s.begin(), s.end(), ' '), s.end());
for(auto c : s)
{
cout << (char)enigma.encrypt(c);
// Breaks encrypted text into sets of 4 letters;
if(count % 4 == 0)
cout << " ";
count++;
}
cout << endl;
return 0;
}