Crypto++
datatest.cpp
1 #include "factory.h"
2 #include "integer.h"
3 #include "filters.h"
4 #include "hex.h"
5 #include "randpool.h"
6 #include "files.h"
7 #include "trunhash.h"
8 #include "queue.h"
9 #include "validate.h"
10 #include <iostream>
11 #include <memory>
12 
13 USING_NAMESPACE(CryptoPP)
14 USING_NAMESPACE(std)
15 
16 typedef std::map<std::string, std::string> TestData;
17 
18 class TestFailure : public Exception
19 {
20 public:
21  TestFailure() : Exception(OTHER_ERROR, "Validation test failed") {}
22 };
23 
24 static const TestData *s_currentTestData = NULL;
25 
26 static void OutputTestData(const TestData &v)
27 {
28  for (TestData::const_iterator i = v.begin(); i != v.end(); ++i)
29  {
30  cerr << i->first << ": " << i->second << endl;
31  }
32 }
33 
34 static void SignalTestFailure()
35 {
36  OutputTestData(*s_currentTestData);
37  throw TestFailure();
38 }
39 
40 static void SignalTestError()
41 {
42  OutputTestData(*s_currentTestData);
43  throw Exception(Exception::OTHER_ERROR, "Unexpected error during validation test");
44 }
45 
46 bool DataExists(const TestData &data, const char *name)
47 {
48  TestData::const_iterator i = data.find(name);
49  return (i != data.end());
50 }
51 
52 const std::string & GetRequiredDatum(const TestData &data, const char *name)
53 {
54  TestData::const_iterator i = data.find(name);
55  if (i == data.end())
56  SignalTestError();
57  return i->second;
58 }
59 
60 void RandomizedTransfer(BufferedTransformation &source, BufferedTransformation &target, bool finish, const std::string &channel=DEFAULT_CHANNEL)
61 {
62  while (source.MaxRetrievable() > (finish ? 0 : 4096))
63  {
64  byte buf[4096+64];
65  size_t start = GlobalRNG().GenerateWord32(0, 63);
66  size_t len = GlobalRNG().GenerateWord32(1, UnsignedMin(4096U, 3*source.MaxRetrievable()/2));
67  len = source.Get(buf+start, len);
68  target.ChannelPut(channel, buf+start, len);
69  }
70 }
71 
72 void PutDecodedDatumInto(const TestData &data, const char *name, BufferedTransformation &target)
73 {
74  std::string s1 = GetRequiredDatum(data, name), s2;
75  ByteQueue q;
76 
77  while (!s1.empty())
78  {
79  while (s1[0] == ' ')
80  {
81  s1 = s1.substr(1);
82  if (s1.empty())
83  goto end; // avoid invalid read if s1 is empty
84  }
85 
86  int repeat = 1;
87  if (s1[0] == 'r')
88  {
89  repeat = atoi(s1.c_str()+1);
90  s1 = s1.substr(s1.find(' ')+1);
91  }
92 
93  s2 = ""; // MSVC 6 doesn't have clear();
94 
95  if (s1[0] == '\"')
96  {
97  s2 = s1.substr(1, s1.find('\"', 1)-1);
98  s1 = s1.substr(s2.length() + 2);
99  }
100  else if (s1.substr(0, 2) == "0x")
101  {
102  StringSource(s1.substr(2, s1.find(' ')), true, new HexDecoder(new StringSink(s2)));
103  s1 = s1.substr(STDMIN(s1.find(' '), s1.length()));
104  }
105  else
106  {
107  StringSource(s1.substr(0, s1.find(' ')), true, new HexDecoder(new StringSink(s2)));
108  s1 = s1.substr(STDMIN(s1.find(' '), s1.length()));
109  }
110 
111  while (repeat--)
112  {
113  q.Put((const byte *)s2.data(), s2.size());
114  RandomizedTransfer(q, target, false);
115  }
116  }
117 
118 end:
119  RandomizedTransfer(q, target, true);
120 }
121 
122 std::string GetDecodedDatum(const TestData &data, const char *name)
123 {
124  std::string s;
125  PutDecodedDatumInto(data, name, StringSink(s).Ref());
126  return s;
127 }
128 
129 std::string GetOptionalDecodedDatum(const TestData &data, const char *name)
130 {
131  std::string s;
132  if (DataExists(data, name))
133  PutDecodedDatumInto(data, name, StringSink(s).Ref());
134  return s;
135 }
136 
138 {
139 public:
140  TestDataNameValuePairs(const TestData &data) : m_data(data) {}
141 
142  virtual bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const
143  {
144  TestData::const_iterator i = m_data.find(name);
145  if (i == m_data.end())
146  {
147  if (std::string(name) == Name::DigestSize() && valueType == typeid(int))
148  {
149  i = m_data.find("MAC");
150  if (i == m_data.end())
151  i = m_data.find("Digest");
152  if (i == m_data.end())
153  return false;
154 
155  m_temp.resize(0);
156  PutDecodedDatumInto(m_data, i->first.c_str(), StringSink(m_temp).Ref());
157  *reinterpret_cast<int *>(pValue) = (int)m_temp.size();
158  return true;
159  }
160  else
161  return false;
162  }
163 
164  const std::string &value = i->second;
165 
166  if (valueType == typeid(int))
167  *reinterpret_cast<int *>(pValue) = atoi(value.c_str());
168  else if (valueType == typeid(Integer))
169  *reinterpret_cast<Integer *>(pValue) = Integer((std::string(value) + "h").c_str());
170  else if (valueType == typeid(ConstByteArrayParameter))
171  {
172  m_temp.resize(0);
173  PutDecodedDatumInto(m_data, name, StringSink(m_temp).Ref());
174  reinterpret_cast<ConstByteArrayParameter *>(pValue)->Assign((const byte *)m_temp.data(), m_temp.size(), false);
175  }
176  else
177  throw ValueTypeMismatch(name, typeid(std::string), valueType);
178 
179  return true;
180  }
181 
182 private:
183  const TestData &m_data;
184  mutable std::string m_temp;
185 };
186 
187 void TestKeyPairValidAndConsistent(CryptoMaterial &pub, const CryptoMaterial &priv)
188 {
189  if (!pub.Validate(GlobalRNG(), 3))
190  SignalTestFailure();
191  if (!priv.Validate(GlobalRNG(), 3))
192  SignalTestFailure();
193 
194 /* EqualityComparisonFilter comparison;
195  pub.Save(ChannelSwitch(comparison, "0"));
196  pub.AssignFrom(priv);
197  pub.Save(ChannelSwitch(comparison, "1"));
198  comparison.ChannelMessageSeriesEnd("0");
199  comparison.ChannelMessageSeriesEnd("1");
200 */
201 }
202 
203 void TestSignatureScheme(TestData &v)
204 {
205  std::string name = GetRequiredDatum(v, "Name");
206  std::string test = GetRequiredDatum(v, "Test");
207 
208  std::auto_ptr<PK_Signer> signer(ObjectFactoryRegistry<PK_Signer>::Registry().CreateObject(name.c_str()));
209  std::auto_ptr<PK_Verifier> verifier(ObjectFactoryRegistry<PK_Verifier>::Registry().CreateObject(name.c_str()));
210 
211  TestDataNameValuePairs pairs(v);
212  std::string keyFormat = GetRequiredDatum(v, "KeyFormat");
213 
214  if (keyFormat == "DER")
215  verifier->AccessMaterial().Load(StringStore(GetDecodedDatum(v, "PublicKey")).Ref());
216  else if (keyFormat == "Component")
217  verifier->AccessMaterial().AssignFrom(pairs);
218 
219  if (test == "Verify" || test == "NotVerify")
220  {
221  VerifierFilter verifierFilter(*verifier, NULL, VerifierFilter::SIGNATURE_AT_BEGIN);
222  PutDecodedDatumInto(v, "Signature", verifierFilter);
223  PutDecodedDatumInto(v, "Message", verifierFilter);
224  verifierFilter.MessageEnd();
225  if (verifierFilter.GetLastResult() == (test == "NotVerify"))
226  SignalTestFailure();
227  }
228  else if (test == "PublicKeyValid")
229  {
230  if (!verifier->GetMaterial().Validate(GlobalRNG(), 3))
231  SignalTestFailure();
232  }
233  else
234  goto privateKeyTests;
235 
236  return;
237 
238 privateKeyTests:
239  if (keyFormat == "DER")
240  signer->AccessMaterial().Load(StringStore(GetDecodedDatum(v, "PrivateKey")).Ref());
241  else if (keyFormat == "Component")
242  signer->AccessMaterial().AssignFrom(pairs);
243 
244  if (test == "KeyPairValidAndConsistent")
245  {
246  TestKeyPairValidAndConsistent(verifier->AccessMaterial(), signer->GetMaterial());
247  }
248  else if (test == "Sign")
249  {
250  SignerFilter f(GlobalRNG(), *signer, new HexEncoder(new FileSink(cout)));
251  StringSource ss(GetDecodedDatum(v, "Message"), true, new Redirector(f));
252  SignalTestFailure();
253  }
254  else if (test == "DeterministicSign")
255  {
256  SignalTestError();
257  assert(false); // TODO: implement
258  }
259  else if (test == "RandomSign")
260  {
261  SignalTestError();
262  assert(false); // TODO: implement
263  }
264  else if (test == "GenerateKey")
265  {
266  SignalTestError();
267  assert(false);
268  }
269  else
270  {
271  SignalTestError();
272  assert(false);
273  }
274 }
275 
276 void TestAsymmetricCipher(TestData &v)
277 {
278  std::string name = GetRequiredDatum(v, "Name");
279  std::string test = GetRequiredDatum(v, "Test");
280 
281  std::auto_ptr<PK_Encryptor> encryptor(ObjectFactoryRegistry<PK_Encryptor>::Registry().CreateObject(name.c_str()));
282  std::auto_ptr<PK_Decryptor> decryptor(ObjectFactoryRegistry<PK_Decryptor>::Registry().CreateObject(name.c_str()));
283 
284  std::string keyFormat = GetRequiredDatum(v, "KeyFormat");
285 
286  if (keyFormat == "DER")
287  {
288  decryptor->AccessMaterial().Load(StringStore(GetDecodedDatum(v, "PrivateKey")).Ref());
289  encryptor->AccessMaterial().Load(StringStore(GetDecodedDatum(v, "PublicKey")).Ref());
290  }
291  else if (keyFormat == "Component")
292  {
293  TestDataNameValuePairs pairs(v);
294  decryptor->AccessMaterial().AssignFrom(pairs);
295  encryptor->AccessMaterial().AssignFrom(pairs);
296  }
297 
298  if (test == "DecryptMatch")
299  {
300  std::string decrypted, expected = GetDecodedDatum(v, "Plaintext");
301  StringSource ss(GetDecodedDatum(v, "Ciphertext"), true, new PK_DecryptorFilter(GlobalRNG(), *decryptor, new StringSink(decrypted)));
302  if (decrypted != expected)
303  SignalTestFailure();
304  }
305  else if (test == "KeyPairValidAndConsistent")
306  {
307  TestKeyPairValidAndConsistent(encryptor->AccessMaterial(), decryptor->GetMaterial());
308  }
309  else
310  {
311  SignalTestError();
312  assert(false);
313  }
314 }
315 
316 void TestSymmetricCipher(TestData &v, const NameValuePairs &overrideParameters)
317 {
318  std::string name = GetRequiredDatum(v, "Name");
319  std::string test = GetRequiredDatum(v, "Test");
320 
321  std::string key = GetDecodedDatum(v, "Key");
322  std::string plaintext = GetDecodedDatum(v, "Plaintext");
323 
324  TestDataNameValuePairs testDataPairs(v);
325  CombinedNameValuePairs pairs(overrideParameters, testDataPairs);
326 
327  if (test == "Encrypt" || test == "EncryptXorDigest" || test == "Resync" || test == "EncryptionMCT" || test == "DecryptionMCT")
328  {
329  static member_ptr<SymmetricCipher> encryptor, decryptor;
330  static std::string lastName;
331 
332  if (name != lastName)
333  {
334  encryptor.reset(ObjectFactoryRegistry<SymmetricCipher, ENCRYPTION>::Registry().CreateObject(name.c_str()));
335  decryptor.reset(ObjectFactoryRegistry<SymmetricCipher, DECRYPTION>::Registry().CreateObject(name.c_str()));
336  lastName = name;
337  }
338 
340  if (pairs.GetValue(Name::IV(), iv) && iv.size() != encryptor->IVSize())
341  SignalTestFailure();
342 
343  if (test == "Resync")
344  {
345  encryptor->Resynchronize(iv.begin(), (int)iv.size());
346  decryptor->Resynchronize(iv.begin(), (int)iv.size());
347  }
348  else
349  {
350  encryptor->SetKey((const byte *)key.data(), key.size(), pairs);
351  decryptor->SetKey((const byte *)key.data(), key.size(), pairs);
352  }
353 
354  int seek = pairs.GetIntValueWithDefault("Seek", 0);
355  if (seek)
356  {
357  encryptor->Seek(seek);
358  decryptor->Seek(seek);
359  }
360 
361  std::string encrypted, xorDigest, ciphertext, ciphertextXorDigest;
362  if (test == "EncryptionMCT" || test == "DecryptionMCT")
363  {
364  SymmetricCipher *cipher = encryptor.get();
365  SecByteBlock buf((byte *)plaintext.data(), plaintext.size()), keybuf((byte *)key.data(), key.size());
366 
367  if (test == "DecryptionMCT")
368  {
369  cipher = decryptor.get();
370  ciphertext = GetDecodedDatum(v, "Ciphertext");
371  buf.Assign((byte *)ciphertext.data(), ciphertext.size());
372  }
373 
374  for (int i=0; i<400; i++)
375  {
376  encrypted.reserve(10000 * plaintext.size());
377  for (int j=0; j<10000; j++)
378  {
379  cipher->ProcessString(buf.begin(), buf.size());
380  encrypted.append((char *)buf.begin(), buf.size());
381  }
382 
383  encrypted.erase(0, encrypted.size() - keybuf.size());
384  xorbuf(keybuf.begin(), (const byte *)encrypted.data(), keybuf.size());
385  cipher->SetKey(keybuf, keybuf.size());
386  }
387  encrypted.assign((char *)buf.begin(), buf.size());
388  ciphertext = GetDecodedDatum(v, test == "EncryptionMCT" ? "Ciphertext" : "Plaintext");
389  if (encrypted != ciphertext)
390  {
391  std::cout << "incorrectly encrypted: ";
392  StringSource xx(encrypted, false, new HexEncoder(new FileSink(std::cout)));
393  xx.Pump(256); xx.Flush(false);
394  std::cout << "\n";
395  SignalTestFailure();
396  }
397  return;
398  }
399 
400  StreamTransformationFilter encFilter(*encryptor, new StringSink(encrypted), StreamTransformationFilter::NO_PADDING);
401  RandomizedTransfer(StringStore(plaintext).Ref(), encFilter, true);
402  encFilter.MessageEnd();
403  /*{
404  std::string z;
405  encryptor->Seek(seek);
406  StringSource ss(plaintext, false, new StreamTransformationFilter(*encryptor, new StringSink(z), StreamTransformationFilter::NO_PADDING));
407  while (ss.Pump(64)) {}
408  ss.PumpAll();
409  for (int i=0; i<z.length(); i++)
410  assert(encrypted[i] == z[i]);
411  }*/
412  if (test != "EncryptXorDigest")
413  ciphertext = GetDecodedDatum(v, "Ciphertext");
414  else
415  {
416  ciphertextXorDigest = GetDecodedDatum(v, "CiphertextXorDigest");
417  xorDigest.append(encrypted, 0, 64);
418  for (size_t i=64; i<encrypted.size(); i++)
419  xorDigest[i%64] ^= encrypted[i];
420  }
421  if (test != "EncryptXorDigest" ? encrypted != ciphertext : xorDigest != ciphertextXorDigest)
422  {
423  std::cout << "incorrectly encrypted: ";
424  StringSource xx(encrypted, false, new HexEncoder(new FileSink(std::cout)));
425  xx.Pump(2048); xx.Flush(false);
426  std::cout << "\n";
427  SignalTestFailure();
428  }
429  std::string decrypted;
430  StreamTransformationFilter decFilter(*decryptor, new StringSink(decrypted), StreamTransformationFilter::NO_PADDING);
431  RandomizedTransfer(StringStore(encrypted).Ref(), decFilter, true);
432  decFilter.MessageEnd();
433  if (decrypted != plaintext)
434  {
435  std::cout << "incorrectly decrypted: ";
436  StringSource xx(decrypted, false, new HexEncoder(new FileSink(std::cout)));
437  xx.Pump(256); xx.Flush(false);
438  std::cout << "\n";
439  SignalTestFailure();
440  }
441  }
442  else
443  {
444  std::cout << "unexpected test name\n";
445  SignalTestError();
446  }
447 }
448 
449 void TestAuthenticatedSymmetricCipher(TestData &v, const NameValuePairs &overrideParameters)
450 {
451  std::string type = GetRequiredDatum(v, "AlgorithmType");
452  std::string name = GetRequiredDatum(v, "Name");
453  std::string test = GetRequiredDatum(v, "Test");
454  std::string key = GetDecodedDatum(v, "Key");
455 
456  std::string plaintext = GetOptionalDecodedDatum(v, "Plaintext");
457  std::string ciphertext = GetOptionalDecodedDatum(v, "Ciphertext");
458  std::string header = GetOptionalDecodedDatum(v, "Header");
459  std::string footer = GetOptionalDecodedDatum(v, "Footer");
460  std::string mac = GetOptionalDecodedDatum(v, "MAC");
461 
462  TestDataNameValuePairs testDataPairs(v);
463  CombinedNameValuePairs pairs(overrideParameters, testDataPairs);
464 
465  if (test == "Encrypt" || test == "EncryptXorDigest" || test == "NotVerify")
466  {
468  asc1.reset(ObjectFactoryRegistry<AuthenticatedSymmetricCipher, ENCRYPTION>::Registry().CreateObject(name.c_str()));
469  asc2.reset(ObjectFactoryRegistry<AuthenticatedSymmetricCipher, DECRYPTION>::Registry().CreateObject(name.c_str()));
470  asc1->SetKey((const byte *)key.data(), key.size(), pairs);
471  asc2->SetKey((const byte *)key.data(), key.size(), pairs);
472 
473  std::string encrypted, decrypted;
474  AuthenticatedEncryptionFilter ef(*asc1, new StringSink(encrypted));
475  bool macAtBegin = !mac.empty() && !GlobalRNG().GenerateBit(); // test both ways randomly
476  AuthenticatedDecryptionFilter df(*asc2, new StringSink(decrypted), macAtBegin ? AuthenticatedDecryptionFilter::MAC_AT_BEGIN : 0);
477 
478  if (asc1->NeedsPrespecifiedDataLengths())
479  {
480  asc1->SpecifyDataLengths(header.size(), plaintext.size(), footer.size());
481  asc2->SpecifyDataLengths(header.size(), plaintext.size(), footer.size());
482  }
483 
484  StringStore sh(header), sp(plaintext), sc(ciphertext), sf(footer), sm(mac);
485 
486  if (macAtBegin)
487  RandomizedTransfer(sm, df, true);
488  sh.CopyTo(df, LWORD_MAX, AAD_CHANNEL);
489  RandomizedTransfer(sc, df, true);
490  sf.CopyTo(df, LWORD_MAX, AAD_CHANNEL);
491  if (!macAtBegin)
492  RandomizedTransfer(sm, df, true);
493  df.MessageEnd();
494 
495  RandomizedTransfer(sh, ef, true, AAD_CHANNEL);
496  RandomizedTransfer(sp, ef, true);
497  RandomizedTransfer(sf, ef, true, AAD_CHANNEL);
498  ef.MessageEnd();
499 
500  if (test == "Encrypt" && encrypted != ciphertext+mac)
501  {
502  std::cout << "incorrectly encrypted: ";
503  StringSource xx(encrypted, false, new HexEncoder(new FileSink(std::cout)));
504  xx.Pump(2048); xx.Flush(false);
505  std::cout << "\n";
506  SignalTestFailure();
507  }
508  if (test == "Encrypt" && decrypted != plaintext)
509  {
510  std::cout << "incorrectly decrypted: ";
511  StringSource xx(decrypted, false, new HexEncoder(new FileSink(std::cout)));
512  xx.Pump(256); xx.Flush(false);
513  std::cout << "\n";
514  SignalTestFailure();
515  }
516 
517  if (ciphertext.size()+mac.size()-plaintext.size() != asc1->DigestSize())
518  {
519  std::cout << "bad MAC size\n";
520  SignalTestFailure();
521  }
522  if (df.GetLastResult() != (test == "Encrypt"))
523  {
524  std::cout << "MAC incorrectly verified\n";
525  SignalTestFailure();
526  }
527  }
528  else
529  {
530  std::cout << "unexpected test name\n";
531  SignalTestError();
532  }
533 }
534 
535 void TestDigestOrMAC(TestData &v, bool testDigest)
536 {
537  std::string name = GetRequiredDatum(v, "Name");
538  std::string test = GetRequiredDatum(v, "Test");
539  const char *digestName = testDigest ? "Digest" : "MAC";
540 
543  HashTransformation *pHash = NULL;
544 
545  TestDataNameValuePairs pairs(v);
546 
547  if (testDigest)
548  {
549  hash.reset(ObjectFactoryRegistry<HashTransformation>::Registry().CreateObject(name.c_str()));
550  pHash = hash.get();
551  }
552  else
553  {
554  mac.reset(ObjectFactoryRegistry<MessageAuthenticationCode>::Registry().CreateObject(name.c_str()));
555  pHash = mac.get();
556  std::string key = GetDecodedDatum(v, "Key");
557  mac->SetKey((const byte *)key.c_str(), key.size(), pairs);
558  }
559 
560  if (test == "Verify" || test == "VerifyTruncated" || test == "NotVerify")
561  {
562  int digestSize = -1;
563  if (test == "VerifyTruncated")
564  pairs.GetIntValue(Name::DigestSize(), digestSize);
565  HashVerificationFilter verifierFilter(*pHash, NULL, HashVerificationFilter::HASH_AT_BEGIN, digestSize);
566  PutDecodedDatumInto(v, digestName, verifierFilter);
567  PutDecodedDatumInto(v, "Message", verifierFilter);
568  verifierFilter.MessageEnd();
569  if (verifierFilter.GetLastResult() == (test == "NotVerify"))
570  SignalTestFailure();
571  }
572  else
573  {
574  SignalTestError();
575  assert(false);
576  }
577 }
578 
579 bool GetField(std::istream &is, std::string &name, std::string &value)
580 {
581  name.resize(0); // GCC workaround: 2.95.3 doesn't have clear()
582  is >> name;
583  if (name.empty())
584  return false;
585 
586  if (name[name.size()-1] != ':')
587  {
588  char c;
589  is >> skipws >> c;
590  if (c != ':')
591  SignalTestError();
592  }
593  else
594  name.erase(name.size()-1);
595 
596  while (is.peek() == ' ')
597  is.ignore(1);
598 
599  // VC60 workaround: getline bug
600  char buffer[128];
601  value.resize(0); // GCC workaround: 2.95.3 doesn't have clear()
602  bool continueLine;
603 
604  do
605  {
606  do
607  {
608  is.get(buffer, sizeof(buffer));
609  value += buffer;
610  }
611  while (buffer[0] != 0);
612  is.clear();
613  is.ignore();
614 
615  if (!value.empty() && value[value.size()-1] == '\r')
616  value.resize(value.size()-1);
617 
618  if (!value.empty() && value[value.size()-1] == '\\')
619  {
620  value.resize(value.size()-1);
621  continueLine = true;
622  }
623  else
624  continueLine = false;
625 
626  std::string::size_type i = value.find('#');
627  if (i != std::string::npos)
628  value.erase(i);
629  }
630  while (continueLine);
631 
632  return true;
633 }
634 
635 void OutputPair(const NameValuePairs &v, const char *name)
636 {
637  Integer x;
638  bool b = v.GetValue(name, x);
639  assert(b);
640  cout << name << ": \\\n ";
641  x.Encode(HexEncoder(new FileSink(cout), false, 64, "\\\n ").Ref(), x.MinEncodedSize());
642  cout << endl;
643 }
644 
645 void OutputNameValuePairs(const NameValuePairs &v)
646 {
647  std::string names = v.GetValueNames();
648  string::size_type i = 0;
649  while (i < names.size())
650  {
651  string::size_type j = names.find_first_of (';', i);
652 
653  if (j == string::npos)
654  return;
655  else
656  {
657  std::string name = names.substr(i, j-i);
658  if (name.find(':') == string::npos)
659  OutputPair(v, name.c_str());
660  }
661 
662  i = j + 1;
663  }
664 }
665 
666 void TestDataFile(const std::string &filename, const NameValuePairs &overrideParameters, unsigned int &totalTests, unsigned int &failedTests)
667 {
668  std::ifstream file(filename.c_str());
669  if (!file.good())
670  throw Exception(Exception::OTHER_ERROR, "Can not open file " + filename + " for reading");
671  TestData v;
672  s_currentTestData = &v;
673  std::string name, value, lastAlgName;
674 
675  while (file)
676  {
677  while (file.peek() == '#')
678  file.ignore(INT_MAX, '\n');
679 
680  if (file.peek() == '\n' || file.peek() == '\r')
681  v.clear();
682 
683  if (!GetField(file, name, value))
684  break;
685  v[name] = value;
686 
687  if (name == "Test")
688  {
689  bool failed = true;
690  std::string algType = GetRequiredDatum(v, "AlgorithmType");
691 
692  if (lastAlgName != GetRequiredDatum(v, "Name"))
693  {
694  lastAlgName = GetRequiredDatum(v, "Name");
695  cout << "\nTesting " << algType.c_str() << " algorithm " << lastAlgName.c_str() << ".\n";
696  }
697 
698  try
699  {
700  if (algType == "Signature")
701  TestSignatureScheme(v);
702  else if (algType == "SymmetricCipher")
703  TestSymmetricCipher(v, overrideParameters);
704  else if (algType == "AuthenticatedSymmetricCipher")
705  TestAuthenticatedSymmetricCipher(v, overrideParameters);
706  else if (algType == "AsymmetricCipher")
707  TestAsymmetricCipher(v);
708  else if (algType == "MessageDigest")
709  TestDigestOrMAC(v, true);
710  else if (algType == "MAC")
711  TestDigestOrMAC(v, false);
712  else if (algType == "FileList")
713  TestDataFile(GetRequiredDatum(v, "Test"), g_nullNameValuePairs, totalTests, failedTests);
714  else
715  SignalTestError();
716  failed = false;
717  }
718  catch (TestFailure &)
719  {
720  cout << "\nTest failed.\n";
721  }
722  catch (CryptoPP::Exception &e)
723  {
724  cout << "\nCryptoPP::Exception caught: " << e.what() << endl;
725  }
726  catch (std::exception &e)
727  {
728  cout << "\nstd::exception caught: " << e.what() << endl;
729  }
730 
731  if (failed)
732  {
733  cout << "Skipping to next test.\n";
734  failedTests++;
735  }
736  else
737  cout << "." << flush;
738 
739  totalTests++;
740  }
741  }
742 }
743 
744 bool RunTestDataFile(const char *filename, const NameValuePairs &overrideParameters)
745 {
746  unsigned int totalTests = 0, failedTests = 0;
747  TestDataFile(filename, overrideParameters, totalTests, failedTests);
748  cout << dec << "\nTests complete. Total tests = " << totalTests << ". Failed tests = " << failedTests << ".\n";
749  if (failedTests != 0)
750  cout << "SOME TESTS FAILED!\n";
751  return failedTests == 0;
752 }