1 /*
2 * (C) 2009 Jack Lloyd
3 *
4 * Distributed under the terms of the Botan license
5 */
6 
7 #include <fstream>
8 #include <iostream>
9 #include <sstream>
10 #include <boost/regex.hpp>
11 
12 #include <botan/botan.h>
13 #include <botan/eax.h>
14 
15 using namespace Botan;
16 
17 namespace {
18 
from_string(const std::string & s)19 unsigned from_string(const std::string& s)
20    {
21    std::istringstream stream(s);
22    unsigned n;
23    stream >> n;
24    return n;
25    }
26 
seq(unsigned n)27 std::string seq(unsigned n)
28    {
29    std::string s;
30 
31    for(unsigned i = 0; i != n; ++i)
32       {
33       unsigned char b = (i & 0xFF);
34 
35       const char bin2hex[] = { '0', '1', '2', '3', '4', '5', '6', '7',
36                                '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
37 
38       s += bin2hex[(b >> 4)];
39       s += bin2hex[(b & 0x0f)];
40       }
41 
42    return s;
43    }
44 
eax_test(const std::string & algo,const std::string & key_str,const std::string & nonce_str,const std::string & header_str,const std::string & tag_str,const std::string & plaintext_str,const std::string & ciphertext)45 void eax_test(const std::string& algo,
46               const std::string& key_str,
47               const std::string& nonce_str,
48               const std::string& header_str,
49               const std::string& tag_str,
50               const std::string& plaintext_str,
51               const std::string& ciphertext)
52    {
53    /*
54    printf("EAX(algo=%s key=%s nonce=%s header=%s tag=%s pt=%s ct=%s)\n",
55           algo.c_str(), key_str.c_str(), nonce_str.c_str(), header_str.c_str(), tag_str.c_str(),
56           plaintext_str.c_str(), ciphertext.c_str());
57    */
58 
59    SymmetricKey key(key_str);
60    InitializationVector iv(nonce_str);
61 
62    EAX_Encryption* enc;
63 
64    Pipe pipe(new Hex_Decoder,
65              enc = new EAX_Encryption(get_block_cipher(algo)),
66              new Hex_Encoder);
67 
68    enc->set_key(key);
69    enc->set_iv(iv);
70 
71    OctetString header(header_str);
72 
73    enc->set_header(header.begin(), header.length());
74 
75    pipe.start_msg();
76    pipe.write(plaintext_str);
77    pipe.end_msg();
78 
79    std::string out = pipe.read_all_as_string();
80 
81    if(out != ciphertext + tag_str)
82       {
83       printf("BAD enc %s '%s' != '%s%s'\n", algo.c_str(),
84              out.c_str(), ciphertext.c_str(), tag_str.c_str());
85       }
86    else
87       printf("OK enc %s\n", algo.c_str());
88 
89    try
90       {
91       EAX_Decryption* dec;
92       Pipe pipe2(new Hex_Decoder,
93                  dec = new EAX_Decryption(get_block_cipher(algo)),
94                  new Hex_Encoder);
95 
96       dec->set_key(key);
97       dec->set_iv(iv);
98 
99       dec->set_header(header.begin(), header.length());
100 
101       pipe2.start_msg();
102       pipe2.write(ciphertext);
103       pipe2.write(tag_str);
104       pipe2.end_msg();
105 
106       std::string out2 = pipe2.read_all_as_string();
107 
108       if(out2 != plaintext_str)
109          {
110          printf("BAD decrypt %s '%s'\n", algo.c_str(), out2.c_str());
111          }
112       else
113          printf("OK decrypt %s\n", algo.c_str());
114       }
115    catch(std::exception& e)
116       {
117       printf("%s\n", e.what());
118       }
119 
120    }
121 
translate_algo(const std::string & in)122 std::pair<std::string, int> translate_algo(const std::string& in)
123    {
124    if(in == "aes (16 byte key)")
125       return std::make_pair("AES-128", 16);
126 
127    if(in == "blowfish (8 byte key)")
128       return std::make_pair("Blowfish", 8);
129 
130    if(in == "rc2 (8 byte key)")
131       return std::make_pair("RC2", 8);
132 
133    if(in == "rc5 (8 byte key)")
134       return std::make_pair("RC5", 8);
135 
136    if(in == "rc6 (16 byte key)")
137       return std::make_pair("RC6", 16);
138 
139    if(in == "safer-sk128 (16 byte key)")
140       return std::make_pair("SAFER-SK(10)", 16);
141 
142    if(in == "twofish (16 byte key)")
143       return std::make_pair("Twofish", 16);
144 
145    if(in == "des (8 byte key)")
146       return std::make_pair("DES", 8);
147 
148    if(in == "3des (24 byte key)")
149       return std::make_pair("TripleDES", 24);
150 
151    // These 3 are disabled due to differences in base algorithm.
152 
153 #if 0
154    // XTEA: LTC uses little endian, Botan (and Crypto++) use big-endian
155    // I swapped to LE in XTEA and the vectors did match
156    if(in == "xtea (16 byte key)")
157       return std::make_pair("XTEA", 16);
158 
159    // Skipjack: LTC uses big-endian, Botan (and Crypto++) use
160    // little-endian I am not sure if that was the full difference
161    // though, was unable to replicate LTC's EAX vectors with Skipjack
162    if(in == "skipjack (10 byte key)")
163       return std::make_pair("Skipjack", 10);
164 
165    // Noekeon: unknown cause, though LTC's lone test vector does not
166    // match Botan
167 
168    if(in == "noekeon (16 byte key)")
169       return std::make_pair("Noekeon", 16);
170 
171 #endif
172 
173    return std::make_pair("", 0);
174    }
175 
rep(const std::string & s_in,unsigned n)176 std::string rep(const std::string& s_in, unsigned n)
177    {
178    std::string s_out;
179 
180    for(unsigned i = 0; i != n; ++i)
181       s_out += s_in[i % s_in.size()];
182 
183    return s_out;
184    }
185 
run_tests(std::istream & in)186 void run_tests(std::istream& in)
187    {
188    std::string algo;
189    std::string key;
190 
191    while(in.good())
192       {
193       std::string line;
194 
195       std::getline(in, line);
196 
197       if(line == "")
198          continue;
199 
200       if(line.size() > 5 && line.substr(0, 4) == "EAX-")
201          {
202          std::pair<std::string, int> name_and_keylen =
203             translate_algo(line.substr(4));
204 
205          algo = name_and_keylen.first;
206          key = seq(name_and_keylen.second);
207          }
208       else if(algo != "")
209          {
210          boost::regex vec_regex("^([ 0-9]{3}): (.*), (.*)$");
211 
212          boost::smatch what;
213 
214          if(boost::regex_match(line, what, vec_regex, boost::match_extra))
215             {
216             unsigned n = from_string(what[1]);
217             std::string ciphertext = what[2];
218             std::string tag = what[3];
219 
220             std::string plaintext = seq(n);
221             std::string header = seq(n);
222             std::string nonce = seq(n);
223 
224             eax_test(algo, key, nonce, header, tag,
225                      plaintext, ciphertext);
226 
227             key = rep(tag, key.size()); // repeat as needed
228             }
229          }
230       }
231 
232 
233    }
234 
235 }
236 
main()237 int main()
238    {
239    std::ifstream in("eax.vec");
240 
241    Botan::LibraryInitializer init;
242 
243    if(!in)
244       {
245       std::cerr << "Couldn't read input file\n";
246       return 1;
247       }
248 
249    run_tests(in);
250 
251    }
252