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