1/*
2 * symCompat.c - test compatibilty of two different implementations of a
3 * given symmetric encryption algorithm - one in the standard AppleCSP,
4 * the other in either libcrypto (for Blowfish and CAST), BSAFE, or the
5 * NIST reference port for AES.
6 *
7 * Written by Doug Mitchell.
8 */
9
10#include <stdlib.h>
11#include <stdio.h>
12#include <time.h>
13#include <Security/cssm.h>
14#include <Security/cssmapple.h>
15#include "cspwrap.h"
16#include "common.h"
17#include "bsafeUtils.h"
18#include "ssleayUtils.h"
19#include "rijndaelApi.h"
20#include <string.h>
21#include "cspdlTesting.h"
22
23/*
24 * Defaults.
25 */
26#define LOOPS_DEF		200
27
28#define MIN_DATA_SIZE	8
29#define MAX_DATA_SIZE	10000							/* bytes */
30#define MAX_KEY_SIZE	MAX_KEY_SIZE_RC245_BYTES		/* bytes */
31#define LOOP_NOTIFY		20
32
33#define RAW_MODE			CSSM_ALGMODE_ECB		/* doesn't work for BSAFE */
34#define RAW_MODE_BSAFE		CSSM_ALGMODE_CBC_IV8
35
36#define COOKED_MODE			CSSM_ALGMODE_CBCPadIV8
37#define RAW_MODE_STREAM		CSSM_ALGMODE_NONE
38
39#define RAW_MODE_STR		"ECB"
40#define RAW_MODE_BSAFE_STR	"CBC/noPad"
41#define COOKED_MODE_STR		"CBC/Pad"
42#define RAW_MODE_STREAM_STR	"None"
43
44/*
45 * Enumerate algs our own way to allow iteration.
46 */
47typedef enum {
48	// ALG_ASC = 1,			// not tested - no reference available
49	ALG_DES = 1,
50	ALG_RC2,
51	ALG_RC4,
52	ALG_RC5,
53	ALG_3DES,
54	ALG_AES,
55	ALG_AES192,		/* 192 bit block */
56	ALG_AES256,		/* 256 bit block */
57	ALG_BFISH,
58	ALG_CAST
59} SymAlg;
60#define ALG_FIRST			ALG_DES
61#define ALG_LAST			ALG_CAST
62
63static void usage(char **argv)
64{
65	printf("usage: %s [options]\n", argv[0]);
66	printf("   Options:\n");
67	printf("   a=algorithm (d=DES; 3=3DES3; 2=RC2; 4=RC4; 5=RC5; a=AES; A=AES192; \n");
68	printf("                6=AES256; b=Blowfish; c=CAST; default=all)\n");
69	printf("   l=loops (default=%d; 0=forever)\n", LOOPS_DEF);
70	printf("   k=keySizeInBits\n");
71	printf("   e(ncrypt only)\n");
72	printf("   m=maxPtextSize (default=%d)\n", MAX_DATA_SIZE);
73	printf("   n=minPtextSize (default=%d)\n", MIN_DATA_SIZE);
74	printf("   p=pauseInterval (default=0, no pause)\n");
75	printf("   s (all ops single-shot, not staged)\n");
76	printf("   o (raw - no padding or CBC if possible)\n");
77	printf("   O (cooked - padding and CBC if possible)\n");
78	printf("   z (keys and plaintext all zeroes)\n");
79	printf("   D (CSP/DL; default = bare CSP)\n");
80	printf("   y (use ssleay EVP; AES128 only)\n");
81	printf("   v(erbose)\n");
82	printf("   q(uiet)\n");
83	printf("   h(elp)\n");
84	exit(1);
85}
86
87/*
88 * encrypt/decrypt using reference BSAFE.
89 */
90static CSSM_RETURN encryptDecryptBSAFE(
91	CSSM_BOOL			forEncrypt,
92	CSSM_ALGORITHMS		encrAlg,
93	CSSM_ENCRYPT_MODE	encrMode,
94	const CSSM_DATA		*iv,				//�optional per mode
95	uint32				keySizeInBits,
96	uint32				effectiveKeyBits,	// optional per key alg
97	uint32				rounds,				// ditto
98	const CSSM_DATA		*key,				// raw key bytes
99	const CSSM_DATA		*inText,
100	CSSM_DATA_PTR 		outText)			// mallocd and returned
101{
102	CSSM_RETURN crtn;
103	BU_KEY buKey;
104
105	crtn = buGenSymKey(keySizeInBits, key, &buKey);
106	if(crtn) {
107		return crtn;
108	}
109	crtn = buEncryptDecrypt(buKey,
110		forEncrypt,					// forEncrypt
111		encrAlg,
112		encrMode,
113		iv,
114		effectiveKeyBits,
115		rounds,
116		inText,
117		outText);
118	buFreeKey(buKey);
119	return crtn;
120}
121
122/*
123 * encrypt/decrypt using reference ssleay.
124 */
125static CSSM_RETURN encryptDecryptEAY(
126	CSSM_BOOL			forEncrypt,
127	CSSM_ALGORITHMS		encrAlg,
128	CSSM_ENCRYPT_MODE	encrMode,
129	const CSSM_DATA		*iv,				//�optional per mode
130	uint32				keySizeInBits,
131	const CSSM_DATA		*key,				// raw key bytes, Length ignored
132	const CSSM_DATA		*inText,
133	CSSM_DATA_PTR 		outText)			// mallocd and returned
134{
135	CSSM_RETURN crtn;
136	EAY_KEY eayKey;
137	CSSM_DATA ckey = *key;
138	ckey.Length = keySizeInBits / 8;
139
140	crtn = eayGenSymKey(encrAlg, forEncrypt, &ckey, &eayKey);
141	if(crtn) {
142		return crtn;
143	}
144	crtn = eayEncryptDecrypt(eayKey,
145		forEncrypt,
146		encrAlg,
147		encrMode,
148		iv,
149		inText,
150		outText);
151	eayFreeKey(eayKey);
152	return crtn;
153}
154
155/*
156 * encrypt/decrypt using reference AES.
157 */
158static CSSM_RETURN encryptDecryptAES(
159	CSSM_BOOL			forEncrypt,
160	CSSM_ALGORITHMS		encrAlg,
161	CSSM_ENCRYPT_MODE	encrMode,
162	const CSSM_DATA		*iv,				//�optional per mode
163	uint32				keySizeInBits,
164	uint32				effectiveKeyBits,	// optional per key alg
165	uint32				cipherBlockSize,
166	uint32				rounds,				// ditto
167	const CSSM_DATA		*key,				// raw key bytes
168	const CSSM_DATA		*inText,
169	CSSM_DATA_PTR 		outText)			// mallocd and returned
170{
171	keyInstance 	aesKey;
172	cipherInstance 	aesCipher;
173	BYTE 			mode;
174	int 			artn;
175	BYTE			*ivPtr;
176
177	if(cipherBlockSize == 0) {
178		cipherBlockSize = MIN_AES_BLOCK_BITS;
179	}
180	switch(encrMode) {
181		case CSSM_ALGMODE_CBC_IV8:
182			mode = MODE_CBC;
183			ivPtr = iv->Data;
184			break;
185		case CSSM_ALGMODE_ECB:
186			mode = MODE_ECB;
187			ivPtr = NULL;
188			break;
189		default:
190			printf("***AES reference implementation doesn't do padding (yet)\n");
191			return CSSM_OK;
192	}
193	/* fixme - adjust for padding if necessary */
194	outText->Data = (uint8 *)CSSM_MALLOC(inText->Length);
195	outText->Length = inText->Length;
196	artn = _makeKey(&aesKey,
197		forEncrypt ? DIR_ENCRYPT : DIR_DECRYPT,
198		keySizeInBits,
199		cipherBlockSize,
200		key->Data);
201	if(artn <= 0) {
202		printf("***AES makeKey returned %d\n", artn);
203		return CSSM_ERRCODE_INTERNAL_ERROR;
204	}
205	artn = _cipherInit(&aesCipher,
206		mode,
207		cipherBlockSize,
208		ivPtr);
209	if(artn <= 0) {
210		printf("***AES cipherInit returned %d\n", artn);
211		return CSSM_ERRCODE_INTERNAL_ERROR;
212	}
213	if(forEncrypt) {
214		artn = _blockEncrypt(&aesCipher,
215			&aesKey,
216			(BYTE *)inText->Data,
217			inText->Length * 8,
218			(BYTE *)outText->Data);
219	}
220	else {
221		artn = _blockDecrypt(&aesCipher,
222			&aesKey,
223			(BYTE *)inText->Data,
224			inText->Length * 8,
225			(BYTE *)outText->Data);
226	}
227	if(artn <= 0) {
228		printf("***AES encrypt/decrypt returned %d\n", artn);
229		return CSSM_ERRCODE_INTERNAL_ERROR;
230	}
231	return CSSM_OK;
232}
233
234/*
235 * Encrypt/decrypt, one-shot, using one of the various reference implementations.
236 */
237static CSSM_RETURN encryptDecryptRef(
238	CSSM_BOOL			forEncrypt,
239	CSSM_ALGORITHMS		encrAlg,
240	CSSM_ENCRYPT_MODE	encrMode,
241	const CSSM_DATA		*iv,				// optional per mode
242	uint32				keySizeInBits,
243	uint32				effectiveKeyBits,	// optional per key alg
244	uint32				cipherBlockSize,
245	uint32				rounds,				// ditto
246	CSSM_BOOL			useEvp,				// AES only
247	const CSSM_DATA		*key,				// raw key bytes
248	const CSSM_DATA		*inText,
249	CSSM_DATA_PTR 		outText)			// mallocd and returned
250{
251	switch(encrAlg) {
252		case CSSM_ALGID_AES:
253			if(useEvp && (cipherBlockSize == 128)) {
254				return (CSSM_RETURN)evpEncryptDecrypt(encrAlg, forEncrypt,
255					key, keySizeInBits, encrMode, iv, inText, outText);
256			}
257			else {
258				return encryptDecryptAES(
259					forEncrypt,
260					encrAlg,
261					encrMode,
262					iv,
263					keySizeInBits,
264					effectiveKeyBits,
265					cipherBlockSize,
266					rounds,
267					key,
268					inText,
269					outText);
270			}
271		case CSSM_ALGID_BLOWFISH:
272		case CSSM_ALGID_CAST:
273			return encryptDecryptEAY(
274				forEncrypt,
275				encrAlg,
276				encrMode,
277				iv,
278				keySizeInBits,
279				key,
280				inText,
281				outText);
282		default:
283			if(useEvp && (encrAlg == CSSM_ALGID_DES)) {
284				return (CSSM_RETURN)evpEncryptDecrypt(encrAlg, forEncrypt,
285					key, keySizeInBits, encrMode, iv, inText, outText);
286			}
287			else {
288				return encryptDecryptBSAFE(
289					forEncrypt,
290					encrAlg,
291					encrMode,
292					iv,
293					keySizeInBits,
294					effectiveKeyBits,
295					rounds,
296					key,
297					inText,
298					outText);
299			}
300	}
301}
302
303/*
304 * encrypt/decrypt using CSSM.
305 */
306static CSSM_RETURN encryptDecryptCSSM(
307	CSSM_CSP_HANDLE 	cspHand,
308	CSSM_BOOL			forEncrypt,
309	CSSM_ALGORITHMS		keyAlg,
310	CSSM_ALGORITHMS		encrAlg,
311	CSSM_ENCRYPT_MODE	encrMode,
312	CSSM_PADDING 		padding,			// CSSM_PADDING_PKCS1, etc.
313
314	CSSM_BOOL 			multiUpdates,		// false:single update, true:multi updates
315	const CSSM_DATA		*iv,				//�optional per mode
316	uint32				keySizeInBits,
317	uint32				effectiveKeyBits,	// optional per key alg
318	uint32				cipherBlockSize,
319	uint32				rounds,				// ditto
320	const CSSM_DATA		*key,				// raw key bytes
321	const CSSM_DATA		*inText,
322	CSSM_BOOL			genRaw,				// first generate raw key (CSPDL)
323	CSSM_DATA_PTR 		outText)			// mallocd and returned
324{
325	CSSM_KEY_PTR		symKey;				// mallocd by cspGenSymKey or a ptr
326											// to refKey
327	CSSM_KEY			refKey;				// in case of genRaw
328	CSSM_BOOL			refKeyGenerated = CSSM_FALSE;
329	unsigned			keyBytes = (keySizeInBits + 7) / 8;
330	CSSM_RETURN			crtn;
331
332	if(genRaw) {
333		crtn = cspGenSymKeyWithBits(cspHand,
334			keyAlg,
335			CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT,
336			key,
337			keyBytes,
338			&refKey);
339		if(crtn) {
340			return crtn;
341		}
342		symKey = &refKey;
343		refKeyGenerated = CSSM_TRUE;
344	}
345	else {
346		/* cook up a raw symmetric key */
347		symKey = cspGenSymKey(cspHand,
348			keyAlg,
349			"noLabel",
350			8,
351			CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT,
352			keySizeInBits,
353			CSSM_FALSE);			// ref key
354		if(symKey == NULL) {
355			return CSSM_ERRCODE_INTERNAL_ERROR;
356		}
357		if(symKey->KeyData.Length != keyBytes) {
358			printf("***Generated key size error (exp %d, got %lu)\n",
359				keyBytes, symKey->KeyData.Length);
360			return CSSM_ERRCODE_INTERNAL_ERROR;
361		}
362		memmove(symKey->KeyData.Data, key->Data, keyBytes);
363	}
364	outText->Data = NULL;
365	outText->Length = 0;
366
367	if(keySizeInBits == effectiveKeyBits) {
368		effectiveKeyBits = 0;
369	}
370
371	/* go for it */
372	if(forEncrypt) {
373		crtn = cspStagedEncrypt(cspHand,
374			encrAlg,
375			encrMode,
376			padding,
377			symKey,
378			NULL,			// no second key
379			effectiveKeyBits,
380			cipherBlockSize / 8,
381			rounds,
382			iv,
383			inText,
384			outText,
385			multiUpdates);
386	}
387	else {
388		crtn = cspStagedDecrypt(cspHand,
389			encrAlg,
390			encrMode,
391			padding,
392			symKey,
393			NULL,			// no second key
394			effectiveKeyBits,
395			cipherBlockSize / 8,
396			rounds,
397			iv,
398			inText,
399			outText,
400			multiUpdates);
401	}
402	cspFreeKey(cspHand, symKey);
403	if(!refKeyGenerated) {
404		/* key itself mallocd by cspGenSymKey */
405		CSSM_FREE(symKey);
406	}
407	return crtn;
408}
409
410#define LOG_FREQ	20
411
412static int doTest(CSSM_CSP_HANDLE cspHand,
413	const CSSM_DATA		*ptext,
414	const CSSM_DATA		*keyData,
415	const CSSM_DATA		*iv,
416	uint32 				keyAlg,						// CSSM_ALGID_xxx of the key
417	uint32 				encrAlg,						// encrypt/decrypt
418	uint32 				encrMode,
419	uint32 				padding,
420	uint32				keySizeInBits,
421	uint32 				efectiveKeySizeInBits,
422	uint32				cipherBlockSize,
423	CSSM_BOOL			useEvp,					// AES only
424	CSSM_BOOL 			stagedEncr,
425	CSSM_BOOL 			stagedDecr,
426	CSSM_BOOL 			quiet,
427	CSSM_BOOL			encryptOnly,
428	CSSM_BOOL			genRaw)					// first generate raw key (CSPDL)
429{
430	CSSM_DATA 		ctextRef = {0, NULL};		// ciphertext, reference
431	CSSM_DATA		ctextTest = {0, NULL};		// ciphertext, test
432	CSSM_DATA		rptext = {0, NULL};			// recovered plaintext
433	int				rtn = 0;
434	CSSM_RETURN		crtn;
435	uint32			rounds = 0;
436
437	if(encrAlg == CSSM_ALGID_RC5) {
438		/* roll the dice, pick one of three values for rounds */
439		unsigned die = genRand(1,3);
440		switch(die) {
441			case 1:
442				rounds = 8;
443				break;
444			case 2:
445				rounds = 12;
446				break;
447			case 3:
448				rounds = 16;
449				break;
450		}
451	}
452
453	/*
454	 * encrypt with each method;
455	 * verify ciphertexts compare;
456	 * decrypt with test code;
457	 * verify recovered plaintext and incoming plaintext compare;
458	 */
459	crtn = encryptDecryptRef(CSSM_TRUE,
460		encrAlg,
461		encrMode,
462		iv,
463		keySizeInBits,
464		efectiveKeySizeInBits,
465		cipherBlockSize,
466		rounds,
467		useEvp,
468		keyData,
469		ptext,
470		&ctextRef);
471	if(crtn) {
472		return testError(quiet);
473	}
474	crtn = encryptDecryptCSSM(cspHand,
475		CSSM_TRUE,
476		keyAlg,
477		encrAlg,
478		encrMode,
479		padding,
480		stagedEncr,
481		iv,
482		keySizeInBits,
483		efectiveKeySizeInBits,
484		cipherBlockSize,
485		rounds,
486		keyData,
487		ptext,
488		genRaw,
489		&ctextTest);
490	if(crtn) {
491		return testError(quiet);
492	}
493
494	/* ensure both methods resulted in same ciphertext */
495	if(ctextRef.Length != ctextTest.Length) {
496		printf("Ctext length mismatch (1)\n");
497		rtn = testError(quiet);
498		if(rtn) {
499			goto abort;
500		}
501	}
502	if(memcmp(ctextRef.Data, ctextTest.Data, ctextTest.Length)) {
503		printf("Ctext miscompare\n");
504		rtn = testError(quiet);
505		if(rtn) {
506			goto abort;
507		}
508	}
509
510	if(encryptOnly) {
511		rtn = 0;
512		goto abort;
513	}
514
515	/* decrypt with the test method */
516	crtn = encryptDecryptCSSM(cspHand,
517		CSSM_FALSE,
518		keyAlg,
519		encrAlg,
520		encrMode,
521		padding,
522		stagedDecr,
523		iv,
524		keySizeInBits,
525		efectiveKeySizeInBits,
526		cipherBlockSize,
527		rounds,
528		keyData,
529		&ctextTest,
530		genRaw,
531		&rptext);
532	if(crtn) {
533		return testError(quiet);
534	}
535	if(rptext.Length != ptext->Length) {
536		printf("ptext length mismatch (1)\n");
537		rtn = testError(quiet);
538		if(rtn) {
539			goto abort;
540		}
541	}
542	if(memcmp(rptext.Data, ptext->Data, ptext->Length)) {
543		printf("ptext miscompare\n");
544		rtn = testError(quiet);
545	}
546	else {
547		rtn = 0;
548	}
549abort:
550	if(ctextTest.Length) {
551		CSSM_FREE(ctextTest.Data);
552	}
553	if(ctextRef.Length) {
554		CSSM_FREE(ctextRef.Data);
555	}
556	if(rptext.Length) {
557		CSSM_FREE(rptext.Data);
558	}
559	return rtn;
560}
561
562
563int main(int argc, char **argv)
564{
565	int					arg;
566	char				*argp;
567	unsigned			loop;
568	CSSM_DATA			ptext;
569	CSSM_CSP_HANDLE 	cspHand;
570	CSSM_BOOL			stagedEncr;
571	CSSM_BOOL 			stagedDecr;
572	const char			*algStr;
573	uint32				keyAlg;					// CSSM_ALGID_xxx of the key
574	uint32				encrAlg;				// CSSM_ALGID_xxx of encr/decr
575	int					i;
576	unsigned			currAlg;				// ALG_xxx
577	uint32				actKeySizeInBits;
578	uint32				effectKeySizeInBits;
579	int					rtn = 0;
580	CSSM_DATA			keyData;
581	CSSM_DATA			initVector;
582	CSSM_BOOL			genRaw = CSSM_FALSE;	// first generate raw key (CSPDL)
583	uint32				minTextSize;
584	uint32				rawMode;
585	uint32				cookedMode;
586	const char			*rawModeStr;
587	const char			*cookedModeStr;
588	uint32				algBlockSize;
589
590	/*
591	 * User-spec'd params
592	 */
593	CSSM_BOOL	keySizeSpec = CSSM_FALSE;		// false: use rand key size
594	unsigned	minAlg = ALG_FIRST;
595	unsigned	maxAlg = ALG_LAST;
596	unsigned	loops = LOOPS_DEF;
597	CSSM_BOOL	verbose = CSSM_FALSE;
598	CSSM_BOOL	quiet = CSSM_FALSE;
599	unsigned	pauseInterval = 0;
600	uint32		padding;
601	CSSM_BOOL	bareCsp = CSSM_TRUE;
602	CSSM_BOOL	encryptOnly = CSSM_FALSE;
603	unsigned 	maxPtextSize = MAX_DATA_SIZE;
604	unsigned	minPtextSize = MIN_DATA_SIZE;
605	CSSM_BOOL	oneShotOnly = CSSM_FALSE;
606	CSSM_BOOL	allZeroes = CSSM_FALSE;
607	CSSM_BOOL	rawCookedSpecd = CSSM_FALSE;	// when true, use allRaw only
608	CSSM_BOOL	allRaw = CSSM_FALSE;
609	CSSM_BOOL	useEvp = CSSM_FALSE;
610
611	for(arg=1; arg<argc; arg++) {
612		argp = argv[arg];
613		switch(argp[0]) {
614			case 'a':
615				if(argp[1] != '=') {
616					usage(argv);
617				}
618				switch(argp[2]) {
619					case 'd':
620						minAlg = maxAlg = ALG_DES;
621						break;
622					case '3':
623						minAlg = maxAlg = ALG_3DES;
624						break;
625					case '2':
626						minAlg = maxAlg = ALG_RC2;
627						break;
628					case '4':
629						minAlg = maxAlg = ALG_RC4;
630						break;
631					case '5':
632						minAlg = maxAlg = ALG_RC5;
633						break;
634					case 'a':
635						minAlg = maxAlg = ALG_AES;
636						break;
637					case 'A':
638						minAlg = maxAlg = ALG_AES192;
639						break;
640					case '6':
641						minAlg = maxAlg = ALG_AES256;
642						break;
643					case 'b':
644						minAlg = maxAlg = ALG_BFISH;
645						break;
646					case 'c':
647						minAlg = maxAlg = ALG_CAST;
648						break;
649					default:
650						usage(argv);
651				}
652				break;
653		    case 'l':
654				loops = atoi(&argp[2]);
655				break;
656		    case 'k':
657		    	actKeySizeInBits = effectKeySizeInBits = atoi(&argp[2]);
658		    	keySizeSpec = CSSM_TRUE;
659				break;
660		    case 'v':
661		    	verbose = CSSM_TRUE;
662				break;
663			case 'D':
664				bareCsp = CSSM_FALSE;
665				#if CSPDL_ALL_KEYS_ARE_REF
666				genRaw = CSSM_TRUE;
667				#endif
668				break;
669		    case 'e':
670		    	encryptOnly = CSSM_TRUE;
671				break;
672			case 'm':
673				maxPtextSize = atoi(&argp[2]);
674				break;
675			case 'n':
676				minPtextSize = atoi(&argp[2]);
677				break;
678		    case 'z':
679		    	allZeroes = CSSM_TRUE;
680				break;
681		    case 's':
682		    	oneShotOnly = CSSM_TRUE;
683				break;
684		    case 'q':
685		    	quiet = CSSM_TRUE;
686				break;
687		    case 'p':
688		    	pauseInterval = atoi(&argp[2]);;
689				break;
690			case 'o':
691				rawCookedSpecd = CSSM_TRUE;
692				allRaw = CSSM_TRUE;
693				break;
694			case 'O':
695				rawCookedSpecd = CSSM_TRUE;
696				allRaw = CSSM_FALSE;		// i.e., use cooked
697				break;
698			case 'y':
699				useEvp = CSSM_TRUE;
700				break;
701		    case 'h':
702		    default:
703				usage(argv);
704		}
705	}
706	ptext.Data = (uint8 *)CSSM_MALLOC(maxPtextSize);
707	if(ptext.Data == NULL) {
708		printf("Insufficient heap space\n");
709		exit(1);
710	}
711	/* ptext length set in test loop */
712
713	keyData.Data = (uint8 *)CSSM_MALLOC(MAX_KEY_SIZE);
714	if(keyData.Data == NULL) {
715		printf("Insufficient heap space\n");
716		exit(1);
717	}
718	keyData.Length = MAX_KEY_SIZE;
719
720	initVector.Data = (uint8 *)"someStrangeInitVect";
721
722	printf("Starting symCompat; args: ");
723	for(i=1; i<argc; i++) {
724		printf("%s ", argv[i]);
725	}
726	printf("\n");
727	cspHand = cspDlDbStartup(bareCsp, NULL);
728	if(cspHand == 0) {
729		exit(1);
730	}
731	if(pauseInterval) {
732		fpurge(stdin);
733		printf("Top of test; hit CR to proceed: ");
734		getchar();
735	}
736	for(currAlg=minAlg; currAlg<=maxAlg; currAlg++) {
737		/* some default values... */
738		padding = CSSM_PADDING_PKCS1;
739		switch(currAlg) {
740			case ALG_DES:
741				encrAlg = keyAlg = CSSM_ALGID_DES;
742				algStr        = "DES";
743				algBlockSize  = 8;
744				if(useEvp) {
745					/* this one requires padding */
746					rawMode       = RAW_MODE;
747					cookedMode    = COOKED_MODE;
748					rawModeStr	  = RAW_MODE_STR;
749					cookedModeStr = COOKED_MODE_STR;
750					padding = CSSM_PADDING_PKCS5;
751				}
752				else {
753					rawMode       = RAW_MODE_BSAFE;
754					cookedMode    = CSSM_ALGMODE_CBCPadIV8;
755					rawModeStr	  = RAW_MODE_BSAFE_STR;
756					cookedModeStr = COOKED_MODE_STR;
757				}
758				break;
759			case ALG_3DES:
760				/* currently the only one with different key and encr algs */
761				keyAlg  = CSSM_ALGID_3DES_3KEY;
762				encrAlg = CSSM_ALGID_3DES_3KEY_EDE;
763				algStr = "3DES";
764				algBlockSize  = 8;
765				rawMode       = RAW_MODE_BSAFE;
766				cookedMode    = CSSM_ALGMODE_CBCPadIV8;
767				rawModeStr	  = RAW_MODE_BSAFE_STR;
768				cookedModeStr = COOKED_MODE_STR;
769				break;
770			case ALG_RC2:
771				encrAlg = keyAlg = CSSM_ALGID_RC2;
772				algStr = "RC2";
773				algBlockSize  = 8;
774				rawMode       = RAW_MODE_BSAFE;
775				cookedMode    = CSSM_ALGMODE_CBCPadIV8;
776				rawModeStr	  = RAW_MODE_BSAFE_STR;
777				cookedModeStr = COOKED_MODE_STR;
778				break;
779			case ALG_RC4:
780				encrAlg = keyAlg = CSSM_ALGID_RC4;
781				algStr = "RC4";
782				algBlockSize  = 0;
783				rawMode       = RAW_MODE_STREAM;
784				cookedMode    = RAW_MODE_STREAM;
785				rawModeStr	  = RAW_MODE_STREAM_STR;
786				cookedModeStr = RAW_MODE_STREAM_STR;
787				break;
788			case ALG_RC5:
789				encrAlg = keyAlg = CSSM_ALGID_RC5;
790				algStr = "RC5";
791				algBlockSize  = 8;
792				rawMode       = RAW_MODE_BSAFE;
793				cookedMode    = CSSM_ALGMODE_CBCPadIV8;
794				rawModeStr	  = RAW_MODE_BSAFE_STR;
795				cookedModeStr = COOKED_MODE_STR;
796				break;
797			case ALG_AES:
798				encrAlg = keyAlg = CSSM_ALGID_AES;
799				algStr = "AES";
800				algBlockSize  = 16;
801				if(useEvp) {
802					rawMode       = RAW_MODE;
803					cookedMode    = COOKED_MODE;
804					rawModeStr	  = RAW_MODE_STR;
805					cookedModeStr = COOKED_MODE_STR;
806					padding = CSSM_PADDING_PKCS7;
807				}
808				else {
809					/* padding not supported in ref implementation */
810					rawMode       = RAW_MODE;
811					cookedMode    = RAW_MODE_BSAFE;
812					rawModeStr	  = RAW_MODE_STR;
813					cookedModeStr = RAW_MODE_BSAFE_STR;
814				}
815				break;
816			case ALG_AES192:
817				encrAlg = keyAlg = CSSM_ALGID_AES;
818				algStr = "AES192";
819				/* padding not supported in ref implementation */
820				algBlockSize  = 24;
821				rawMode       = RAW_MODE;
822				cookedMode    = RAW_MODE_BSAFE;
823				rawModeStr	  = RAW_MODE_STR;
824				cookedModeStr = RAW_MODE_BSAFE_STR;
825				break;
826			case ALG_AES256:
827				encrAlg = keyAlg = CSSM_ALGID_AES;
828				algStr = "AES";
829				/* padding not supported in ref implementation */
830				algBlockSize  = 32;
831				rawMode       = RAW_MODE;
832				cookedMode    = RAW_MODE_BSAFE;
833				rawModeStr	  = RAW_MODE_STR;
834				cookedModeStr = RAW_MODE_BSAFE_STR;
835				break;
836			case ALG_BFISH:
837				encrAlg = keyAlg = CSSM_ALGID_BLOWFISH;
838				algStr = "Blowfish";
839				algBlockSize = 8;
840				/* libcrypt doesn't do padding or ECB */
841				rawMode       = RAW_MODE_BSAFE;
842				cookedMode    = RAW_MODE_BSAFE;
843				rawModeStr	  = RAW_MODE_BSAFE_STR;
844				cookedModeStr = RAW_MODE_BSAFE_STR;
845				break;
846			case ALG_CAST:
847				encrAlg = keyAlg = CSSM_ALGID_CAST;
848				algStr = "CAST";
849				algBlockSize = 8;
850				/* libcrypt doesn't do padding or ECB */
851				rawMode       = RAW_MODE_BSAFE;
852				cookedMode    = RAW_MODE_BSAFE;
853				rawModeStr	  = RAW_MODE_BSAFE_STR;
854				cookedModeStr = RAW_MODE_BSAFE_STR;
855				break;
856		}
857
858		/* assume for now all algs require IV */
859		initVector.Length = algBlockSize ? algBlockSize : 8;
860
861		if(!quiet || verbose) {
862			printf("Testing alg %s\n", algStr);
863		}
864		for(loop=1; ; loop++) {
865			/* mix up raw/cooked */
866			uint32 mode;
867			const char *modeStr;
868			CSSM_BOOL paddingEnabled;
869
870			if(rawCookedSpecd) {
871				if(allRaw) {
872					mode = rawMode;
873					modeStr = rawModeStr;
874				}
875				else {
876					mode = cookedMode;
877					modeStr = cookedModeStr;
878				}
879			}
880			else {
881				if(loop & 1) {
882					mode = rawMode;
883					modeStr = rawModeStr;
884				}
885				else {
886					mode = cookedMode;
887					modeStr = cookedModeStr;
888				}
889			}
890			switch(mode) {
891				case CSSM_ALGMODE_CBCPadIV8:
892					paddingEnabled = CSSM_TRUE;
893					break;
894				default:
895					/* all others - right? */
896					paddingEnabled = CSSM_FALSE;
897					break;
898			}
899			minTextSize = minPtextSize;	// default
900			if(!paddingEnabled && algBlockSize && (minTextSize < algBlockSize)) {
901				/* i.e., no padding, adjust min ptext size */
902				minTextSize = algBlockSize;
903			}
904			simpleGenData(&ptext, minTextSize, maxPtextSize);
905			if(!paddingEnabled && algBlockSize) {
906				/* align ptext */
907				ptext.Length = (ptext.Length / algBlockSize) * algBlockSize;
908			}
909
910			/* mix up staging */
911			if(oneShotOnly) {
912				stagedEncr = CSSM_FALSE;
913				stagedDecr = CSSM_FALSE;
914			}
915			else {
916				stagedEncr = (loop & 2) ? CSSM_TRUE : CSSM_FALSE;
917				stagedDecr = (loop & 4) ? CSSM_TRUE : CSSM_FALSE;
918			}
919
920			if(allZeroes) {
921				memset(ptext.Data, 0, ptext.Length);
922				memset(keyData.Data, 0, MAX_KEY_SIZE);
923				keyData.Length = MAX_KEY_SIZE;
924			}
925			else {
926				simpleGenData(&keyData, MAX_KEY_SIZE, MAX_KEY_SIZE);
927			}
928
929			if(!keySizeSpec) {
930				effectKeySizeInBits = randKeySizeBits(keyAlg, OT_Encrypt);
931				/*
932				 * generate keys with well aligned sizes; effectiveKeySize
933				 * differs only if not well aligned
934				 */
935				actKeySizeInBits = (effectKeySizeInBits + 7) & ~7;
936			}
937			/* else constant, spec'd by user, may be 0 (default per alg) */
938			if(!quiet) {
939			   	if(verbose || ((loop % LOOP_NOTIFY) == 0)) {
940					if(algBlockSize) {
941						printf("..loop %d text size %lu keySizeBits %u"
942							" blockSize %u stageEncr %d  stageDecr %d mode %s\n",
943							loop, (unsigned long)ptext.Length, (unsigned)effectKeySizeInBits,
944							(unsigned)algBlockSize, (int)stagedEncr, (int)stagedDecr,
945							modeStr);
946					}
947					else {
948						printf("..loop %d text size %lu keySizeBits %u"
949							" stageEncr %d  stageDecr %d mode %s\n",
950							loop, (unsigned long)ptext.Length, (unsigned)effectKeySizeInBits,
951							(int)stagedEncr, (int)stagedDecr, modeStr);
952					}
953				}
954			}
955
956			if(doTest(cspHand,
957					&ptext,
958					&keyData,
959					&initVector,
960					keyAlg,
961					encrAlg,
962					mode,
963					padding,
964					actKeySizeInBits,
965					actKeySizeInBits,		// FIXME - test effective key size
966					algBlockSize * 8,
967					useEvp,
968					stagedEncr,
969					stagedDecr,
970					quiet,
971					encryptOnly,
972					genRaw)) {
973				rtn = 1;
974				break;
975			}
976			if(pauseInterval && ((loop % pauseInterval) == 0)) {
977				char c;
978				fpurge(stdin);
979				printf("Hit CR to proceed, q to abort: ");
980				c = getchar();
981				if(c == 'q') {
982					goto testDone;
983				}
984			}
985			if(loops && (loop == loops)) {
986				break;
987			}
988		}	/* main loop */
989		if(rtn) {
990			break;
991		}
992
993	}	/* for algs */
994
995testDone:
996	cspShutdown(cspHand, bareCsp);
997	if(pauseInterval) {
998		fpurge(stdin);
999		printf("ModuleDetach/Unload complete; hit CR to exit: ");
1000		getchar();
1001	}
1002	if((rtn == 0) && !quiet) {
1003		printf("%s test complete\n", argv[0]);
1004	}
1005	CSSM_FREE(ptext.Data);
1006	CSSM_FREE(keyData.Data);
1007	return rtn;
1008}
1009
1010
1011