bgneal@4
|
1 // Copyright (C) 2012 by Brian Neal.
|
bgneal@4
|
2 // This file is part of Cpp-Enigma, the Enigma Machine simulation.
|
bgneal@4
|
3 // Cpp-Enigma is released under the MIT License (see License.txt).
|
bgneal@4
|
4 //
|
bgneal@4
|
5 // test_machine.t.h - Unit tests for the enigma_machine class.
|
bgneal@4
|
6
|
bgneal@4
|
7 #include <memory>
|
bgneal@4
|
8 #include <string>
|
bgneal@4
|
9 #include <vector>
|
bgneal@4
|
10 #include <cxxtest/TestSuite.h>
|
bgneal@4
|
11 #include "machine.h"
|
bgneal@4
|
12 #include "enigma_utils.h"
|
bgneal@4
|
13
|
bgneal@4
|
14 using namespace enigma;
|
bgneal@4
|
15
|
bgneal@4
|
16
|
bgneal@7
|
17 class display_suite : public CxxTest::TestSuite
|
bgneal@7
|
18 {
|
bgneal@7
|
19 public:
|
bgneal@7
|
20
|
bgneal@7
|
21 void test_set_display3()
|
bgneal@7
|
22 {
|
bgneal@7
|
23 enigma_machine m({"II", "IV", "V"}, {}, "B");
|
bgneal@7
|
24 TS_ASSERT_THROWS(m.set_display("ABCD"), enigma_machine_error);
|
bgneal@7
|
25 TS_ASSERT_THROWS_NOTHING(m.set_display("ABC"));
|
bgneal@7
|
26 }
|
bgneal@7
|
27
|
bgneal@7
|
28 void test_set_display4()
|
bgneal@7
|
29 {
|
bgneal@7
|
30 enigma_machine m({"Gamma", "II", "IV", "V"}, {}, "B-Thin");
|
bgneal@7
|
31 TS_ASSERT_THROWS(m.set_display("BCD"), enigma_machine_error);
|
bgneal@7
|
32 TS_ASSERT_THROWS_NOTHING(m.set_display("ABCD"));
|
bgneal@7
|
33 }
|
bgneal@7
|
34 };
|
bgneal@7
|
35
|
bgneal@4
|
36 class stepping_test_suite : public CxxTest::TestSuite
|
bgneal@4
|
37 {
|
bgneal@4
|
38 public:
|
bgneal@4
|
39
|
bgneal@4
|
40 void test_double_stepping()
|
bgneal@4
|
41 {
|
bgneal@4
|
42 // Ensure the rotors step realistically by testing for a "double-step"
|
bgneal@4
|
43 // This example taken from
|
bgneal@4
|
44 // http://users.telenet.be/d.rijmenants/en/enigmatech.htm
|
bgneal@4
|
45 // in the section on "The Stepping Mechanism."
|
bgneal@4
|
46
|
bgneal@4
|
47 enigma_machine m({"III", "II", "I"}, {});
|
bgneal@4
|
48 m.set_display('K', 'D', 'O');
|
bgneal@4
|
49
|
bgneal@4
|
50 const std::vector<std::string> truth_data = {
|
bgneal@4
|
51 "KDP", "KDQ", "KER", "LFS", "LFT", "LFU",
|
bgneal@4
|
52 };
|
bgneal@4
|
53
|
bgneal@4
|
54 for (const auto& expected : truth_data)
|
bgneal@4
|
55 {
|
bgneal@4
|
56 m.key_press('A');
|
bgneal@4
|
57 TS_ASSERT_EQUALS(m.get_display(), expected);
|
bgneal@4
|
58 }
|
bgneal@4
|
59 }
|
bgneal@4
|
60 };
|
bgneal@4
|
61
|
bgneal@4
|
62
|
bgneal@4
|
63 class simple_cipher_test_suite : public CxxTest::TestSuite
|
bgneal@4
|
64 {
|
bgneal@4
|
65 public:
|
bgneal@4
|
66
|
bgneal@4
|
67 void setUp()
|
bgneal@4
|
68 {
|
bgneal@4
|
69 m.reset(new enigma_machine({"I", "II", "III"}, {}));
|
bgneal@4
|
70 m->set_display('A', 'A', 'A');
|
bgneal@4
|
71 plaintext = "AAAAA";
|
bgneal@4
|
72 ciphertext = "BDZGO";
|
bgneal@4
|
73 }
|
bgneal@4
|
74
|
bgneal@4
|
75 void test_simple_encrypt()
|
bgneal@4
|
76 {
|
bgneal@4
|
77 std::vector<char> buffer(plaintext.size());
|
bgneal@4
|
78 m->process_text(plaintext.c_str(), buffer.data(), plaintext.size());
|
bgneal@4
|
79 TS_ASSERT_EQUALS(ciphertext, std::string(buffer.begin(), buffer.end()));
|
bgneal@4
|
80 }
|
bgneal@4
|
81
|
bgneal@4
|
82 void test_simple_decrypt()
|
bgneal@4
|
83 {
|
bgneal@4
|
84 std::vector<char> buffer(plaintext.size());
|
bgneal@4
|
85 m->process_text(ciphertext.c_str(), buffer.data(), ciphertext.size());
|
bgneal@4
|
86 TS_ASSERT_EQUALS(plaintext, std::string(buffer.begin(), buffer.end()));
|
bgneal@4
|
87 }
|
bgneal@4
|
88
|
bgneal@4
|
89 private:
|
bgneal@4
|
90 std::unique_ptr<enigma_machine> m;
|
bgneal@4
|
91 std::string plaintext;
|
bgneal@4
|
92 std::string ciphertext;
|
bgneal@4
|
93 };
|
bgneal@4
|
94
|
bgneal@4
|
95
|
bgneal@4
|
96 // This example taken from Dirk Rijmenants' simulator manual.
|
bgneal@4
|
97 //
|
bgneal@4
|
98 // It is credited to Frode Weierud and Geoff Sullivan.
|
bgneal@4
|
99 // http://cryptocellar.com
|
bgneal@4
|
100 //
|
bgneal@4
|
101 class actual_decrypt_test_suite : public CxxTest::TestSuite
|
bgneal@4
|
102 {
|
bgneal@4
|
103 public:
|
bgneal@4
|
104 void setUp()
|
bgneal@4
|
105 {
|
bgneal@4
|
106 m.reset(new enigma_machine({"II", "IV", "V"}, {1, 20, 11}, "B",
|
bgneal@4
|
107 "AV BS CG DL FU HZ IN KM OW RX"));
|
bgneal@4
|
108 }
|
bgneal@4
|
109
|
bgneal@4
|
110 void decrypt(const std::string& start,
|
bgneal@4
|
111 const std::string& enc_key,
|
bgneal@4
|
112 const std::string& ciphertext,
|
bgneal@4
|
113 const std::string& truth_data)
|
bgneal@4
|
114 {
|
bgneal@4
|
115 // remove spaces & Kenngruppen from ciphertext
|
bgneal@4
|
116 std::string ctext(ciphertext.begin() + 5, ciphertext.end());
|
bgneal@4
|
117 ctext = remove_spaces(ctext);
|
bgneal@4
|
118
|
bgneal@4
|
119 // remove spaces from truth_data
|
bgneal@4
|
120 const std::string expected(remove_spaces(truth_data));
|
bgneal@4
|
121
|
bgneal@4
|
122 // decrypt message key to get start position
|
bgneal@4
|
123 m->set_display(start[0], start[1], start[2]);
|
bgneal@4
|
124 std::string key = m->process_text(enc_key);
|
bgneal@4
|
125
|
bgneal@4
|
126 // decrypt the message with the key
|
bgneal@4
|
127 m->set_display(key[0], key[1], key[2]);
|
bgneal@4
|
128
|
bgneal@4
|
129 const std::string plaintext = m->process_text(ctext);
|
bgneal@4
|
130
|
bgneal@4
|
131 TS_ASSERT_EQUALS(plaintext, expected);
|
bgneal@4
|
132 }
|
bgneal@4
|
133
|
bgneal@4
|
134 void test_decrpyt_1()
|
bgneal@4
|
135 {
|
bgneal@4
|
136 const std::string ciphertext =
|
bgneal@4
|
137 "RFUGZ EDPUD NRGYS ZRCXN"
|
bgneal@4
|
138 "UYTPO MRMBO FKTBZ REZKM"
|
bgneal@4
|
139 "LXLVE FGUEY SIOZV EQMIK"
|
bgneal@4
|
140 "UBPMM YLKLT TDEIS MDICA"
|
bgneal@4
|
141 "GYKUA CTCDO MOHWX MUUIA"
|
bgneal@4
|
142 "UBSTS LRNBZ SZWNR FXWFY"
|
bgneal@4
|
143 "SSXJZ VIJHI DISHP RKLKA"
|
bgneal@4
|
144 "YUPAD TXQSP INQMA TLPIF"
|
bgneal@4
|
145 "SVKDA SCTAC DPBOP VHJK";
|
bgneal@4
|
146
|
bgneal@4
|
147 const std::string truth_data =
|
bgneal@4
|
148 "AUFKL XABTE ILUNG XVONX"
|
bgneal@4
|
149 "KURTI NOWAX KURTI NOWAX"
|
bgneal@4
|
150 "NORDW ESTLX SEBEZ XSEBE"
|
bgneal@4
|
151 "ZXUAF FLIEG ERSTR ASZER"
|
bgneal@4
|
152 "IQTUN GXDUB ROWKI XDUBR"
|
bgneal@4
|
153 "OWKIX OPOTS CHKAX OPOTS"
|
bgneal@4
|
154 "CHKAX UMXEI NSAQT DREIN"
|
bgneal@4
|
155 "ULLXU HRANG ETRET ENXAN"
|
bgneal@4
|
156 "GRIFF XINFX RGTX";
|
bgneal@4
|
157
|
bgneal@4
|
158 decrypt("WXC", "KCH", ciphertext, truth_data);
|
bgneal@4
|
159 }
|
bgneal@4
|
160
|
bgneal@4
|
161 void test_decrpyt_2()
|
bgneal@4
|
162 {
|
bgneal@4
|
163 const std::string ciphertext =
|
bgneal@4
|
164 "FNJAU SFBWD NJUSE GQOBH"
|
bgneal@4
|
165 "KRTAR EEZMW KPPRB XOHDR"
|
bgneal@4
|
166 "OEQGB BGTQV PGVKB VVGBI"
|
bgneal@4
|
167 "MHUSZ YDAJQ IROAX SSSNR"
|
bgneal@4
|
168 "EHYGG RPISE ZBOVM QIEMM"
|
bgneal@4
|
169 "ZCYSG QDGRE RVBIL EKXYQ"
|
bgneal@4
|
170 "IRGIR QNRDN VRXCY YTNJR";
|
bgneal@4
|
171
|
bgneal@4
|
172 const std::string truth_data =
|
bgneal@4
|
173 "DREIG EHTLA NGSAM ABERS"
|
bgneal@4
|
174 "IQERV ORWAE RTSXE INSSI"
|
bgneal@4
|
175 "EBENN ULLSE QSXUH RXROE"
|
bgneal@4
|
176 "MXEIN SXINF RGTXD REIXA"
|
bgneal@4
|
177 "UFFLI EGERS TRASZ EMITA"
|
bgneal@4
|
178 "NFANG XEINS SEQSX KMXKM"
|
bgneal@4
|
179 "XOSTW XKAME NECXK";
|
bgneal@4
|
180
|
bgneal@4
|
181 decrypt("CRS", "YPJ", ciphertext, truth_data);
|
bgneal@4
|
182 }
|
bgneal@4
|
183
|
bgneal@4
|
184 private:
|
bgneal@4
|
185 std::unique_ptr<enigma_machine> m;
|
bgneal@4
|
186 };
|
bgneal@4
|
187
|
bgneal@4
|
188
|
bgneal@4
|
189 // This is the Kriegsmarine example from Dirk Rijmenants' simulator manual.
|
bgneal@4
|
190 //
|
bgneal@4
|
191 // It is credited to Stefan Krah and the M4 project:
|
bgneal@4
|
192 // http://www.bytereef.org/m4_project.html
|
bgneal@4
|
193 //
|
bgneal@4
|
194 class kriegsmarine_test_suite : public CxxTest::TestSuite
|
bgneal@4
|
195 {
|
bgneal@4
|
196 public:
|
bgneal@4
|
197
|
bgneal@4
|
198 void test_decrypt()
|
bgneal@4
|
199 {
|
bgneal@4
|
200 const std::string stecker = "1/20 2/12 4/6 7/10 8/13 14/23 15/16 17/25 18/26 22/24";
|
bgneal@4
|
201
|
bgneal@4
|
202 enigma_machine machine({"Beta", "II", "IV", "I"}, {0, 0, 0, 21}, "B-Thin", stecker);
|
bgneal@4
|
203
|
bgneal@4
|
204 std::string ciphertext = remove_spaces(
|
bgneal@4
|
205 "FCLC QRKN NCZW VUSX PNYM INHZ XMQX SFWX WLKJ AHSH NMCO CCAK UQPM KCSM"
|
bgneal@4
|
206 "HKSE INJU SBLK IOSX CKUB HMLL XCSJ USRR DVKO HULX WCCB GVLI YXEO AHXR"
|
bgneal@4
|
207 "HKKF VDRE WEZL XOBA FGYU JQUK GRTV UKAM EURB VEKS UHHV OYHA BCJW MAKL"
|
bgneal@4
|
208 "FKLM YFVN RIZR VVRT KOFD ANJM OLBG FFLE OPRG TFLV RHOW OPBE KVWM UQFM"
|
bgneal@4
|
209 "PWPA RMFH AGKX IIBG FCLC QRKM VA");
|
bgneal@4
|
210
|
bgneal@4
|
211 // remove the message indicators from the message (the first and last 2
|
bgneal@4
|
212 // groups of the message -- it appears the last partial group 'VA' should
|
bgneal@4
|
213 // be removed also)
|
bgneal@4
|
214
|
bgneal@4
|
215 ciphertext = std::string(ciphertext.begin() + 8, ciphertext.end() - 10);
|
bgneal@4
|
216
|
bgneal@4
|
217 machine.set_display('V', 'J', 'N', 'A');
|
bgneal@4
|
218 const std::string plaintext = machine.process_text(ciphertext);
|
bgneal@4
|
219
|
bgneal@4
|
220 const std::string truth_data = remove_spaces(
|
bgneal@4
|
221 "VONV ONJL OOKS JHFF TTTE"
|
bgneal@4
|
222 "INSE INSD REIZ WOYY QNNS"
|
bgneal@4
|
223 "NEUN INHA LTXX BEIA NGRI"
|
bgneal@4
|
224 "FFUN TERW ASSE RGED RUEC"
|
bgneal@4
|
225 "KTYW ABOS XLET ZTER GEGN"
|
bgneal@4
|
226 "ERST ANDN ULAC HTDR EINU"
|
bgneal@4
|
227 "LUHR MARQ UANT ONJO TANE"
|
bgneal@4
|
228 "UNAC HTSE YHSD REIY ZWOZ"
|
bgneal@4
|
229 "WONU LGRA DYAC HTSM YSTO"
|
bgneal@4
|
230 "SSEN ACHX EKNS VIER MBFA"
|
bgneal@4
|
231 "ELLT YNNN NNNO OOVI ERYS"
|
bgneal@4
|
232 "ICHT EINS NULL");
|
bgneal@4
|
233
|
bgneal@4
|
234 TS_ASSERT_EQUALS(plaintext, truth_data);
|
bgneal@4
|
235 }
|
bgneal@4
|
236
|
bgneal@4
|
237 };
|