1/* Copyright (c) 1998,2003-2005,2008 Apple Inc.
2 *
3 * symDelta.c - Ensure that varying each parameter in a symmetric
4 *              encryption op does in fact change the ciphertext.
5 *
6 * Revision History
7 * ----------------
8 *  July 18 2000	Doug Mitchell at Apple
9 *		Created.
10 */
11#include <string.h>
12#include <stdlib.h>
13#include <stdio.h>
14#include <time.h>
15#include <Security/cssm.h>
16#include <Security/cssmapple.h>
17#include "cspwrap.h"
18#include "common.h"
19#include "cspdlTesting.h"
20
21/* we need to know a little bit about AES for this test.... */
22#define AES_BLOCK_SIZE		16		/* bytes */
23
24/*
25 * Defaults.
26 */
27#define LOOPS_DEF			10
28#define MIN_PTEXT_SIZE		AES_BLOCK_SIZE		/* for non-padding tests */
29#define MAX_PTEXT_SIZE		1000
30#define MAX_IV_SIZE			AES_BLOCK_SIZE
31
32/*
33 * Enumerate algs our own way to allow iteration.
34 */
35typedef unsigned privAlg;
36enum {
37	pka_ASC,
38	pka_RC4,
39	pka_DES,
40	pka_RC2,
41	pka_RC5,
42	pka_3DES,
43	pka_AES
44};
45
46/*
47 * Ditto for modes. ALGMODE_NONE not iterated, it's a special case for
48 * RC4 and ASC.
49 */
50typedef unsigned privMode;
51enum {
52	pma_CBC_PadIV8,
53	pma_CBC_IV8,			// no pad - requires well-aligned ptext
54	pma_ECB,				// no IV, no pad - requires well-aligned ptext
55};
56
57#define ENCR_ALG_FIRST			pka_ASC
58#define ENCR_ALG_LAST			pka_AES
59
60#define ENCR_MODE_FIRST			pma_CBC_PadIV8
61#define ENCR_MODE_LAST			pma_ECB
62
63/*
64 * Args passed to each test and to testCommon; these completely define
65 * the paramters for one encryption op.
66 */
67typedef struct {
68	CSSM_CSP_HANDLE 	cspHand;
69	CSSM_ALGORITHMS		keyAlg;
70	CSSM_ALGORITHMS		encrAlg;
71	uint32				keySizeInBits;
72	uint32				effectiveKeySizeInBits;	// 0 means not used
73	uint32				rounds;					// ditto
74	const char 			*keyAlgStr;
75	CSSM_ENCRYPT_MODE	encrMode;
76	const char			*encrModeStr;
77	CSSM_PADDING		encrPad;
78	CSSM_DATA_PTR		ptext;
79	CSSM_BOOL 			useInitVector;		// encrypt needs an IV
80	CSSM_BOOL			useRefKey;
81	CSSM_DATA			initVector;			// Data mallocd and init in main()
82	CSSM_KEY_PTR		key;				// gen'd in main
83	CSSM_BOOL			verbose;
84	CSSM_BOOL			quiet;
85} testArgs;
86
87static void usage(char **argv)
88{
89	printf("usage: %s [options]\n", argv[0]);
90	printf("   Options:\n");
91	printf("   l=loops (default=%d; 0=forever)\n", LOOPS_DEF);
92	printf("   e(xport)\n");
93	printf("   r(epeatOnly)\n");
94	printf("   p(ause after each loop)\n");
95	printf("   D (CSP/DL; default = bare CSP)\n");
96	printf("   q(uiet)\n");
97	printf("   h(elp)\n");
98	exit(1);
99}
100
101/*
102 * Given a privAlg value, return various associated stuff.
103 */
104static void algInfo(privAlg alg,		// pka_DES, etc.
105	CSSM_ALGORITHMS		*keyAlg,		// CSSM_ALGID_DES, etc. RETURNED
106										//   key alg for key gen algs
107	CSSM_ALGORITHMS		*encrAlg,		// encrypt/decrypt alg for key
108										//   gen algs
109	const char			**algStr,		// RETURNED
110	CSSM_SIZE			*ivSize)		// RETURNED
111{
112	*ivSize = 8;
113	switch(alg) {
114		case pka_DES:
115			*keyAlg = *encrAlg = CSSM_ALGID_DES;
116			*algStr = "DES";
117			return;
118		case pka_3DES:
119			*keyAlg = CSSM_ALGID_3DES_3KEY;
120			*encrAlg = CSSM_ALGID_3DES_3KEY_EDE;
121			*algStr = "3DES";
122			return;
123		case pka_RC2:
124			*keyAlg = *encrAlg = CSSM_ALGID_RC2;
125			*algStr = "RC2";
126			return;
127		case pka_RC4:
128			*keyAlg = *encrAlg = CSSM_ALGID_RC4;
129			/* initVector false */
130			*ivSize = 0;
131			*algStr = "RC4";
132			return;
133		case pka_RC5:
134			*keyAlg = *encrAlg = CSSM_ALGID_RC5;
135			*algStr = "RC5";
136			return;
137		case pka_AES:
138			*keyAlg = *encrAlg = CSSM_ALGID_AES;
139			*algStr = "AES";
140			*ivSize = AES_BLOCK_SIZE;
141			return;
142		case pka_ASC:
143			*keyAlg = *encrAlg = CSSM_ALGID_ASC;
144			/* initVector false */
145			*ivSize = 0;
146			*algStr = "ASC";
147			return;
148		default:
149			printf("BRRZZZT! Update algInfo()!\n");
150			testError(CSSM_TRUE);
151	}
152}
153
154/* given a privMode, return related info */
155static void modeInfo(
156	CSSM_ALGORITHMS		alg,
157	privMode 			mode,
158	CSSM_ENCRYPT_MODE	*cdsaMode,
159	const char			**modeStr,
160	CSSM_PADDING		*pad,			// PKCS5 or NONE
161	CSSM_BOOL			*useInitVector)	// RETURNED, for encrypt/decrypt
162{
163	*useInitVector = CSSM_FALSE;
164
165	/* first deal with modeless algorithms */
166	switch(alg) {
167		case CSSM_ALGID_RC4:
168		case CSSM_ALGID_ASC:
169			*cdsaMode = CSSM_ALGMODE_NONE;
170			*modeStr = "NONE";
171			*pad = CSSM_PADDING_NONE;
172			return;
173		default:
174			break;
175	}
176
177	switch(mode) {
178		case pma_CBC_PadIV8:
179			*cdsaMode = CSSM_ALGMODE_CBCPadIV8;
180			*modeStr = "CBCPadIV8";
181			*useInitVector = CSSM_TRUE;
182			*pad = CSSM_PADDING_PKCS5;
183			return;
184		case pma_CBC_IV8:
185			*cdsaMode = CSSM_ALGMODE_CBC_IV8;
186			*modeStr = "CBC_IV8";
187			*useInitVector = CSSM_TRUE;
188			*pad = CSSM_PADDING_NONE;
189			return;
190		case pma_ECB:
191			*cdsaMode = CSSM_ALGMODE_ECB;
192			*modeStr = "ECB";
193			*pad = CSSM_PADDING_NONE;
194			return;
195		default:
196			printf("BRRZZZT! Update modeInfo()!\n");
197			testError(CSSM_TRUE);
198	}
199}
200
201/*
202 * Given alg and mode, determine alignment of ptext size. 0 means no
203 * alignment necessary.
204 */
205uint32 alignInfo(
206	CSSM_ALGORITHMS		alg,
207	CSSM_ENCRYPT_MODE	mode)
208{
209	switch(alg) {
210		case CSSM_ALGID_RC4:
211		case CSSM_ALGID_ASC:
212			return 0;
213		default:
214			break;
215	}
216
217	switch(mode) {
218		case CSSM_ALGMODE_CBC_IV8:
219		case CSSM_ALGMODE_ECB:
220			if(alg == CSSM_ALGID_AES) {
221				return AES_BLOCK_SIZE;
222			}
223			else {
224				return 8;
225			}
226		default:
227			return 0;
228	}
229}
230
231/* a handy "compare two CSSM_DATAs" ditty */
232static CSSM_BOOL compareData(const CSSM_DATA_PTR d1,
233	const CSSM_DATA_PTR d2)
234{
235	if(d1->Length != d2->Length) {
236		return CSSM_FALSE;
237	}
238	if(memcmp(d1->Data, d2->Data, d1->Length)) {
239		return CSSM_FALSE;
240	}
241	return CSSM_TRUE;
242}
243
244/* generate random one-bit byte */
245static uint8 randBit()
246{
247	return 1 << genRand(0, 7);
248}
249
250/*
251 * Copy a key.
252 */
253static void copyCssmKey(
254	const CSSM_KEY_PTR	key1,
255	CSSM_KEY_PTR		key2)
256{
257	key2->KeyHeader = key1->KeyHeader;
258	key2->KeyData.Data = NULL;
259	key2->KeyData.Length = 0;
260	appCopyCssmData(&key1->KeyData, &key2->KeyData);
261}
262
263/*
264 * Encrypt ptext using specified parameters
265 */
266static int encryptCom(CSSM_CSP_HANDLE cspHand,
267	const char *testName,
268	CSSM_DATA_PTR ptext,
269	CSSM_KEY_PTR key,
270	CSSM_ALGORITHMS alg,
271	CSSM_ENCRYPT_MODE mode,
272	CSSM_PADDING padding,			// CSSM_PADDING_PKCS1, etc.
273	CSSM_DATA_PTR iv,				// may be NULL
274	uint32 effectiveKeySizeInBits,	// may be 0
275	uint32 rounds,					// ditto
276	CSSM_DATA_PTR ctext,			// RETURNED
277	CSSM_BOOL quiet)
278{
279	CSSM_CC_HANDLE cryptHand;
280	CSSM_RETURN crtn;
281	CSSM_SIZE bytesEncrypted;
282	CSSM_DATA remData;
283	int rtn;
284
285	cryptHand = genCryptHandle(cspHand,
286		alg,
287		mode,
288		padding,
289		key,
290		NULL,			// no 2nd key
291		iv,				// InitVector
292		effectiveKeySizeInBits,
293		rounds);
294	if(cryptHand == 0) {
295		return testError(quiet);
296	}
297
298	remData.Data = NULL;
299	remData.Length = 0;
300	crtn = CSSM_EncryptData(cryptHand,
301		ptext,
302		1,
303		ctext,
304		1,
305		&bytesEncrypted,
306		&remData);
307
308	if(crtn) {
309		printError("CSSM_EncryptData", crtn);
310		rtn = testError(quiet);
311		goto done;
312	}
313	if(remData.Length != 0) {
314		ctext->Data = (uint8 *)appRealloc(ctext->Data, bytesEncrypted, NULL);
315		memmove(ctext->Data + ctext->Length,
316			remData.Data,
317			bytesEncrypted - ctext->Length);
318		appFreeCssmData(&remData, CSSM_FALSE);
319	}
320	ctext->Length = bytesEncrypted;
321	rtn = 0;
322done:
323	if(CSSM_DeleteContext(cryptHand)) {
324		printError("CSSM_DeleteContext", 0);
325		rtn = 1;
326	}
327	return rtn;
328}
329
330/*
331 * Common test portion
332 *   encrypt ptext with args in targ1;
333 *   encrypt ptext with args in targ2;
334 *	 compare 2 ctexts; expect failure;
335 */
336static int testCommon(const char *testName,
337	testArgs *targs1,
338	testArgs *targs2)
339{
340	CSSM_DATA		ctext1 = {0, NULL};
341	CSSM_DATA		ctext2 = {0, NULL};
342
343	if(encryptCom(targs1->cspHand,
344			testName,
345			targs1->ptext,
346			targs1->key,
347			targs1->encrAlg,
348			targs1->encrMode,
349			targs1->encrPad,
350			&targs1->initVector,
351			targs1->effectiveKeySizeInBits,
352			targs1->rounds,
353			&ctext1,
354			targs1->quiet)) {
355		return 1;
356	}
357	if(encryptCom(targs2->cspHand,
358			testName,
359			targs2->ptext,
360			targs2->key,
361			targs2->encrAlg,
362			targs2->encrMode,
363			targs2->encrPad,
364			&targs2->initVector,
365			targs2->effectiveKeySizeInBits,
366			targs2->rounds,
367			&ctext2,
368			targs2->quiet)) {
369		return 1;
370	}
371	if(compareData(&ctext1, &ctext2)) {
372		printf("***%s: Unexpected Data compare!\n", testName);
373		return testError(targs1->quiet);
374	}
375	appFreeCssmData(&ctext1, CSSM_FALSE);
376	appFreeCssmData(&ctext2, CSSM_FALSE);
377	return 0;
378}
379
380/**
381 ** inidividual tests.
382 **/
383#define KEY_LABEL1		"noLabel1"
384#define KEY_LABEL2		"noLabel2"
385#define KEY_LABEL_LEN	strlen(KEY_LABEL1)
386#define REPEAT_ON_ERROR	1
387
388/*
389 * Ensure initVector alters ctext.
390 */
391static int initVectTest(testArgs *targs)
392{
393	uint32			mungeDex;
394	uint32			mungeBits;
395	testArgs		mungeArgs = *targs;
396	CSSM_DATA		mungeIV;
397
398	if(targs->verbose) {
399		printf("         ...modifying init vector\n");
400	}
401
402	/* get munged copy of iv */
403	mungeIV.Length = targs->initVector.Length;
404	mungeIV.Data = (uint8 *)CSSM_MALLOC(mungeIV.Length);
405	memmove(mungeIV.Data, targs->initVector.Data, mungeIV.Length);
406	mungeArgs.initVector = mungeIV;
407	mungeDex = genRand(0, mungeIV.Length - 1);
408	mungeBits = randBit();
409	mungeIV.Data[mungeDex] ^= mungeBits;
410	if(testCommon("initVectTest", targs, &mungeArgs))  {
411		return 1;
412	}
413	appFreeCssmData(&mungeIV, CSSM_FALSE);
414	return 0;
415}
416
417/*
418 * Ensure effectiveKeySizeInBits alters ctext. RC2 only.
419 */
420static int effectSizeTest(testArgs *targs)
421{
422	testArgs		mungeArgs = *targs;
423
424	if(targs->verbose) {
425		printf("         ...modifying effective key size\n");
426	}
427	mungeArgs.effectiveKeySizeInBits -= 8;
428	return testCommon("effectSizeTest", targs, &mungeArgs);
429}
430
431/*
432 * Ensure rounds alters ctext. RC5 only.
433 */
434static int roundsTest(testArgs *targs)
435{
436	testArgs		mungeArgs = *targs;
437
438	if(targs->verbose) {
439		printf("         ...modifying rounds\n");
440	}
441	switch(targs->rounds) {
442		case 8:
443			mungeArgs.rounds = 12;
444			break;
445		case 12:
446			mungeArgs.rounds = 16;
447			break;
448		case 16:
449			mungeArgs.rounds = 8;
450			break;
451		default:
452			printf("***ACK! roundsTest needs work!\n");
453			return 1;
454	}
455	return testCommon("roundsTest", targs, &mungeArgs);
456}
457
458
459/*
460 * ensure encryption algorithm alters ctext.
461 */
462static int encrAlgTest(testArgs *targs)
463{
464	testArgs		mungeArgs = *targs;
465	CSSM_KEY		mungeKey = *targs->key;
466
467	/* come up with different encrypt alg - not all work */
468	switch(targs->encrAlg) {
469		case CSSM_ALGID_DES:		// fixed size key
470		case CSSM_ALGID_3DES_3KEY_EDE:
471		default:
472			return 0;
473		case CSSM_ALGID_RC4:		// no IV
474			mungeArgs.encrAlg = CSSM_ALGID_ASC;
475			break;
476		case CSSM_ALGID_ASC:		// no IV
477			mungeArgs.encrAlg = CSSM_ALGID_RC4;
478			break;
479		case CSSM_ALGID_RC2:
480			mungeArgs.encrAlg = CSSM_ALGID_RC5;
481			break;
482		case CSSM_ALGID_RC5:
483			mungeArgs.encrAlg = CSSM_ALGID_RC2;
484			break;
485		case CSSM_ALGID_AES:
486			mungeArgs.encrAlg = CSSM_ALGID_RC5;
487			mungeArgs.initVector.Length = 8;
488			break;
489	}
490
491	/* we're assuming this is legal - a shallow copy of a key, followed by a blind
492	 * reassignment of its algorithm... */
493	mungeKey.KeyHeader.AlgorithmId = mungeArgs.encrAlg;
494	mungeArgs.key = &mungeKey;
495
496	if(targs->verbose) {
497		printf("         ...modifying encryption alg\n");
498	}
499
500	return testCommon("encrAlgTest", targs, &mungeArgs);
501}
502
503/*
504 * ensure encryption mode alters ctext.
505 */
506static int encrModeTest(testArgs *targs)
507{
508	testArgs		mungeArgs = *targs;
509
510	/* come up with different encrypt mode - not all work */
511	switch(targs->encrMode) {
512		case CSSM_ALGMODE_NONE:			// i.e., RC4, ASC
513		case CSSM_ALGMODE_CBCPadIV8:	// others, only one which does
514										//   padding
515			return 0;
516		case CSSM_ALGMODE_CBC_IV8:
517			mungeArgs.encrMode = CSSM_ALGMODE_ECB;
518			mungeArgs.useInitVector = CSSM_FALSE;
519			break;
520		case CSSM_ALGMODE_ECB:
521			mungeArgs.encrMode = CSSM_ALGMODE_CBC_IV8;
522			mungeArgs.useInitVector = CSSM_TRUE;
523			break;
524		default:
525			printf("Update encrModeTest\n");
526			return 1;
527	}
528	if(targs->verbose) {
529		printf("         ...modifying encryption mode\n");
530	}
531
532	return testCommon("encrModeTest", targs, &mungeArgs);
533}
534
535/*
536 * Ensure ptext alters ctext.
537 */
538static int ptextTest(testArgs *targs)
539{
540	uint32			mungeDex;
541	uint32			mungeBits;
542	testArgs		mungeArgs = *targs;
543	CSSM_DATA		mungePtext;
544
545	if(targs->verbose) {
546		printf("         ...modifying plaintext\n");
547	}
548
549	/* get munged copy of ptext */
550	mungePtext.Length = targs->ptext->Length;
551	mungePtext.Data = (uint8 *)CSSM_MALLOC(mungePtext.Length);
552	memmove(mungePtext.Data, targs->ptext->Data, mungePtext.Length);
553	mungeArgs.ptext = &mungePtext;
554	mungeDex = genRand(0, mungePtext.Length - 1);
555	mungeBits = randBit();
556	mungePtext.Data[mungeDex] ^= mungeBits;
557	if(testCommon("ptextTest", targs, &mungeArgs))  {
558		return 1;
559	}
560	appFreeCssmData(&mungePtext, CSSM_FALSE);
561	return 0;
562}
563
564/*
565 * Ensure key alters ctext. Requires raw key, of course.
566 */
567static int keyTest(testArgs *targs)
568{
569	uint32			mungeDex;
570	uint32			mungeBits;
571	testArgs		mungeArgs = *targs;
572	CSSM_KEY		mungeKey;
573	unsigned		minBit;
574	unsigned		maxByte;
575
576	if(targs->verbose) {
577		printf("         ...modifying key\n");
578	}
579
580	/* get munged copy of key */
581	copyCssmKey(targs->key, &mungeKey);
582	mungeArgs.key = &mungeKey;
583
584	maxByte = mungeKey.KeyData.Length - 1;
585	if(targs->effectiveKeySizeInBits) {
586		/* skip MS byte - partially used */
587		maxByte--;
588	}
589	mungeDex = genRand(0, maxByte);
590
591	minBit = 0;
592	switch(targs->keyAlg) {
593		case CSSM_ALGID_DES:
594		case CSSM_ALGID_DESX:
595		case CSSM_ALGID_3DES_3KEY:
596			/* skip lsb - DES parity bit */
597			minBit++;
598			break;
599		default:
600			break;
601	}
602	mungeBits = 1 << genRand(minBit, 7);
603	mungeKey.KeyData.Data[mungeDex] ^= mungeBits;
604	if(testCommon("keyTest", targs, &mungeArgs))  {
605		return 1;
606	}
607	appFreeCssmData(&mungeKey.KeyData, CSSM_FALSE);
608	return 0;
609}
610
611int main(int argc, char **argv)
612{
613	int					arg;
614	char				*argp;
615	unsigned			loop;
616	CSSM_DATA			ptext;
617	CSSM_DATA			initVector;
618	testArgs			targs;
619	privAlg				encrAlg;
620	int 				rtn = 0;
621	privMode			pmode;
622	uint32				origLen;
623	uint32				alignRequired;
624	CSSM_BOOL			refKeys = CSSM_FALSE;
625	int					i;
626
627	/*
628	 * User-spec'd params
629	 */
630	unsigned	loops = LOOPS_DEF;
631	CSSM_BOOL	quiet = CSSM_FALSE;
632	CSSM_BOOL	doPause = CSSM_FALSE;
633	CSSM_BOOL	verbose = CSSM_FALSE;
634	CSSM_BOOL	repeatOnly = CSSM_FALSE;
635	CSSM_BOOL	bareCsp = CSSM_TRUE;
636
637	for(arg=1; arg<argc; arg++) {
638		argp = argv[arg];
639		switch(argp[0]) {
640		    case 'l':
641				loops = atoi(&argp[2]);
642				break;
643		    case 'q':
644		    	quiet = CSSM_TRUE;
645				break;
646		    case 'v':
647		    	verbose = CSSM_TRUE;
648				break;
649			case 'D':
650				bareCsp = CSSM_FALSE;
651				#if 	CSPDL_ALL_KEYS_ARE_REF
652				refKeys = CSSM_TRUE;
653				#endif
654				break;
655		    case 'p':
656		    	doPause = CSSM_TRUE;
657				break;
658			case 'r':
659				repeatOnly = CSSM_TRUE;
660				break;
661		    case 'h':
662		    default:
663				usage(argv);
664		}
665	}
666
667	/* statically allocate ptext and initVector; data and length
668	 * change in test loop */
669	ptext.Data = (uint8 *)CSSM_MALLOC(MAX_PTEXT_SIZE);
670	initVector.Data = (uint8 *)CSSM_MALLOC(MAX_IV_SIZE);
671	targs.ptext = &ptext;
672	targs.initVector = initVector;
673	targs.verbose = verbose;
674	targs.quiet = quiet;
675
676	printf("Starting symDelta; args: ");
677	for(i=1; i<argc; i++) {
678		printf("%s ", argv[i]);
679	}
680	printf("\n");
681	targs.cspHand = cspDlDbStartup(bareCsp, NULL);
682	if(targs.cspHand == 0) {
683		exit(1);
684	}
685
686	for(loop=1; ; loop++) {
687		if(!quiet) {
688			printf("...loop %d\n", loop);
689		}
690		/* change once per outer loop */
691		simpleGenData(&ptext, MIN_PTEXT_SIZE, MAX_PTEXT_SIZE);
692		origLen = ptext.Length;
693		simpleGenData(&initVector, MAX_IV_SIZE, MAX_IV_SIZE);
694		targs.useRefKey = refKeys;
695
696		for(encrAlg=ENCR_ALG_FIRST; encrAlg<=ENCR_ALG_LAST; encrAlg++) {
697			/* Cook up encryption-related args */
698			algInfo(encrAlg,
699				&targs.keyAlg,
700				&targs.encrAlg,
701				&targs.keyAlgStr,
702				&targs.initVector.Length);
703
704			/* random key size */
705			targs.effectiveKeySizeInBits = randKeySizeBits(targs.keyAlg, OT_Encrypt);
706			targs.keySizeInBits = (targs.effectiveKeySizeInBits + 7) & ~7;
707			if(targs.keySizeInBits == targs.effectiveKeySizeInBits) {
708				/* same size, ignore effective */
709				targs.effectiveKeySizeInBits = 0;
710			}
711			if(!quiet) {
712				printf("   ...Encrypt alg %s keySizeInBits %u effectKeySize %u\n",
713					targs.keyAlgStr, (unsigned)targs.keySizeInBits,
714					(unsigned)targs.effectiveKeySizeInBits);
715			}
716
717			/* generate raw key for this keyAlg */
718			targs.key = cspGenSymKey(targs.cspHand,
719				targs.keyAlg,
720				KEY_LABEL1,
721				KEY_LABEL_LEN,
722				CSSM_KEYUSE_ENCRYPT,
723				targs.keySizeInBits,
724				targs.useRefKey);
725			if(targs.key == NULL) {
726				if(testError(quiet)) {
727					goto testDone;		// abort
728				}
729				else {
730					continue;			// next key alg
731				}
732			}
733
734			/*
735			 * Inner loop: iterate thru modes for algorithms which
736			 * support them
737			 */
738			for(pmode=ENCR_MODE_FIRST;
739			    pmode<=ENCR_MODE_LAST;
740				pmode++) {
741
742				/* Cook up mode-related args */
743				modeInfo(targs.keyAlg,
744					pmode,
745					&targs.encrMode,
746					&targs.encrModeStr,
747					&targs.encrPad,
748					&targs.useInitVector);
749
750				if(targs.keyAlg == CSSM_ALGID_RC5) {
751					/* roll the dice, pick one of three values for rounds */
752					unsigned die = genRand(1,3);
753					switch(die) {
754						case 1:
755							targs.rounds = 8;
756							break;
757						case 2:
758							targs.rounds = 12;
759							break;
760						case 3:
761							targs.rounds = 16;
762							break;
763					}
764				}
765				else {
766					targs.rounds = 0;
767				}
768				if(!quiet) {
769					printf("      ...mode %s\n", targs.encrModeStr);
770				}
771
772				alignRequired = alignInfo(targs.encrAlg, targs.encrMode);
773				if(alignRequired) {
774					/* truncate ptext - we'll restore it at end of loop */
775					ptext.Length &= (~(alignRequired - 1));
776				}
777				if(targs.useInitVector) {
778					if(initVectTest(&targs)) {
779						rtn = 1;
780						goto testDone;
781					}
782				}
783
784				if(targs.effectiveKeySizeInBits != 0) {
785					if(effectSizeTest(&targs)) {
786						rtn = 1;
787						goto testDone;
788					}
789				}
790
791				if(targs.rounds != 0) {
792					if(roundsTest(&targs)) {
793						rtn = 1;
794						goto testDone;
795					}
796				}
797
798				if(!targs.useRefKey) {
799					/* can't do this with ref keys due to key/encr alg mismatch */
800					if(encrAlgTest(&targs)) {
801						rtn = 1;
802						goto testDone;
803					}
804				}
805
806				if(encrModeTest(&targs)) {
807					rtn = 1;
808					goto testDone;
809				}
810				if(ptextTest(&targs)) {
811					rtn = 1;
812					goto testDone;
813				}
814				if(!targs.useRefKey) {
815					if(keyTest(&targs)) {
816						rtn = 1;
817						goto testDone;
818					}
819				}
820
821
822				/* restore possible rounded ptext length */
823				ptext.Length = origLen;
824
825				if(targs.encrMode == CSSM_ALGMODE_NONE) {
826					/* one mode, we're done */
827					break;
828				}
829
830			} /* for mode */
831
832			/* free key */
833			cspFreeKey(targs.cspHand, targs.key);
834			CSSM_FREE(targs.key);
835
836		} /* for encrAlg */
837		if(doPause) {
838			if(testError(quiet)) {
839				break;
840			}
841		}
842		if(loops && (loop == loops)) {
843			break;
844		}
845	} /* for loop */
846
847testDone:
848	CSSM_ModuleDetach(targs.cspHand);
849	if(!quiet && (rtn == 0)) {
850		printf("%s test complete\n", argv[0]);
851	}
852	return rtn;
853}
854