1 // test.cpp - originally written and placed in the public domain by Wei Dai
2 //            CryptoPP::Test namespace added by JW in February 2017
3 //            scoped_main added to CryptoPP::Test namespace by JW in July 2017
4 //            Also see http://github.com/weidai11/cryptopp/issues/447
5 
6 #define CRYPTOPP_DEFAULT_NO_DLL
7 #define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1
8 
9 #include "dll.h"
10 #include "cryptlib.h"
11 #include "aes.h"
12 #include "filters.h"
13 #include "md5.h"
14 #include "ripemd.h"
15 #include "rng.h"
16 #include "gzip.h"
17 #include "default.h"
18 #include "randpool.h"
19 #include "ida.h"
20 #include "base64.h"
21 #include "factory.h"
22 #include "whrlpool.h"
23 #include "tiger.h"
24 #include "smartptr.h"
25 #include "pkcspad.h"
26 #include "stdcpp.h"
27 #include "osrng.h"
28 #include "ossig.h"
29 #include "trap.h"
30 
31 #include "validate.h"
32 #include "bench.h"
33 
34 #include <iostream>
35 #include <sstream>
36 #include <locale>
37 #include <cstdlib>
38 #include <ctime>
39 
40 #ifdef CRYPTOPP_WIN32_AVAILABLE
41 #define WIN32_LEAN_AND_MEAN
42 #include <windows.h>
43 #endif
44 
45 #if defined(CRYPTOPP_UNIX_AVAILABLE) || defined(CRYPTOPP_BSD_AVAILABLE)
46 #include <sys/types.h>
47 #include <sys/stat.h>
48 #include <unistd.h>
49 #define UNIX_PATH_FAMILY 1
50 #endif
51 
52 #if defined(CRYPTOPP_OSX_AVAILABLE)
53 #include <sys/types.h>
54 #include <sys/stat.h>
55 #include <unistd.h>
56 #include <mach-o/dyld.h>
57 #define UNIX_PATH_FAMILY 1
58 #endif
59 
60 #if (_MSC_VER >= 1000)
61 #include <crtdbg.h>		// for the debug heap
62 #endif
63 
64 #if defined(__MWERKS__) && defined(macintosh)
65 #include <console.h>
66 #endif
67 
68 #ifdef _OPENMP
69 # include <omp.h>
70 #endif
71 
72 #ifdef __BORLANDC__
73 #pragma comment(lib, "cryptlib_bds.lib")
74 #endif
75 
76 // Aggressive stack checking with VS2005 SP1 and above.
77 #if (_MSC_FULL_VER >= 140050727)
78 # pragma strict_gs_check (on)
79 #endif
80 
81 // If CRYPTOPP_USE_AES_GENERATOR is 1 then AES/OFB based is used.
82 // Otherwise the OS random number generator is used.
83 #define CRYPTOPP_USE_AES_GENERATOR 1
84 
85 // Global namespace, provided by other source files
86 void FIPS140_SampleApplication();
87 void RegisterFactories(CryptoPP::Test::TestClass suites);
88 int (*AdhocTest)(int argc, char *argv[]) = NULLPTR;
89 
90 NAMESPACE_BEGIN(CryptoPP)
91 NAMESPACE_BEGIN(Test)
92 
93 const int MAX_PHRASE_LENGTH = 250;
94 const int GLOBAL_SEED_LENGTH = 16;
95 std::string g_argvPathHint="";
96 
97 void GenerateRSAKey(unsigned int keyLength, const char *privFilename, const char *pubFilename, const char *seed);
98 std::string RSAEncryptString(const char *pubFilename, const char *seed, const char *message);
99 std::string RSADecryptString(const char *privFilename, const char *ciphertext);
100 void RSASignFile(const char *privFilename, const char *messageFilename, const char *signatureFilename);
101 bool RSAVerifyFile(const char *pubFilename, const char *messageFilename, const char *signatureFilename);
102 
103 void DigestFile(const char *file);
104 void HmacFile(const char *hexKey, const char *file);
105 
106 void AES_CTR_Encrypt(const char *hexKey, const char *hexIV, const char *infile, const char *outfile);
107 
108 std::string EncryptString(const char *plaintext, const char *passPhrase);
109 std::string DecryptString(const char *ciphertext, const char *passPhrase);
110 
111 void EncryptFile(const char *in, const char *out, const char *passPhrase);
112 void DecryptFile(const char *in, const char *out, const char *passPhrase);
113 
114 void SecretShareFile(int threshold, int nShares, const char *filename, const char *seed);
115 void SecretRecoverFile(int threshold, const char *outFilename, char *const *inFilenames);
116 
117 void InformationDisperseFile(int threshold, int nShares, const char *filename);
118 void InformationRecoverFile(int threshold, const char *outFilename, char *const *inFilenames);
119 
120 void GzipFile(const char *in, const char *out, int deflate_level);
121 void GunzipFile(const char *in, const char *out);
122 
123 void Base64Encode(const char *infile, const char *outfile);
124 void Base64Decode(const char *infile, const char *outfile);
125 void HexEncode(const char *infile, const char *outfile);
126 void HexDecode(const char *infile, const char *outfile);
127 
128 void FIPS140_GenerateRandomFiles();
129 
130 bool Validate(int, bool);
131 bool SetGlobalSeed(int argc, char* argv[], std::string& seed);
132 void SetArgvPathHint(const char* argv0, std::string& pathHint);
133 
134 ANONYMOUS_NAMESPACE_BEGIN
135 #if (CRYPTOPP_USE_AES_GENERATOR)
136 OFB_Mode<AES>::Encryption s_globalRNG;
137 #else
138 NonblockingRng s_globalRNG;
139 #endif
140 NAMESPACE_END
141 
GlobalRNG()142 RandomNumberGenerator & GlobalRNG()
143 {
144 	return dynamic_cast<RandomNumberGenerator&>(s_globalRNG);
145 }
146 
147 // Global seed used for the self tests
148 std::string s_globalSeed;
149 void PrintSeedAndThreads();
150 
151 // See misc.h and trap.h for comments and usage
152 #if defined(CRYPTOPP_DEBUG) && defined(UNIX_SIGNALS_AVAILABLE)
153 static const SignalHandler<SIGTRAP, false> s_dummyHandler;
154 // static const DebugTrapHandler s_dummyHandler;
155 #endif
156 
scoped_main(int argc,char * argv[])157 int scoped_main(int argc, char *argv[])
158 {
159 #ifdef _CRTDBG_LEAK_CHECK_DF
160 	// Turn on leak-checking
161 	int tempflag = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG );
162 	tempflag |= _CRTDBG_LEAK_CHECK_DF;
163 	_CrtSetDbgFlag( tempflag );
164 #endif
165 
166 #ifdef _SUNPRO_CC
167 	// No need for thread safety for the test program
168 	cout.set_safe_flag(stream_MT::unsafe_object);
169 	cin.set_safe_flag(stream_MT::unsafe_object);
170 #endif
171 
172 	try
173 	{
174 		RegisterFactories(All);
175 
176 		// A hint to help locate TestData/ and TestVectors/ after install.
177 		SetArgvPathHint(argv[0], g_argvPathHint);
178 
179 		// Set a seed for reproducible results. If the seed is too short then
180 		// it is padded with spaces. If the seed is missing then time() is used.
181 		// For example:
182 		//   ./cryptest.exe v seed=abcdefg
183 		SetGlobalSeed(argc, argv, s_globalSeed);
184 
185 #if (CRYPTOPP_USE_AES_GENERATOR)
186 		// Fetch the SymmetricCipher interface, not the RandomNumberGenerator
187 		//  interface, to key the underlying cipher. If CRYPTOPP_USE_AES_GENERATOR is 1
188 		//  then AES/OFB based is used. Otherwise the OS random number generator is used.
189 		SymmetricCipher& cipher = dynamic_cast<SymmetricCipher&>(GlobalRNG());
190 		cipher.SetKeyWithIV((byte *)s_globalSeed.data(), s_globalSeed.size(), (byte *)s_globalSeed.data());
191 #endif
192 
193 		std::string command, executableName, macFilename;
194 
195 		if (argc < 2)
196 			command = 'h';
197 		else
198 			command = argv[1];
199 
200 		if (command == "g")
201 		{
202 			char thisSeed[1024], privFilename[128], pubFilename[128];
203 			unsigned int keyLength;
204 
205 			std::cout << "Key length in bits: ";
206 			std::cin >> keyLength;
207 
208 			std::cout << "\nSave private key to file: ";
209 			std::cin >> privFilename;
210 
211 			std::cout << "\nSave public key to file: ";
212 			std::cin >> pubFilename;
213 
214 			std::cout << "\nRandom Seed: ";
215 			std::ws(std::cin);
216 			std::cin.getline(thisSeed, 1024);
217 
218 			GenerateRSAKey(keyLength, privFilename, pubFilename, thisSeed);
219 		}
220 		else if (command == "rs")
221 			RSASignFile(argv[2], argv[3], argv[4]);
222 		else if (command == "rv")
223 		{
224 			bool verified = RSAVerifyFile(argv[2], argv[3], argv[4]);
225 			std::cout << (verified ? "valid signature" : "invalid signature") << std::endl;
226 		}
227 		else if (command == "r")
228 		{
229 			char privFilename[128], pubFilename[128];
230 			char thisSeed[1024], message[1024];
231 
232 			std::cout << "Private key file: ";
233 			std::cin >> privFilename;
234 
235 			std::cout << "\nPublic key file: ";
236 			std::cin >> pubFilename;
237 
238 			std::cout << "\nRandom Seed: ";
239 			std::ws(std::cin);
240 			std::cin.getline(thisSeed, 1024);
241 
242 			std::cout << "\nMessage: ";
243 			std::cin.getline(message, 1024);
244 
245 			std::string ciphertext = RSAEncryptString(pubFilename, thisSeed, message);
246 			std::cout << "\nCiphertext: " << ciphertext << std::endl;
247 
248 			std::string decrypted = RSADecryptString(privFilename, ciphertext.c_str());
249 			std::cout << "\nDecrypted: " << decrypted << std::endl;
250 		}
251 		else if (command == "mt")
252 		{
253 			MaurerRandomnessTest mt;
254 			FileStore fs(argv[2]);
255 			fs.TransferAllTo(mt);
256 			std::cout << "Maurer Test Value: " << mt.GetTestValue() << std::endl;
257 		}
258 		else if (command == "mac_dll")
259 		{
260 			std::string fname(argv[2] ? argv[2] : "");
261 
262 			// sanity check on file size
263 			std::fstream dllFile(fname.c_str(), std::ios::in | std::ios::out | std::ios::binary);
264 			if (!dllFile.good())
265 			{
266 				std::cerr << "Failed to open file \"" << fname << "\"\n";
267 				return 1;
268 			}
269 
270 			std::ifstream::pos_type fileEnd = dllFile.seekg(0, std::ios_base::end).tellg();
271 			if (fileEnd > 20*1000*1000)
272 			{
273 				std::cerr << "Input file " << fname << " is too large";
274 				std::cerr << "(size is " << fileEnd << ").\n";
275 				return 1;
276 			}
277 
278 			// read file into memory
279 			unsigned int fileSize = (unsigned int)fileEnd;
280 			SecByteBlock buf(fileSize);
281 			dllFile.seekg(0, std::ios_base::beg);
282 			dllFile.read((char *)buf.begin(), fileSize);
283 
284 			// find positions of relevant sections in the file, based on version 8 of documentation from http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx
285 			word32 coffPos = *(word16 *)(void *)(buf+0x3c);
286 			word32 optionalHeaderPos = coffPos + 24;
287 			word16 optionalHeaderMagic = *(word16 *)(void *)(buf+optionalHeaderPos);
288 			if (optionalHeaderMagic != 0x10b && optionalHeaderMagic != 0x20b)
289 			{
290 				std::cerr << "Target file is not a PE32 or PE32+ image.\n";
291 				return 3;
292 			}
293 			word32 checksumPos = optionalHeaderPos + 64;
294 			word32 certificateTableDirectoryPos = optionalHeaderPos + (optionalHeaderMagic == 0x10b ? 128 : 144);
295 			word32 certificateTablePos = *(word32 *)(void *)(buf+certificateTableDirectoryPos);
296 			word32 certificateTableSize = *(word32 *)(void *)(buf+certificateTableDirectoryPos+4);
297 			if (certificateTableSize != 0)
298 				std::cerr << "Warning: certificate table (IMAGE_DIRECTORY_ENTRY_SECURITY) of target image is not empty.\n";
299 
300 			// find where to place computed MAC
301 			byte mac[] = CRYPTOPP_DUMMY_DLL_MAC;
302 			byte *found = std::search(buf.begin(), buf.end(), mac+0, mac+sizeof(mac));
303 			if (found == buf.end())
304 			{
305 				std::cerr << "MAC placeholder not found. The MAC may already be placed.\n";
306 				return 2;
307 			}
308 			word32 macPos = (unsigned int)(found-buf.begin());
309 
310 			// compute MAC
311 			member_ptr<MessageAuthenticationCode> pMac(NewIntegrityCheckingMAC());
312 			CRYPTOPP_ASSERT(pMac->DigestSize() == sizeof(mac));
313 			MeterFilter f(new HashFilter(*pMac, new ArraySink(mac, sizeof(mac))));
314 			f.AddRangeToSkip(0, checksumPos, 4);
315 			f.AddRangeToSkip(0, certificateTableDirectoryPos, 8);
316 			f.AddRangeToSkip(0, macPos, sizeof(mac));
317 			f.AddRangeToSkip(0, certificateTablePos, certificateTableSize);
318 			f.PutMessageEnd(buf.begin(), buf.size());
319 
320 			// Encode MAC
321 			std::string hexMac;
322 			HexEncoder encoder;
323 			encoder.Put(mac, sizeof(mac)), encoder.MessageEnd();
324 			hexMac.resize(static_cast<size_t>(encoder.MaxRetrievable()));
325 			encoder.Get(reinterpret_cast<byte*>(&hexMac[0]), hexMac.size());
326 
327 			// Report MAC and location
328 			std::cout << "Placing MAC " << hexMac << " in " << fname << " at file offset " << macPos;
329 			std::cout << " (0x" << std::hex << macPos << std::dec << ").\n";
330 
331 			// place MAC
332 			dllFile.seekg(macPos, std::ios_base::beg);
333 			dllFile.write((char *)mac, sizeof(mac));
334 		}
335 		else if (command == "m")
336 			DigestFile(argv[2]);
337 		else if (command == "tv")
338 		{
339 			// TestDataFile() adds CRYPTOPP_DATA_DIR as required
340 			std::string fname = (argv[2] ? argv[2] : "all");
341 			if (fname.find(".txt") == std::string::npos)
342 				fname += ".txt";
343 			if (fname.find("TestVectors") == std::string::npos)
344 				fname = "TestVectors/" + fname;
345 
346 			PrintSeedAndThreads();
347 			return !RunTestDataFile(fname.c_str());
348 		}
349 		else if (command == "t")
350 		{
351 			// VC60 workaround: use char array instead of std::string to workaround MSVC's getline bug
352 			char passPhrase[MAX_PHRASE_LENGTH], plaintext[1024];
353 
354 			std::cout << "Passphrase: ";
355 			std::cin.getline(passPhrase, MAX_PHRASE_LENGTH);
356 
357 			std::cout << "\nPlaintext: ";
358 			std::cin.getline(plaintext, sizeof(plaintext));
359 
360 			std::string ciphertext = EncryptString(plaintext, passPhrase);
361 			std::cout << "\nCiphertext: " << ciphertext << std::endl;
362 
363 			std::string decrypted = DecryptString(ciphertext.c_str(), passPhrase);
364 			std::cout << "\nDecrypted: " << decrypted << std::endl;
365 
366 			return 0;
367 		}
368 		else if (command == "e64")
369 			Base64Encode(argv[2], argv[3]);
370 		else if (command == "d64")
371 			Base64Decode(argv[2], argv[3]);
372 		else if (command == "e16")
373 			HexEncode(argv[2], argv[3]);
374 		else if (command == "d16")
375 			HexDecode(argv[2], argv[3]);
376 		else if (command == "e" || command == "d")
377 		{
378 			char passPhrase[MAX_PHRASE_LENGTH];
379 			std::cout << "Passphrase: ";
380 			std::cin.getline(passPhrase, MAX_PHRASE_LENGTH);
381 			if (command == "e")
382 				EncryptFile(argv[2], argv[3], passPhrase);
383 			else
384 				DecryptFile(argv[2], argv[3], passPhrase);
385 		}
386 		else if (command == "ss")
387 		{
388 			char thisSeed[1024];
389 			std::cout << "\nRandom Seed: ";
390 			std::ws(std::cin);
391 			std::cin.getline(thisSeed, sizeof(thisSeed));
392 			SecretShareFile(StringToValue<int, true>(argv[2]), StringToValue<int, true>(argv[3]), argv[4], thisSeed);
393 		}
394 		else if (command == "sr")
395 			SecretRecoverFile(argc-3, argv[2], argv+3);
396 		else if (command == "id")
397 			InformationDisperseFile(StringToValue<int, true>(argv[2]), StringToValue<int, true>(argv[3]), argv[4]);
398 		else if (command == "ir")
399 			InformationRecoverFile(argc-3, argv[2], argv+3);
400 		else if (command == "v" || command == "vv")
401 			return !Validate(argc>2 ? StringToValue<int, true>(argv[2]) : 0, argv[1][1] == 'v');
402 		else if (command.substr(0,1) == "b") // "b", "b1", "b2", ...
403 			BenchmarkWithCommand(argc, argv);
404 		else if (command == "z")
405 			GzipFile(argv[3], argv[4], argv[2][0]-'0');
406 		else if (command == "u")
407 			GunzipFile(argv[2], argv[3]);
408 		else if (command == "fips")
409 			FIPS140_SampleApplication();
410 		else if (command == "fips-rand")
411 			FIPS140_GenerateRandomFiles();
412 		else if (command == "a")
413 		{
414 			if (AdhocTest)
415 				return (*AdhocTest)(argc, argv);
416 			else
417 			{
418 				std::cerr << "AdhocTest not defined.\n";
419 				return 1;
420 			}
421 		}
422 		else if (command == "hmac")
423 			HmacFile(argv[2], argv[3]);
424 		else if (command == "ae")
425 			AES_CTR_Encrypt(argv[2], argv[3], argv[4], argv[5]);
426 		else if (command == "h")
427 		{
428 			FileSource usage(DataDir("TestData/usage.dat").c_str(), true, new FileSink(std::cout));
429 			return 1;
430 		}
431 		else if (command == "V")
432 		{
433 			std::cout << CRYPTOPP_VERSION / 100 << '.' << (CRYPTOPP_VERSION % 100) / 10 << '.' << CRYPTOPP_VERSION % 10 << std::endl;
434 		}
435 		else
436 		{
437 			std::cerr << "Unrecognized command. Run \"cryptest h\" to obtain usage information.\n";
438 			return 1;
439 		}
440 		return 0;
441 	}
442 	catch(const Exception &e)
443 	{
444 		std::cout << "\nException caught: " << e.what() << std::endl;
445 		return -1;
446 	}
447 	catch(const std::exception &e)
448 	{
449 		std::cout << "\nstd::exception caught: " << e.what() << std::endl;
450 		return -2;
451 	}
452 } // main()
453 
SetGlobalSeed(int argc,char * argv[],std::string & seed)454 bool SetGlobalSeed(int argc, char* argv[], std::string& seed)
455 {
456 	bool ret = false;
457 
458 	for (int i=0; i<argc; ++i)
459 	{
460 		std::string arg(argv[i]);
461 		std::string::size_type pos = arg.find("seed=");
462 
463 		if (pos != std::string::npos)
464 		{
465 			// length of "seed=" is 5
466 			seed = arg.substr(pos+5);
467 			ret = true; goto finish;
468 		}
469 	}
470 
471 	// Use a random seed if none is provided
472 	if (s_globalSeed.empty())
473 		s_globalSeed = IntToString(time(NULLPTR));
474 
475 finish:
476 
477 	// Some editors have problems with '\0' fill characters when redirecting output.
478 	s_globalSeed.resize(GLOBAL_SEED_LENGTH, ' ');
479 
480 	return ret;
481 }
482 
SetArgvPathHint(const char * argv0,std::string & pathHint)483 void SetArgvPathHint(const char* argv0, std::string& pathHint)
484 {
485 # if (PATH_MAX > 0)  // Posix
486 	size_t path_max = (size_t)PATH_MAX;
487 #elif (MAX_PATH > 0)  // Microsoft
488 	size_t path_max = (size_t)MAX_PATH;
489 #else
490 	size_t path_max = 260;
491 #endif
492 
493 	// OS X and Solaris provide a larger path using pathconf than MAX_PATH.
494 	// Also see https://stackoverflow.com/a/33249023/608639 for FreeBSD.
495 #if defined(_PC_PATH_MAX)
496 	long ret = pathconf(argv0, _PC_PATH_MAX);
497 	const size_t old_path_max = path_max;
498 	if (SafeConvert(ret, path_max) == false)
499 		path_max = old_path_max;
500 #endif
501 
502 	const size_t argLen = std::strlen(argv0);
503 	if (argLen >= path_max)
504 		return; // Can't use realpath safely
505 	pathHint = std::string(argv0, argLen);
506 
507 #if defined(AT_EXECFN)
508 	if (getauxval(AT_EXECFN))
509 		pathHint = getauxval(AT_EXECFN);
510 #elif defined(_MSC_VER) && (_MSC_VER > 1310)
511 	char* pgmptr = NULLPTR;
512 	errno_t err = _get_pgmptr(&pgmptr);
513 	if (err == 0 && pgmptr != NULLPTR)
514 		pathHint = pgmptr;
515 #elif defined(__MINGW32__) || defined(__MINGW64__)
516 	std::string t(path_max, (char)0);
517 	if (_fullpath(&t[0], pathHint.c_str(), path_max))
518 	{
519 		t.resize(strlen(t.c_str()));
520 		std::swap(pathHint, t);
521 	}
522 #elif defined(CRYPTOPP_OSX_AVAILABLE)
523 	std::string t(path_max, (char)0);
524 	unsigned int len = (unsigned int)t.size();
525 	if (_NSGetExecutablePath(&t[0], &len) == 0)
526 	{
527 		t.resize(len);
528 		std::swap(pathHint, t);
529 	}
530 #elif defined(sun) || defined(__sun)
531 	if (getexecname())
532 		pathHint = getexecname();
533 #endif
534 
535 #if defined(__MINGW32__) || defined(__MINGW64__)
536 	// This path exists to stay out of the Posix paths that follow
537 	;;
538 #elif (_POSIX_C_SOURCE >= 200809L) || (_XOPEN_SOURCE >= 700)
539 	char* resolved = realpath (pathHint.c_str(), NULLPTR);
540 	if (resolved != NULLPTR)
541 	{
542 		pathHint = resolved;
543 		std::free(resolved);
544 	}
545 #elif defined(UNIX_PATH_FAMILY)
546 	std::string resolved(path_max, (char)0);
547 	char* r = realpath (pathHint.c_str(), &resolved[0]);
548 	if (r != NULLPTR)
549 	{
550 		resolved.resize(std::strlen(&resolved[0]));
551 		std::swap(pathHint, resolved);
552 	}
553 #endif
554 
555 #if defined(UNIX_PATH_FAMILY)
556 	// Is it possible for realpath to fail?
557 	struct stat buf; int x;
558 	x = lstat(pathHint.c_str(), &buf);
559 	if (x != 0 || S_ISLNK(buf.st_mode))
560 		pathHint.clear();
561 #endif
562 
563 	// Trim the executable name, leave the path with a slash.
564 	std::string::size_type pos = pathHint.find_last_of("\\/");
565 	if (pos != std::string::npos)
566 		pathHint.erase(pos+1);
567 }
568 
FIPS140_GenerateRandomFiles()569 void FIPS140_GenerateRandomFiles()
570 {
571 #ifdef OS_RNG_AVAILABLE
572 	DefaultAutoSeededRNG rng;
573 	RandomNumberStore store(rng, ULONG_MAX);
574 
575 	for (unsigned int i=0; i<100000; i++)
576 		store.TransferTo(FileSink((IntToString(i) + ".rnd").c_str()).Ref(), 20000);
577 #else
578 	std::cout << "OS provided RNG not available.\n";
579 	exit(-1);
580 #endif
581 }
582 
PrintSeedAndThreads()583 void PrintSeedAndThreads()
584 {
585 	std::cout << "Using seed: " << s_globalSeed << std::endl;
586 
587 #ifdef _OPENMP
588 	int tc = 0;
589 	#pragma omp parallel
590 	{
591 		tc = omp_get_num_threads();
592 	}
593 
594 	std::cout << "OpenMP version " << (int)_OPENMP << ", ";
595 	std::cout << tc << (tc == 1 ? " thread" : " threads") << std::endl;
596 #endif
597 }
598 
HexDecodeString(const char * hex)599 SecByteBlock HexDecodeString(const char *hex)
600 {
601 	StringSource ss(hex, true, new HexDecoder);
602 	SecByteBlock result((size_t)ss.MaxRetrievable());
603 	ss.Get(result, result.size());
604 	return result;
605 }
606 
GenerateRSAKey(unsigned int keyLength,const char * privFilename,const char * pubFilename,const char * seed)607 void GenerateRSAKey(unsigned int keyLength, const char *privFilename, const char *pubFilename, const char *seed)
608 {
609 	// DEREncode() changed to Save() at Issue 569.
610 	RandomPool randPool;
611 	randPool.IncorporateEntropy((byte *)seed, strlen(seed));
612 
613 	RSAES_OAEP_SHA_Decryptor priv(randPool, keyLength);
614 	HexEncoder privFile(new FileSink(privFilename));
615 	priv.AccessMaterial().Save(privFile);
616 	privFile.MessageEnd();
617 
618 	RSAES_OAEP_SHA_Encryptor pub(priv);
619 	HexEncoder pubFile(new FileSink(pubFilename));
620 	pub.AccessMaterial().Save(pubFile);
621 	pubFile.MessageEnd();
622 }
623 
RSAEncryptString(const char * pubFilename,const char * seed,const char * message)624 std::string RSAEncryptString(const char *pubFilename, const char *seed, const char *message)
625 {
626 	FileSource pubFile(pubFilename, true, new HexDecoder);
627 	RSAES_OAEP_SHA_Encryptor pub(pubFile);
628 
629 	RandomPool randPool;
630 	randPool.IncorporateEntropy((byte *)seed, strlen(seed));
631 
632 	std::string result;
633 	StringSource(message, true, new PK_EncryptorFilter(randPool, pub, new HexEncoder(new StringSink(result))));
634 	return result;
635 }
636 
RSADecryptString(const char * privFilename,const char * ciphertext)637 std::string RSADecryptString(const char *privFilename, const char *ciphertext)
638 {
639 	FileSource privFile(privFilename, true, new HexDecoder);
640 	RSAES_OAEP_SHA_Decryptor priv(privFile);
641 
642 	std::string result;
643 	StringSource(ciphertext, true, new HexDecoder(new PK_DecryptorFilter(GlobalRNG(), priv, new StringSink(result))));
644 	return result;
645 }
646 
RSASignFile(const char * privFilename,const char * messageFilename,const char * signatureFilename)647 void RSASignFile(const char *privFilename, const char *messageFilename, const char *signatureFilename)
648 {
649 	FileSource privFile(privFilename, true, new HexDecoder);
650 	RSASS<PKCS1v15, SHA1>::Signer priv(privFile);
651 	FileSource f(messageFilename, true, new SignerFilter(GlobalRNG(), priv, new HexEncoder(new FileSink(signatureFilename))));
652 }
653 
RSAVerifyFile(const char * pubFilename,const char * messageFilename,const char * signatureFilename)654 bool RSAVerifyFile(const char *pubFilename, const char *messageFilename, const char *signatureFilename)
655 {
656 	FileSource pubFile(pubFilename, true, new HexDecoder);
657 	RSASS<PKCS1v15, SHA1>::Verifier pub(pubFile);
658 
659 	FileSource signatureFile(signatureFilename, true, new HexDecoder);
660 	if (signatureFile.MaxRetrievable() != pub.SignatureLength())
661 		return false;
662 	SecByteBlock signature(pub.SignatureLength());
663 	signatureFile.Get(signature, signature.size());
664 
665 	SignatureVerificationFilter *verifierFilter = new SignatureVerificationFilter(pub);
666 	verifierFilter->Put(signature, pub.SignatureLength());
667 	FileSource f(messageFilename, true, verifierFilter);
668 
669 	return verifierFilter->GetLastResult();
670 }
671 
DigestFile(const char * filename)672 void DigestFile(const char *filename)
673 {
674 	SHA1 sha;
675 	RIPEMD160 ripemd;
676 	SHA256 sha256;
677 	Tiger tiger;
678 	SHA512 sha512;
679 	Whirlpool whirlpool;
680 
681 	vector_member_ptrs<HashFilter> filters(6);
682 	filters[0].reset(new HashFilter(sha));
683 	filters[1].reset(new HashFilter(ripemd));
684 	filters[2].reset(new HashFilter(tiger));
685 	filters[3].reset(new HashFilter(sha256));
686 	filters[4].reset(new HashFilter(sha512));
687 	filters[5].reset(new HashFilter(whirlpool));
688 
689 	member_ptr<ChannelSwitch> channelSwitch(new ChannelSwitch);
690 	size_t i;
691 	for (i=0; i<filters.size(); i++)
692 		channelSwitch->AddDefaultRoute(*filters[i]);
693 	FileSource(filename, true, channelSwitch.release());
694 
695 	HexEncoder encoder(new FileSink(std::cout), false);
696 	for (i=0; i<filters.size(); i++)
697 	{
698 		std::cout << filters[i]->AlgorithmName() << ": ";
699 		filters[i]->TransferTo(encoder);
700 		std::cout << "\n";
701 	}
702 }
703 
HmacFile(const char * hexKey,const char * file)704 void HmacFile(const char *hexKey, const char *file)
705 {
706 	member_ptr<MessageAuthenticationCode> mac;
707 	if (strcmp(hexKey, "selftest") == 0)
708 	{
709 		std::cerr << "Computing HMAC/SHA1 value for self test.\n";
710 		mac.reset(NewIntegrityCheckingMAC());
711 	}
712 	else
713 	{
714 		std::string decodedKey;
715 		StringSource(hexKey, true, new HexDecoder(new StringSink(decodedKey)));
716 		mac.reset(new HMAC<SHA1>((const byte *)decodedKey.data(), decodedKey.size()));
717 	}
718 	FileSource(file, true, new HashFilter(*mac, new HexEncoder(new FileSink(std::cout))));
719 }
720 
AES_CTR_Encrypt(const char * hexKey,const char * hexIV,const char * infile,const char * outfile)721 void AES_CTR_Encrypt(const char *hexKey, const char *hexIV, const char *infile, const char *outfile)
722 {
723 	SecByteBlock key = HexDecodeString(hexKey);
724 	SecByteBlock iv = HexDecodeString(hexIV);
725 	CTR_Mode<AES>::Encryption aes(key, key.size(), iv);
726 	FileSource(infile, true, new StreamTransformationFilter(aes, new FileSink(outfile)));
727 }
728 
EncryptString(const char * instr,const char * passPhrase)729 std::string EncryptString(const char *instr, const char *passPhrase)
730 {
731 	std::string outstr;
732 
733 	DefaultEncryptorWithMAC encryptor(passPhrase, new HexEncoder(new StringSink(outstr)));
734 	encryptor.Put((byte *)instr, strlen(instr));
735 	encryptor.MessageEnd();
736 
737 	return outstr;
738 }
739 
DecryptString(const char * instr,const char * passPhrase)740 std::string DecryptString(const char *instr, const char *passPhrase)
741 {
742 	std::string outstr;
743 
744 	HexDecoder decryptor(new DefaultDecryptorWithMAC(passPhrase, new StringSink(outstr)));
745 	decryptor.Put((byte *)instr, strlen(instr));
746 	decryptor.MessageEnd();
747 
748 	return outstr;
749 }
750 
EncryptFile(const char * in,const char * out,const char * passPhrase)751 void EncryptFile(const char *in, const char *out, const char *passPhrase)
752 {
753 	FileSource f(in, true, new DefaultEncryptorWithMAC(passPhrase, new FileSink(out)));
754 }
755 
DecryptFile(const char * in,const char * out,const char * passPhrase)756 void DecryptFile(const char *in, const char *out, const char *passPhrase)
757 {
758 	FileSource f(in, true, new DefaultDecryptorWithMAC(passPhrase, new FileSink(out)));
759 }
760 
SecretShareFile(int threshold,int nShares,const char * filename,const char * seed)761 void SecretShareFile(int threshold, int nShares, const char *filename, const char *seed)
762 {
763 	CRYPTOPP_ASSERT(nShares >= 1 && nShares<=1000);
764 	if (nShares < 1 || nShares > 1000)
765 		throw InvalidArgument("SecretShareFile: " + IntToString(nShares) + " is not in range [1, 1000]");
766 
767 	RandomPool rng;
768 	rng.IncorporateEntropy((byte *)seed, strlen(seed));
769 
770 	ChannelSwitch *channelSwitch = NULLPTR;
771 	FileSource source(filename, false, new SecretSharing(rng, threshold, nShares, channelSwitch = new ChannelSwitch));
772 
773 	// Be careful of the type of Sink used. An ArraySink will stop writing data once the array
774 	//    is full. Also see http://groups.google.com/forum/#!topic/cryptopp-users/XEKKLCEFH3Y.
775 	vector_member_ptrs<FileSink> fileSinks(nShares);
776 	std::string channel;
777 	for (int i=0; i<nShares; i++)
778 	{
779 		char extension[5] = ".000";
780 		extension[1]='0'+byte(i/100);
781 		extension[2]='0'+byte((i/10)%10);
782 		extension[3]='0'+byte(i%10);
783 		fileSinks[i].reset(new FileSink((std::string(filename)+extension).c_str()));
784 
785 		channel = WordToString<word32>(i);
786 		fileSinks[i]->Put((const byte *)channel.data(), 4);
787 		channelSwitch->AddRoute(channel, *fileSinks[i], DEFAULT_CHANNEL);
788 	}
789 
790 	source.PumpAll();
791 }
792 
SecretRecoverFile(int threshold,const char * outFilename,char * const * inFilenames)793 void SecretRecoverFile(int threshold, const char *outFilename, char *const *inFilenames)
794 {
795 	CRYPTOPP_ASSERT(threshold >= 1 && threshold <=1000);
796 	if (threshold < 1 || threshold > 1000)
797 		throw InvalidArgument("SecretRecoverFile: " + IntToString(threshold) + " is not in range [1, 1000]");
798 
799 	SecretRecovery recovery(threshold, new FileSink(outFilename));
800 
801 	vector_member_ptrs<FileSource> fileSources(threshold);
802 	SecByteBlock channel(4);
803 	int i;
804 	for (i=0; i<threshold; i++)
805 	{
806 		fileSources[i].reset(new FileSource(inFilenames[i], false));
807 		fileSources[i]->Pump(4);
808 		fileSources[i]->Get(channel, 4);
809 		fileSources[i]->Attach(new ChannelSwitch(recovery, std::string((char *)channel.begin(), 4)));
810 	}
811 
812 	while (fileSources[0]->Pump(256))
813 		for (i=1; i<threshold; i++)
814 			fileSources[i]->Pump(256);
815 
816 	for (i=0; i<threshold; i++)
817 		fileSources[i]->PumpAll();
818 }
819 
InformationDisperseFile(int threshold,int nShares,const char * filename)820 void InformationDisperseFile(int threshold, int nShares, const char *filename)
821 {
822 	CRYPTOPP_ASSERT(threshold >= 1 && threshold <=1000);
823 	if (threshold < 1 || threshold > 1000)
824 		throw InvalidArgument("InformationDisperseFile: " + IntToString(nShares) + " is not in range [1, 1000]");
825 
826 	ChannelSwitch *channelSwitch = NULLPTR;
827 	FileSource source(filename, false, new InformationDispersal(threshold, nShares, channelSwitch = new ChannelSwitch));
828 
829 	// Be careful of the type of Sink used. An ArraySink will stop writing data once the array
830 	//    is full. Also see http://groups.google.com/forum/#!topic/cryptopp-users/XEKKLCEFH3Y.
831 	vector_member_ptrs<FileSink> fileSinks(nShares);
832 	std::string channel;
833 	for (int i=0; i<nShares; i++)
834 	{
835 		char extension[5] = ".000";
836 		extension[1]='0'+byte(i/100);
837 		extension[2]='0'+byte((i/10)%10);
838 		extension[3]='0'+byte(i%10);
839 		fileSinks[i].reset(new FileSink((std::string(filename)+extension).c_str()));
840 
841 		channel = WordToString<word32>(i);
842 		fileSinks[i]->Put((const byte *)channel.data(), 4);
843 		channelSwitch->AddRoute(channel, *fileSinks[i], DEFAULT_CHANNEL);
844 	}
845 
846 	source.PumpAll();
847 }
848 
InformationRecoverFile(int threshold,const char * outFilename,char * const * inFilenames)849 void InformationRecoverFile(int threshold, const char *outFilename, char *const *inFilenames)
850 {
851 	CRYPTOPP_ASSERT(threshold<=1000);
852 	if (threshold < 1 || threshold > 1000)
853 		throw InvalidArgument("InformationRecoverFile: " + IntToString(threshold) + " is not in range [1, 1000]");
854 
855 	InformationRecovery recovery(threshold, new FileSink(outFilename));
856 
857 	vector_member_ptrs<FileSource> fileSources(threshold);
858 	SecByteBlock channel(4);
859 	int i;
860 	for (i=0; i<threshold; i++)
861 	{
862 		fileSources[i].reset(new FileSource(inFilenames[i], false));
863 		fileSources[i]->Pump(4);
864 		fileSources[i]->Get(channel, 4);
865 		fileSources[i]->Attach(new ChannelSwitch(recovery, std::string((char *)channel.begin(), 4)));
866 	}
867 
868 	while (fileSources[0]->Pump(256))
869 		for (i=1; i<threshold; i++)
870 			fileSources[i]->Pump(256);
871 
872 	for (i=0; i<threshold; i++)
873 		fileSources[i]->PumpAll();
874 }
875 
GzipFile(const char * in,const char * out,int deflate_level)876 void GzipFile(const char *in, const char *out, int deflate_level)
877 {
878 //	FileSource(in, true, new Gzip(new FileSink(out), deflate_level));
879 
880 	// use a filter graph to compare decompressed data with original
881 	//
882 	// Source ----> Gzip ------> Sink
883 	//    \           |
884 	//	    \       Gunzip
885 	//		  \       |
886 	//		    \     v
887 	//		      > ComparisonFilter
888 
889 	EqualityComparisonFilter comparison;
890 
891 	Gunzip gunzip(new ChannelSwitch(comparison, "0"));
892 	gunzip.SetAutoSignalPropagation(0);
893 
894 	FileSink sink(out);
895 
896 	ChannelSwitch *cs;
897 	Gzip gzip(cs = new ChannelSwitch(sink), deflate_level);
898 	cs->AddDefaultRoute(gunzip);
899 
900 	cs = new ChannelSwitch(gzip);
901 	cs->AddDefaultRoute(comparison, "1");
902 	FileSource source(in, true, cs);
903 
904 	comparison.ChannelMessageSeriesEnd("0");
905 	comparison.ChannelMessageSeriesEnd("1");
906 }
907 
GunzipFile(const char * in,const char * out)908 void GunzipFile(const char *in, const char *out)
909 {
910 	FileSource(in, true, new Gunzip(new FileSink(out)));
911 }
912 
Base64Encode(const char * in,const char * out)913 void Base64Encode(const char *in, const char *out)
914 {
915 	FileSource(in, true, new Base64Encoder(new FileSink(out)));
916 }
917 
Base64Decode(const char * in,const char * out)918 void Base64Decode(const char *in, const char *out)
919 {
920 	FileSource(in, true, new Base64Decoder(new FileSink(out)));
921 }
922 
HexEncode(const char * in,const char * out)923 void HexEncode(const char *in, const char *out)
924 {
925 	FileSource(in, true, new HexEncoder(new FileSink(out)));
926 }
927 
HexDecode(const char * in,const char * out)928 void HexDecode(const char *in, const char *out)
929 {
930 	FileSource(in, true, new HexDecoder(new FileSink(out)));
931 }
932 
Validate(int alg,bool thorough)933 bool Validate(int alg, bool thorough)
934 {
935 	bool result;
936 
937 	g_testBegin = ::time(NULLPTR);
938 	PrintSeedAndThreads();
939 
940 	// TODO: we need to group these tests like benchmarks...
941 	switch (alg)
942 	{
943 	case 0: result = ValidateAll(thorough); break;
944 	case 1: result = TestSettings(); break;
945 	case 2: result = TestOS_RNG(); break;
946 //	case 3: result = TestSecRandom(); break;
947 	case 4: result = ValidateMD5(); break;
948 	case 5: result = ValidateSHA(); break;
949 	case 6: result = ValidateDES(); break;
950 	case 7: result = ValidateIDEA(); break;
951 	case 8: result = ValidateARC4(); break;
952 	case 9: result = ValidateRC5(); break;
953 	case 10: result = ValidateBlowfish(); break;
954 //	case 11: result = ValidateDiamond2(); break;
955 	case 12: result = ValidateThreeWay(); break;
956 	case 13: result = ValidateBBS(); break;
957 	case 14: result = ValidateDH(); break;
958 	case 15: result = ValidateX25519(); break;
959 	case 16: result = ValidateRSA(); break;
960 	case 17: result = ValidateElGamal(); break;
961 	case 18: result = ValidateDSA(thorough); break;
962 //	case 18: result = ValidateHAVAL(); break;
963 	case 19: result = ValidateSAFER(); break;
964 	case 20: result = ValidateLUC(); break;
965 	case 21: result = ValidateRabin(); break;
966 //	case 22: result = ValidateBlumGoldwasser(); break;
967 	case 23: result = ValidateECP(); break;
968 	case 24: result = ValidateEC2N(); break;
969 //	case 25: result = ValidateMD5MAC(); break;
970 	case 26: result = ValidateGOST(); break;
971 	case 27: result = ValidateTiger(); break;
972 	case 28: result = ValidateRIPEMD(); break;
973 	case 29: result = ValidateHMAC(); break;
974 //	case 30: result = ValidateXMACC(); break;
975 	case 31: result = ValidateSHARK(); break;
976 	case 32: result = ValidateLUC_DH(); break;
977 	case 33: result = ValidateLUC_DL(); break;
978 	case 34: result = ValidateSEAL(); break;
979 	case 35: result = ValidateCAST(); break;
980 	case 36: result = ValidateSquare(); break;
981 	case 37: result = ValidateRC2(); break;
982 	case 38: result = ValidateRC6(); break;
983 	case 39: result = ValidateMARS(); break;
984 	case 40: result = ValidateRW(); break;
985 	case 41: result = ValidateMD2(); break;
986 	case 42: result = ValidateNR(); break;
987 	case 43: result = ValidateMQV(); break;
988 	case 44: result = ValidateRijndael(); break;
989 	case 45: result = ValidateTwofish(); break;
990 	case 46: result = ValidateSerpent(); break;
991 	case 47: result = ValidateCipherModes(); break;
992 	case 48: result = ValidateCRC32(); break;
993 	case 49: result = ValidateCRC32C(); break;
994 	case 50: result = ValidateECDSA(); break;
995 	case 51: result = ValidateECGDSA(thorough); break;
996 	case 52: result = ValidateXTR_DH(); break;
997 	case 53: result = ValidateSKIPJACK(); break;
998 	case 54: result = ValidateSHA2(); break;
999 	case 55: result = ValidatePanama(); break;
1000 	case 56: result = ValidateAdler32(); break;
1001 	case 57: result = ValidateMD4(); break;
1002 	case 58: result = ValidatePBKDF(); break;
1003 	case 59: result = ValidateHKDF(); break;
1004 	case 60: result = ValidateScrypt(); break;
1005 	case 61: result = ValidateESIGN(); break;
1006 	case 62: result = ValidateDLIES(); break;
1007 	case 63: result = ValidateBaseCode(); break;
1008 	case 64: result = ValidateSHACAL2(); break;
1009 	case 65: result = ValidateARIA(); break;
1010 	case 66: result = ValidateCamellia(); break;
1011 	case 67: result = ValidateWhirlpool(); break;
1012 	case 68: result = ValidateTTMAC(); break;
1013 	case 70: result = ValidateSalsa(); break;
1014 	case 71: result = ValidateChaCha(); break;
1015 	case 72: result = ValidateChaChaTLS(); break;
1016 	case 73: result = ValidateSosemanuk(); break;
1017 	case 74: result = ValidateRabbit(); break;
1018 	case 75: result = ValidateHC128(); break;
1019 	case 76: result = ValidateHC256(); break;
1020 	case 80: result = ValidateVMAC(); break;
1021 	case 81: result = ValidateCCM(); break;
1022 	case 82: result = ValidateGCM(); break;
1023 	case 83: result = ValidateXTS(); break;
1024 	case 84: result = ValidateCMAC(); break;
1025 	case 85: result = ValidateSM3(); break;
1026 	case 86: result = ValidateBLAKE2s(); break;
1027 	case 87: result = ValidateBLAKE2b(); break;
1028 	case 88: result = ValidatePoly1305(); break;
1029 	case 89: result = ValidateSipHash(); break;
1030 	case 90: result = ValidateHashDRBG(); break;
1031 	case 91: result = ValidateHmacDRBG(); break;
1032 	case 92: result = ValidateNaCl(); break;
1033 
1034 	case 100: result = ValidateCHAM(); break;
1035 	case 101: result = ValidateSIMECK(); break;
1036 	case 102: result = ValidateSIMON(); break;
1037 	case 103: result = ValidateSPECK(); break;
1038 
1039 	case 110: result = ValidateSHA3(); break;
1040 	case 111: result = ValidateSHAKE(); break;
1041 	case 112: result = ValidateSHAKE_XOF(); break;
1042 
1043 	case 120: result = ValidateMQV(); break;
1044 	case 121: result = ValidateHMQV(); break;
1045 	case 122: result = ValidateFHMQV(); break;
1046 
1047 #if defined(CRYPTOPP_EXTENDED_VALIDATION)
1048 	// http://github.com/weidai11/cryptopp/issues/92
1049 	case 9999: result = TestSecBlock(); break;
1050 	// http://github.com/weidai11/cryptopp/issues/64
1051 	case 9998: result = TestPolynomialMod2(); break;
1052 	// http://github.com/weidai11/cryptopp/issues/336
1053 	case 9997: result = TestIntegerBitops(); break;
1054 	// http://github.com/weidai11/cryptopp/issues/602
1055 	case 9996: result = TestIntegerOps(); break;
1056 	// http://github.com/weidai11/cryptopp/issues/360
1057 	case 9995: result = TestRounding(); break;
1058 	// http://github.com/weidai11/cryptopp/issues/242
1059 	case 9994: result = TestHuffmanCodes(); break;
1060 	// http://github.com/weidai11/cryptopp/issues/346
1061 	case 9993: result = TestASN1Parse(); break;
1062 	// http://github.com/weidai11/cryptopp/issues/242
1063 	case 9992: result = TestX25519(); break;
1064 	// http://github.com/weidai11/cryptopp/issues/346
1065 	case 9991: result = TestEd25519(); break;
1066 # if defined(CRYPTOPP_ALTIVEC_AVAILABLE)
1067 	case 9990: result = TestAltivecOps(); break;
1068 # endif
1069 #endif
1070 
1071 	default: return false;
1072 	}
1073 
1074 	g_testEnd = ::time(NULLPTR);
1075 
1076 	std::cout << "\nSeed used was " << s_globalSeed;
1077 	std::cout << "\nTest started at " << TimeToString(g_testBegin);
1078 	std::cout << "\nTest ended at " << TimeToString(g_testEnd) << std::endl;
1079 
1080 	return result;
1081 }
1082 
1083 NAMESPACE_END  // Test
1084 NAMESPACE_END  // CryptoPP
1085 
1086 // Microsoft puts a byte in global namespace. Combined with
1087 // a 'using namespace CryptoPP', it causes compile failures.
1088 // Also see http://github.com/weidai11/cryptopp/issues/442
1089 // and http://github.com/weidai11/cryptopp/issues/447.
main(int argc,char * argv[])1090 int CRYPTOPP_API main(int argc, char *argv[])
1091 {
1092 	return CryptoPP::Test::scoped_main(argc, argv);
1093 }
1094