1// test.cpp - written and placed in the public domain by Wei Dai
2
3#define _CRT_SECURE_NO_DEPRECATE
4#define CRYPTOPP_DEFAULT_NO_DLL
5#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1
6
7#include "dll.h"
8#include "md5.h"
9#include "ripemd.h"
10#include "rng.h"
11#include "gzip.h"
12#include "default.h"
13#include "randpool.h"
14#include "ida.h"
15#include "base64.h"
16#include "socketft.h"
17#include "wait.h"
18#include "factory.h"
19#include "whrlpool.h"
20#include "tiger.h"
21
22#include "validate.h"
23#include "bench.h"
24
25#include <iostream>
26#include <time.h>
27
28#ifdef CRYPTOPP_WIN32_AVAILABLE
29#include <windows.h>
30#endif
31
32#if defined(USE_BERKELEY_STYLE_SOCKETS) && !defined(macintosh)
33#include <netinet/in.h>
34#include <netinet/tcp.h>
35#endif
36
37#if (_MSC_VER >= 1000)
38#include <crtdbg.h>		// for the debug heap
39#endif
40
41#if defined(__MWERKS__) && defined(macintosh)
42#include <console.h>
43#endif
44
45#ifdef __BORLANDC__
46#pragma comment(lib, "cryptlib_bds.lib")
47#pragma comment(lib, "ws2_32.lib")
48#endif
49
50USING_NAMESPACE(CryptoPP)
51USING_NAMESPACE(std)
52
53const int MAX_PHRASE_LENGTH=250;
54
55void RegisterFactories();
56
57void GenerateRSAKey(unsigned int keyLength, const char *privFilename, const char *pubFilename, const char *seed);
58string RSAEncryptString(const char *pubFilename, const char *seed, const char *message);
59string RSADecryptString(const char *privFilename, const char *ciphertext);
60void RSASignFile(const char *privFilename, const char *messageFilename, const char *signatureFilename);
61bool RSAVerifyFile(const char *pubFilename, const char *messageFilename, const char *signatureFilename);
62
63void DigestFile(const char *file);
64void HmacFile(const char *hexKey, const char *file);
65
66void AES_CTR_Encrypt(const char *hexKey, const char *hexIV, const char *infile, const char *outfile);
67
68string EncryptString(const char *plaintext, const char *passPhrase);
69string DecryptString(const char *ciphertext, const char *passPhrase);
70
71void EncryptFile(const char *in, const char *out, const char *passPhrase);
72void DecryptFile(const char *in, const char *out, const char *passPhrase);
73
74void SecretShareFile(int threshold, int nShares, const char *filename, const char *seed);
75void SecretRecoverFile(int threshold, const char *outFilename, char *const *inFilenames);
76
77void InformationDisperseFile(int threshold, int nShares, const char *filename);
78void InformationRecoverFile(int threshold, const char *outFilename, char *const *inFilenames);
79
80void GzipFile(const char *in, const char *out, int deflate_level);
81void GunzipFile(const char *in, const char *out);
82
83void Base64Encode(const char *infile, const char *outfile);
84void Base64Decode(const char *infile, const char *outfile);
85void HexEncode(const char *infile, const char *outfile);
86void HexDecode(const char *infile, const char *outfile);
87
88void ForwardTcpPort(const char *sourcePort, const char *destinationHost, const char *destinationPort);
89
90void FIPS140_SampleApplication();
91void FIPS140_GenerateRandomFiles();
92
93bool Validate(int, bool, const char *);
94
95int (*AdhocTest)(int argc, char *argv[]) = NULL;
96
97static OFB_Mode<AES>::Encryption s_globalRNG;
98
99RandomNumberGenerator & GlobalRNG()
100{
101	return s_globalRNG;
102}
103
104int CRYPTOPP_API main(int argc, char *argv[])
105{
106#ifdef _CRTDBG_LEAK_CHECK_DF
107	// Turn on leak-checking
108	int tempflag = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG );
109	tempflag |= _CRTDBG_LEAK_CHECK_DF;
110	_CrtSetDbgFlag( tempflag );
111#endif
112
113#if defined(__MWERKS__) && defined(macintosh)
114	argc = ccommand(&argv);
115#endif
116
117	try
118	{
119		RegisterFactories();
120
121		std::string seed = IntToString(time(NULL));
122		seed.resize(16);
123		s_globalRNG.SetKeyWithIV((byte *)seed.data(), 16, (byte *)seed.data());
124
125		std::string command, executableName, macFilename;
126
127		if (argc < 2)
128			command = 'h';
129		else
130			command = argv[1];
131
132		if (command == "g")
133		{
134			char seed[1024], privFilename[128], pubFilename[128];
135			unsigned int keyLength;
136
137			cout << "Key length in bits: ";
138			cin >> keyLength;
139
140			cout << "\nSave private key to file: ";
141			cin >> privFilename;
142
143			cout << "\nSave public key to file: ";
144			cin >> pubFilename;
145
146			cout << "\nRandom Seed: ";
147			ws(cin);
148			cin.getline(seed, 1024);
149
150			GenerateRSAKey(keyLength, privFilename, pubFilename, seed);
151		}
152		else if (command == "rs")
153			RSASignFile(argv[2], argv[3], argv[4]);
154		else if (command == "rv")
155		{
156			bool verified = RSAVerifyFile(argv[2], argv[3], argv[4]);
157			cout << (verified ? "valid signature" : "invalid signature") << endl;
158		}
159		else if (command == "r")
160		{
161			char privFilename[128], pubFilename[128];
162			char seed[1024], message[1024];
163
164			cout << "Private key file: ";
165			cin >> privFilename;
166
167			cout << "\nPublic key file: ";
168			cin >> pubFilename;
169
170			cout << "\nRandom Seed: ";
171			ws(cin);
172			cin.getline(seed, 1024);
173
174			cout << "\nMessage: ";
175			cin.getline(message, 1024);
176
177			string ciphertext = RSAEncryptString(pubFilename, seed, message);
178			cout << "\nCiphertext: " << ciphertext << endl;
179
180			string decrypted = RSADecryptString(privFilename, ciphertext.c_str());
181			cout << "\nDecrypted: " << decrypted << endl;
182		}
183		else if (command == "mt")
184		{
185			MaurerRandomnessTest mt;
186			FileStore fs(argv[2]);
187			fs.TransferAllTo(mt);
188			cout << "Maurer Test Value: " << mt.GetTestValue() << endl;
189		}
190		else if (command == "mac_dll")
191		{
192			// sanity check on file size
193			std::fstream dllFile(argv[2], ios::in | ios::out | ios::binary);
194			std::ifstream::pos_type fileEnd = dllFile.seekg(0, std::ios_base::end).tellg();
195			if (fileEnd > 20*1000*1000)
196			{
197				cerr << "Input file too large (more than 20 MB).\n";
198				return 1;
199			}
200
201			// read file into memory
202			unsigned int fileSize = (unsigned int)fileEnd;
203			SecByteBlock buf(fileSize);
204			dllFile.seekg(0, std::ios_base::beg);
205			dllFile.read((char *)buf.begin(), fileSize);
206
207			// 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
208			word32 coffPos = *(word16 *)(buf+0x3c);
209			word32 optionalHeaderPos = coffPos + 24;
210			word16 optionalHeaderMagic = *(word16 *)(buf+optionalHeaderPos);
211			if (optionalHeaderMagic != 0x10b && optionalHeaderMagic != 0x20b)
212			{
213				cerr << "Target file is not a PE32 or PE32+ image.\n";
214				return 3;
215			}
216			word32 checksumPos = optionalHeaderPos + 64;
217			word32 certificateTableDirectoryPos = optionalHeaderPos + (optionalHeaderMagic == 0x10b ? 128 : 144);
218			word32 certificateTablePos = *(word32 *)(buf+certificateTableDirectoryPos);
219			word32 certificateTableSize = *(word32 *)(buf+certificateTableDirectoryPos+4);
220			if (certificateTableSize != 0)
221				cerr << "Warning: certificate table (IMAGE_DIRECTORY_ENTRY_SECURITY) of target image is not empty.\n";
222
223			// find where to place computed MAC
224			byte mac[] = CRYPTOPP_DUMMY_DLL_MAC;
225			byte *found = std::search(buf.begin(), buf.end(), mac+0, mac+sizeof(mac));
226			if (found == buf.end())
227			{
228				cerr << "MAC placeholder not found. Possibly the actual MAC was already placed.\n";
229				return 2;
230			}
231			word32 macPos = (unsigned int)(found-buf.begin());
232
233			// compute MAC
234			member_ptr<MessageAuthenticationCode> pMac(NewIntegrityCheckingMAC());
235			assert(pMac->DigestSize() == sizeof(mac));
236			MeterFilter f(new HashFilter(*pMac, new ArraySink(mac, sizeof(mac))));
237			f.AddRangeToSkip(0, checksumPos, 4);
238			f.AddRangeToSkip(0, certificateTableDirectoryPos, 8);
239			f.AddRangeToSkip(0, macPos, sizeof(mac));
240			f.AddRangeToSkip(0, certificateTablePos, certificateTableSize);
241			f.PutMessageEnd(buf.begin(), buf.size());
242
243			// place MAC
244			cout << "Placing MAC in file " << argv[2] << ", location " << macPos << ".\n";
245			dllFile.seekg(macPos, std::ios_base::beg);
246			dllFile.write((char *)mac, sizeof(mac));
247		}
248		else if (command == "m")
249			DigestFile(argv[2]);
250		else if (command == "tv")
251		{
252			std::string fname = argv[2];
253			if (fname.find(".txt") == std::string::npos)
254				fname = "TestVectors/" + fname + ".txt";
255			return !RunTestDataFile(fname.c_str());
256		}
257		else if (command == "t")
258		{
259			// VC60 workaround: use char array instead of std::string to workaround MSVC's getline bug
260			char passPhrase[MAX_PHRASE_LENGTH], plaintext[1024];
261
262			cout << "Passphrase: ";
263			cin.getline(passPhrase, MAX_PHRASE_LENGTH);
264
265			cout << "\nPlaintext: ";
266			cin.getline(plaintext, 1024);
267
268			string ciphertext = EncryptString(plaintext, passPhrase);
269			cout << "\nCiphertext: " << ciphertext << endl;
270
271			string decrypted = DecryptString(ciphertext.c_str(), passPhrase);
272			cout << "\nDecrypted: " << decrypted << endl;
273
274			return 0;
275		}
276		else if (command == "e64")
277			Base64Encode(argv[2], argv[3]);
278		else if (command == "d64")
279			Base64Decode(argv[2], argv[3]);
280		else if (command == "e16")
281			HexEncode(argv[2], argv[3]);
282		else if (command == "d16")
283			HexDecode(argv[2], argv[3]);
284		else if (command == "e" || command == "d")
285		{
286			char passPhrase[MAX_PHRASE_LENGTH];
287			cout << "Passphrase: ";
288			cin.getline(passPhrase, MAX_PHRASE_LENGTH);
289			if (command == "e")
290				EncryptFile(argv[2], argv[3], passPhrase);
291			else
292				DecryptFile(argv[2], argv[3], passPhrase);
293		}
294		else if (command == "ss")
295		{
296			char seed[1024];
297			cout << "\nRandom Seed: ";
298			ws(cin);
299			cin.getline(seed, 1024);
300			SecretShareFile(atoi(argv[2]), atoi(argv[3]), argv[4], seed);
301		}
302		else if (command == "sr")
303			SecretRecoverFile(argc-3, argv[2], argv+3);
304		else if (command == "id")
305			InformationDisperseFile(atoi(argv[2]), atoi(argv[3]), argv[4]);
306		else if (command == "ir")
307			InformationRecoverFile(argc-3, argv[2], argv+3);
308		else if (command == "v" || command == "vv")
309			return !Validate(argc>2 ? atoi(argv[2]) : 0, argv[1][1] == 'v', argc>3 ? argv[3] : NULL);
310		else if (command == "b")
311			BenchmarkAll(argc<3 ? 1 : atof(argv[2]), argc<4 ? 0 : atof(argv[3])*1e9);
312		else if (command == "b2")
313			BenchmarkAll2(argc<3 ? 1 : atof(argv[2]), argc<4 ? 0 : atof(argv[3])*1e9);
314		else if (command == "z")
315			GzipFile(argv[3], argv[4], argv[2][0]-'0');
316		else if (command == "u")
317			GunzipFile(argv[2], argv[3]);
318		else if (command == "fips")
319			FIPS140_SampleApplication();
320		else if (command == "fips-rand")
321			FIPS140_GenerateRandomFiles();
322		else if (command == "ft")
323			ForwardTcpPort(argv[2], argv[3], argv[4]);
324		else if (command == "a")
325		{
326			if (AdhocTest)
327				return (*AdhocTest)(argc, argv);
328			else
329			{
330				cerr << "AdhocTest not defined.\n";
331				return 1;
332			}
333		}
334		else if (command == "hmac")
335			HmacFile(argv[2], argv[3]);
336		else if (command == "ae")
337			AES_CTR_Encrypt(argv[2], argv[3], argv[4], argv[5]);
338		else if (command == "h")
339		{
340			FileSource usage("TestData/usage.dat", true, new FileSink(cout));
341			return 1;
342		}
343		else if (command == "V")
344		{
345			cout << CRYPTOPP_VERSION / 100 << '.' << (CRYPTOPP_VERSION % 100) / 10 << '.' << CRYPTOPP_VERSION % 10 << endl;
346		}
347		else
348		{
349			cerr << "Unrecognized command. Run \"cryptest h\" to obtain usage information.\n";
350			return 1;
351		}
352		return 0;
353	}
354	catch(CryptoPP::Exception &e)
355	{
356		cout << "\nCryptoPP::Exception caught: " << e.what() << endl;
357		return -1;
358	}
359	catch(std::exception &e)
360	{
361		cout << "\nstd::exception caught: " << e.what() << endl;
362		return -2;
363	}
364}
365
366void FIPS140_GenerateRandomFiles()
367{
368#ifdef OS_RNG_AVAILABLE
369	DefaultAutoSeededRNG rng;
370	RandomNumberStore store(rng, ULONG_MAX);
371
372	for (unsigned int i=0; i<100000; i++)
373		store.TransferTo(FileSink((IntToString(i) + ".rnd").c_str()).Ref(), 20000);
374#else
375	cout << "OS provided RNG not available.\n";
376	exit(-1);
377#endif
378}
379
380SecByteBlock HexDecodeString(const char *hex)
381{
382	StringSource ss(hex, true, new HexDecoder);
383	SecByteBlock result((size_t)ss.MaxRetrievable());
384	ss.Get(result, result.size());
385	return result;
386}
387
388void GenerateRSAKey(unsigned int keyLength, const char *privFilename, const char *pubFilename, const char *seed)
389{
390	RandomPool randPool;
391	randPool.IncorporateEntropy((byte *)seed, strlen(seed));
392
393	RSAES_OAEP_SHA_Decryptor priv(randPool, keyLength);
394	HexEncoder privFile(new FileSink(privFilename));
395	priv.DEREncode(privFile);
396	privFile.MessageEnd();
397
398	RSAES_OAEP_SHA_Encryptor pub(priv);
399	HexEncoder pubFile(new FileSink(pubFilename));
400	pub.DEREncode(pubFile);
401	pubFile.MessageEnd();
402}
403
404string RSAEncryptString(const char *pubFilename, const char *seed, const char *message)
405{
406	FileSource pubFile(pubFilename, true, new HexDecoder);
407	RSAES_OAEP_SHA_Encryptor pub(pubFile);
408
409	RandomPool randPool;
410	randPool.IncorporateEntropy((byte *)seed, strlen(seed));
411
412	string result;
413	StringSource(message, true, new PK_EncryptorFilter(randPool, pub, new HexEncoder(new StringSink(result))));
414	return result;
415}
416
417string RSADecryptString(const char *privFilename, const char *ciphertext)
418{
419	FileSource privFile(privFilename, true, new HexDecoder);
420	RSAES_OAEP_SHA_Decryptor priv(privFile);
421
422	string result;
423	StringSource(ciphertext, true, new HexDecoder(new PK_DecryptorFilter(GlobalRNG(), priv, new StringSink(result))));
424	return result;
425}
426
427void RSASignFile(const char *privFilename, const char *messageFilename, const char *signatureFilename)
428{
429	FileSource privFile(privFilename, true, new HexDecoder);
430	RSASS<PKCS1v15, SHA>::Signer priv(privFile);
431	FileSource f(messageFilename, true, new SignerFilter(GlobalRNG(), priv, new HexEncoder(new FileSink(signatureFilename))));
432}
433
434bool RSAVerifyFile(const char *pubFilename, const char *messageFilename, const char *signatureFilename)
435{
436	FileSource pubFile(pubFilename, true, new HexDecoder);
437	RSASS<PKCS1v15, SHA>::Verifier pub(pubFile);
438
439	FileSource signatureFile(signatureFilename, true, new HexDecoder);
440	if (signatureFile.MaxRetrievable() != pub.SignatureLength())
441		return false;
442	SecByteBlock signature(pub.SignatureLength());
443	signatureFile.Get(signature, signature.size());
444
445	VerifierFilter *verifierFilter = new VerifierFilter(pub);
446	verifierFilter->Put(signature, pub.SignatureLength());
447	FileSource f(messageFilename, true, verifierFilter);
448
449	return verifierFilter->GetLastResult();
450}
451
452void DigestFile(const char *filename)
453{
454	SHA1 sha;
455	RIPEMD160 ripemd;
456	SHA256 sha256;
457	Tiger tiger;
458	SHA512 sha512;
459	Whirlpool whirlpool;
460	vector_member_ptrs<HashFilter> filters(6);
461	filters[0].reset(new HashFilter(sha));
462	filters[1].reset(new HashFilter(ripemd));
463	filters[2].reset(new HashFilter(tiger));
464	filters[3].reset(new HashFilter(sha256));
465	filters[4].reset(new HashFilter(sha512));
466	filters[5].reset(new HashFilter(whirlpool));
467
468	auto_ptr<ChannelSwitch> channelSwitch(new ChannelSwitch);
469	size_t i;
470	for (i=0; i<filters.size(); i++)
471		channelSwitch->AddDefaultRoute(*filters[i]);
472	FileSource(filename, true, channelSwitch.release());
473
474	HexEncoder encoder(new FileSink(cout), false);
475	for (i=0; i<filters.size(); i++)
476	{
477		cout << filters[i]->AlgorithmName() << ": ";
478		filters[i]->TransferTo(encoder);
479		cout << "\n";
480	}
481}
482
483void HmacFile(const char *hexKey, const char *file)
484{
485	member_ptr<MessageAuthenticationCode> mac;
486	if (strcmp(hexKey, "selftest") == 0)
487	{
488		cerr << "Computing HMAC/SHA1 value for self test.\n";
489		mac.reset(NewIntegrityCheckingMAC());
490	}
491	else
492	{
493		std::string decodedKey;
494		StringSource(hexKey, true, new HexDecoder(new StringSink(decodedKey)));
495		mac.reset(new HMAC<SHA1>((const byte *)decodedKey.data(), decodedKey.size()));
496	}
497	FileSource(file, true, new HashFilter(*mac, new HexEncoder(new FileSink(cout))));
498}
499
500void AES_CTR_Encrypt(const char *hexKey, const char *hexIV, const char *infile, const char *outfile)
501{
502	SecByteBlock key = HexDecodeString(hexKey);
503	SecByteBlock iv = HexDecodeString(hexIV);
504	CTR_Mode<AES>::Encryption aes(key, key.size(), iv);
505	FileSource(infile, true, new StreamTransformationFilter(aes, new FileSink(outfile)));
506}
507
508string EncryptString(const char *instr, const char *passPhrase)
509{
510	string outstr;
511
512	DefaultEncryptorWithMAC encryptor(passPhrase, new HexEncoder(new StringSink(outstr)));
513	encryptor.Put((byte *)instr, strlen(instr));
514	encryptor.MessageEnd();
515
516	return outstr;
517}
518
519string DecryptString(const char *instr, const char *passPhrase)
520{
521	string outstr;
522
523	HexDecoder decryptor(new DefaultDecryptorWithMAC(passPhrase, new StringSink(outstr)));
524	decryptor.Put((byte *)instr, strlen(instr));
525	decryptor.MessageEnd();
526
527	return outstr;
528}
529
530void EncryptFile(const char *in, const char *out, const char *passPhrase)
531{
532	FileSource f(in, true, new DefaultEncryptorWithMAC(passPhrase, new FileSink(out)));
533}
534
535void DecryptFile(const char *in, const char *out, const char *passPhrase)
536{
537	FileSource f(in, true, new DefaultDecryptorWithMAC(passPhrase, new FileSink(out)));
538}
539
540void SecretShareFile(int threshold, int nShares, const char *filename, const char *seed)
541{
542	assert(nShares<=1000);
543
544	RandomPool rng;
545	rng.IncorporateEntropy((byte *)seed, strlen(seed));
546
547	ChannelSwitch *channelSwitch;
548	FileSource source(filename, false, new SecretSharing(rng, threshold, nShares, channelSwitch = new ChannelSwitch));
549
550	vector_member_ptrs<FileSink> fileSinks(nShares);
551	string channel;
552	for (int i=0; i<nShares; i++)
553	{
554		char extension[5] = ".000";
555		extension[1]='0'+byte(i/100);
556		extension[2]='0'+byte((i/10)%10);
557		extension[3]='0'+byte(i%10);
558		fileSinks[i].reset(new FileSink((string(filename)+extension).c_str()));
559
560		channel = WordToString<word32>(i);
561		fileSinks[i]->Put((byte *)channel.data(), 4);
562		channelSwitch->AddRoute(channel, *fileSinks[i], DEFAULT_CHANNEL);
563	}
564
565	source.PumpAll();
566}
567
568void SecretRecoverFile(int threshold, const char *outFilename, char *const *inFilenames)
569{
570	assert(threshold<=1000);
571
572	SecretRecovery recovery(threshold, new FileSink(outFilename));
573
574	vector_member_ptrs<FileSource> fileSources(threshold);
575	SecByteBlock channel(4);
576	int i;
577	for (i=0; i<threshold; i++)
578	{
579		fileSources[i].reset(new FileSource(inFilenames[i], false));
580		fileSources[i]->Pump(4);
581		fileSources[i]->Get(channel, 4);
582		fileSources[i]->Attach(new ChannelSwitch(recovery, string((char *)channel.begin(), 4)));
583	}
584
585	while (fileSources[0]->Pump(256))
586		for (i=1; i<threshold; i++)
587			fileSources[i]->Pump(256);
588
589	for (i=0; i<threshold; i++)
590		fileSources[i]->PumpAll();
591}
592
593void InformationDisperseFile(int threshold, int nShares, const char *filename)
594{
595	assert(nShares<=1000);
596
597	ChannelSwitch *channelSwitch;
598	FileSource source(filename, false, new InformationDispersal(threshold, nShares, channelSwitch = new ChannelSwitch));
599
600	vector_member_ptrs<FileSink> fileSinks(nShares);
601	string channel;
602	for (int i=0; i<nShares; i++)
603	{
604		char extension[5] = ".000";
605		extension[1]='0'+byte(i/100);
606		extension[2]='0'+byte((i/10)%10);
607		extension[3]='0'+byte(i%10);
608		fileSinks[i].reset(new FileSink((string(filename)+extension).c_str()));
609
610		channel = WordToString<word32>(i);
611		fileSinks[i]->Put((byte *)channel.data(), 4);
612		channelSwitch->AddRoute(channel, *fileSinks[i], DEFAULT_CHANNEL);
613	}
614
615	source.PumpAll();
616}
617
618void InformationRecoverFile(int threshold, const char *outFilename, char *const *inFilenames)
619{
620	assert(threshold<=1000);
621
622	InformationRecovery recovery(threshold, new FileSink(outFilename));
623
624	vector_member_ptrs<FileSource> fileSources(threshold);
625	SecByteBlock channel(4);
626	int i;
627	for (i=0; i<threshold; i++)
628	{
629		fileSources[i].reset(new FileSource(inFilenames[i], false));
630		fileSources[i]->Pump(4);
631		fileSources[i]->Get(channel, 4);
632		fileSources[i]->Attach(new ChannelSwitch(recovery, string((char *)channel.begin(), 4)));
633	}
634
635	while (fileSources[0]->Pump(256))
636		for (i=1; i<threshold; i++)
637			fileSources[i]->Pump(256);
638
639	for (i=0; i<threshold; i++)
640		fileSources[i]->PumpAll();
641}
642
643void GzipFile(const char *in, const char *out, int deflate_level)
644{
645//	FileSource(in, true, new Gzip(new FileSink(out), deflate_level));
646
647	// use a filter graph to compare decompressed data with original
648	//
649	// Source ----> Gzip ------> Sink
650	//    \           |
651	//	    \       Gunzip
652	//		  \       |
653	//		    \     v
654	//		      > ComparisonFilter
655
656	EqualityComparisonFilter comparison;
657
658	Gunzip gunzip(new ChannelSwitch(comparison, "0"));
659	gunzip.SetAutoSignalPropagation(0);
660
661	FileSink sink(out);
662
663	ChannelSwitch *cs;
664	Gzip gzip(cs = new ChannelSwitch(sink), deflate_level);
665	cs->AddDefaultRoute(gunzip);
666
667	cs = new ChannelSwitch(gzip);
668	cs->AddDefaultRoute(comparison, "1");
669	FileSource source(in, true, cs);
670
671	comparison.ChannelMessageSeriesEnd("0");
672	comparison.ChannelMessageSeriesEnd("1");
673}
674
675void GunzipFile(const char *in, const char *out)
676{
677	FileSource(in, true, new Gunzip(new FileSink(out)));
678}
679
680void Base64Encode(const char *in, const char *out)
681{
682	FileSource(in, true, new Base64Encoder(new FileSink(out)));
683}
684
685void Base64Decode(const char *in, const char *out)
686{
687	FileSource(in, true, new Base64Decoder(new FileSink(out)));
688}
689
690void HexEncode(const char *in, const char *out)
691{
692	FileSource(in, true, new HexEncoder(new FileSink(out)));
693}
694
695void HexDecode(const char *in, const char *out)
696{
697	FileSource(in, true, new HexDecoder(new FileSink(out)));
698}
699
700void ForwardTcpPort(const char *sourcePortName, const char *destinationHost, const char *destinationPortName)
701{
702#ifdef SOCKETS_AVAILABLE
703	SocketsInitializer sockInit;
704
705	Socket sockListen, sockSource, sockDestination;
706
707	int sourcePort = Socket::PortNameToNumber(sourcePortName);
708	int destinationPort = Socket::PortNameToNumber(destinationPortName);
709
710	sockListen.Create();
711	sockListen.Bind(sourcePort);
712	setsockopt(sockListen, IPPROTO_TCP, TCP_NODELAY, "\x01", 1);
713
714	cout << "Listing on port " << sourcePort << ".\n";
715	sockListen.Listen();
716
717	sockListen.Accept(sockSource);
718	cout << "Connection accepted on port " << sourcePort << ".\n";
719	sockListen.CloseSocket();
720
721	cout << "Making connection to " << destinationHost << ", port " << destinationPort << ".\n";
722	sockDestination.Create();
723	sockDestination.Connect(destinationHost, destinationPort);
724
725	cout << "Connection made to " << destinationHost << ", starting to forward.\n";
726
727	SocketSource out(sockSource, false, new SocketSink(sockDestination));
728	SocketSource in(sockDestination, false, new SocketSink(sockSource));
729
730	WaitObjectContainer waitObjects;
731
732	while (!(in.SourceExhausted() && out.SourceExhausted()))
733	{
734		waitObjects.Clear();
735
736		out.GetWaitObjects(waitObjects, CallStack("ForwardTcpPort - out", NULL));
737		in.GetWaitObjects(waitObjects, CallStack("ForwardTcpPort - in", NULL));
738
739		waitObjects.Wait(INFINITE_TIME);
740
741		if (!out.SourceExhausted())
742		{
743			cout << "o" << flush;
744			out.PumpAll2(false);
745			if (out.SourceExhausted())
746				cout << "EOF received on source socket.\n";
747		}
748
749		if (!in.SourceExhausted())
750		{
751			cout << "i" << flush;
752			in.PumpAll2(false);
753			if (in.SourceExhausted())
754				cout << "EOF received on destination socket.\n";
755		}
756	}
757#else
758	cout << "Socket support was not enabled at compile time.\n";
759	exit(-1);
760#endif
761}
762
763bool Validate(int alg, bool thorough, const char *seedInput)
764{
765	bool result;
766
767	std::string seed = seedInput ? std::string(seedInput) : IntToString(time(NULL));
768	seed.resize(16);
769
770	cout << "Using seed: " << seed << endl << endl;
771	s_globalRNG.SetKeyWithIV((byte *)seed.data(), 16, (byte *)seed.data());
772
773	switch (alg)
774	{
775	case 0: result = ValidateAll(thorough); break;
776	case 1: result = TestSettings(); break;
777	case 2: result = TestOS_RNG(); break;
778	case 3: result = ValidateMD5(); break;
779	case 4: result = ValidateSHA(); break;
780	case 5: result = ValidateDES(); break;
781	case 6: result = ValidateIDEA(); break;
782	case 7: result = ValidateARC4(); break;
783	case 8: result = ValidateRC5(); break;
784	case 9: result = ValidateBlowfish(); break;
785//	case 10: result = ValidateDiamond2(); break;
786	case 11: result = ValidateThreeWay(); break;
787	case 12: result = ValidateBBS(); break;
788	case 13: result = ValidateDH(); break;
789	case 14: result = ValidateRSA(); break;
790	case 15: result = ValidateElGamal(); break;
791	case 16: result = ValidateDSA(thorough); break;
792//	case 17: result = ValidateHAVAL(); break;
793	case 18: result = ValidateSAFER(); break;
794	case 19: result = ValidateLUC(); break;
795	case 20: result = ValidateRabin(); break;
796//	case 21: result = ValidateBlumGoldwasser(); break;
797	case 22: result = ValidateECP(); break;
798	case 23: result = ValidateEC2N(); break;
799//	case 24: result = ValidateMD5MAC(); break;
800	case 25: result = ValidateGOST(); break;
801	case 26: result = ValidateTiger(); break;
802	case 27: result = ValidateRIPEMD(); break;
803	case 28: result = ValidateHMAC(); break;
804//	case 29: result = ValidateXMACC(); break;
805	case 30: result = ValidateSHARK(); break;
806	case 32: result = ValidateLUC_DH(); break;
807	case 33: result = ValidateLUC_DL(); break;
808	case 34: result = ValidateSEAL(); break;
809	case 35: result = ValidateCAST(); break;
810	case 36: result = ValidateSquare(); break;
811	case 37: result = ValidateRC2(); break;
812	case 38: result = ValidateRC6(); break;
813	case 39: result = ValidateMARS(); break;
814	case 40: result = ValidateRW(); break;
815	case 41: result = ValidateMD2(); break;
816	case 42: result = ValidateNR(); break;
817	case 43: result = ValidateMQV(); break;
818	case 44: result = ValidateRijndael(); break;
819	case 45: result = ValidateTwofish(); break;
820	case 46: result = ValidateSerpent(); break;
821	case 47: result = ValidateCipherModes(); break;
822	case 48: result = ValidateCRC32(); break;
823	case 49: result = ValidateECDSA(); break;
824	case 50: result = ValidateXTR_DH(); break;
825	case 51: result = ValidateSKIPJACK(); break;
826	case 52: result = ValidateSHA2(); break;
827	case 53: result = ValidatePanama(); break;
828	case 54: result = ValidateAdler32(); break;
829	case 55: result = ValidateMD4(); break;
830	case 56: result = ValidatePBKDF(); break;
831	case 57: result = ValidateESIGN(); break;
832	case 58: result = ValidateDLIES(); break;
833	case 59: result = ValidateBaseCode(); break;
834	case 60: result = ValidateSHACAL2(); break;
835	case 61: result = ValidateCamellia(); break;
836	case 62: result = ValidateWhirlpool(); break;
837	case 63: result = ValidateTTMAC(); break;
838	case 64: result = ValidateSalsa(); break;
839	case 65: result = ValidateSosemanuk(); break;
840	case 66: result = ValidateVMAC(); break;
841	case 67: result = ValidateCCM(); break;
842	case 68: result = ValidateGCM(); break;
843	case 69: result = ValidateCMAC(); break;
844	default: return false;
845	}
846
847	time_t endTime = time(NULL);
848	cout << "\nTest ended at " << asctime(localtime(&endTime));
849	cout << "Seed used was: " << seed << endl;
850
851	return result;
852}
853