1/* Copyright (c) 2006,2008 Apple Inc.
2 *
3 * ccSymTest.c - test CommonCrypto symmetric encrypt/decrypt.
4 */
5#include <string.h>
6#include <stdlib.h>
7#include <stdio.h>
8#include <CommonCrypto/CommonCryptor.h>
9#include "common.h"
10#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
11
12/*
13 * Defaults.
14 */
15#define LOOPS_DEF		500
16#define MIN_DATA_SIZE	8
17#define MAX_DATA_SIZE	10000						/* bytes */
18#define MAX_KEY_SIZE	kCCKeySizeMaxRC4			/* bytes */
19#define MAX_BLOCK_SIZE	kCCBlockSizeAES128			/* bytes */
20#define LOOP_NOTIFY		250
21
22/*
23 * Enumerate algs our own way to allow iteration.
24 */
25typedef enum {
26	ALG_AES_128 = 1,	/* 128 bit block, 128 bit key */
27	ALG_AES_192,		/* 128 bit block, 192 bit key */
28	ALG_AES_256,		/* 128 bit block, 256 bit key */
29	ALG_DES,
30	ALG_3DES,
31	ALG_CAST,
32	ALG_RC4,
33	/* these aren't in CommonCrypto (yet?) */
34	ALG_RC2,
35	ALG_RC5,
36	ALG_BFISH,
37	ALG_ASC,
38	ALG_NULL					/* normally not used */
39} SymAlg;
40#define ALG_FIRST			ALG_AES_128
41#define ALG_LAST			ALG_RC4
42
43
44#define LOG_SIZE			0
45#if		LOG_SIZE
46#define logSize(s)	printf s
47#else
48#define logSize(s)
49#endif
50
51static void usage(char **argv)
52{
53	printf("usage: %s [options]\n", argv[0]);
54	printf("   Options:\n");
55	printf("   a=algorithm (d=DES; 3=3DES; a=AES128; n=AES192; A=AES256; \n");
56	printf("     c=CAST; 4=RC4; default=all)\n");
57	printf("   l=loops (default=%d; 0=forever)\n", LOOPS_DEF);
58	printf("   m=maxPtextSize (default=%d)\n", MAX_DATA_SIZE);
59	printf("   n=minPtextSize (default=%d)\n", MIN_DATA_SIZE);
60	printf("   k=keySizeInBytes\n");
61	printf("   p=pauseInterval (default=0, no pause)\n");
62	printf("   o (no padding, well-aligned plaintext)\n");
63	printf("   e (ECB only)\n");
64	printf("   E (CBC only, no ECB)\n");
65	printf("   u (no multi-update ops)\n");
66	printf("   U (only multi-update ops)\n");
67	printf("   x (always allocate context)\n");
68	printf("   X (never allocate context)\n");
69	printf("   v(erbose)\n");
70	printf("   q(uiet)\n");
71	printf("   h(elp)\n");
72	exit(1);
73}
74
75static void printCCError(const char *str, CCCryptorStatus crtn)
76{
77	const char *errStr;
78	char unknownStr[200];
79
80	switch(crtn) {
81		case kCCSuccess: errStr = "kCCSuccess"; break;
82		case kCCParamError: errStr = "kCCParamError"; break;
83		case kCCBufferTooSmall: errStr = "kCCBufferTooSmall"; break;
84		case kCCMemoryFailure: errStr = "kCCMemoryFailure"; break;
85		case kCCAlignmentError: errStr = "kCCAlignmentError"; break;
86		case kCCDecodeError: errStr = "kCCDecodeError"; break;
87		case kCCUnimplemented: errStr = "kCCUnimplemented"; break;
88		default:
89			sprintf(unknownStr, "Unknown(%ld)\n", (long)crtn);
90			errStr = unknownStr;
91			break;
92	}
93	printf("***%s returned %s\n", str, errStr);
94}
95
96/* max context size */
97#define CC_MAX_CTX_SIZE	kCCContextSizeRC4
98
99/*
100 * We write a marker at end of expected output and at end of caller-allocated
101 * CCCryptorRef, and check at the end to make sure they weren't written
102 */
103#define MARKER_LENGTH	8
104#define MARKER_BYTE		0x7e
105
106/*
107 * Test harness for CCCryptor with lots of options.
108 */
109CCCryptorStatus doCCCrypt(
110	bool forEncrypt,
111	CCAlgorithm encrAlg,
112	bool doCbc,
113	bool doPadding,
114	const void *keyBytes, size_t keyLen,
115	const void *iv,
116	bool randUpdates,
117	bool inPlace,								/* !doPadding only */
118	size_t ctxSize,								/* if nonzero, we allocate ctx */
119	bool askOutSize,
120	const uint8_t *inText, size_t inTextLen,
121	uint8_t **outText, size_t *outTextLen)		/* both returned, WE malloc */
122{
123	CCCryptorRef	cryptor = NULL;
124	CCCryptorStatus crtn;
125	CCOperation		op = forEncrypt ? kCCEncrypt : kCCDecrypt;
126	CCOptions		options = 0;
127	uint8_t			*outBuf = NULL;			/* mallocd output buffer */
128	uint8_t			*outp;					/* running ptr into outBuf */
129	const uint8		*inp;					/* running ptr into inText */
130	size_t			outLen;					/* bytes remaining in outBuf */
131	size_t			toMove;					/* bytes remaining in inText */
132	size_t			thisMoveOut;			/* output from CCCryptUpdate()/CCCryptFinal() */
133	size_t			outBytes;				/* total bytes actually produced in outBuf */
134	char			ctx[CC_MAX_CTX_SIZE];	/* for CCCryptorCreateFromData() */
135	uint8_t			*textMarker = NULL;		/* 8 bytes of marker here after expected end of
136											 * output */
137	char			*ctxMarker = NULL;		/* ditto for caller-provided context */
138	unsigned		dex;
139	size_t			askedOutSize;			/* from the lib */
140	size_t			thisOutLen;				/* dataOutAvailable we use */
141
142	if(ctxSize > CC_MAX_CTX_SIZE) {
143		printf("***HEY! Adjust CC_MAX_CTX_SIZE!\n");
144		exit(1);
145	}
146	if(!doCbc) {
147		options |= kCCOptionECBMode;
148	}
149	if(doPadding) {
150		options |= kCCOptionPKCS7Padding;
151	}
152
153	/* just hack this one */
154	outLen = inTextLen;
155	if(forEncrypt) {
156		outLen += MAX_BLOCK_SIZE;
157	}
158
159	outBuf = (uint8_t *)malloc(outLen + MARKER_LENGTH);
160
161	/* library should not touch this memory */
162	textMarker = outBuf + outLen;
163	memset(textMarker, MARKER_BYTE, MARKER_LENGTH);
164
165	/* subsequent errors to errOut: */
166
167	if(inPlace) {
168		memmove(outBuf, inText, inTextLen);
169		inp = outBuf;
170	}
171	else {
172		inp = inText;
173	}
174
175	if(!randUpdates) {
176		/* one shot */
177		if(askOutSize) {
178			crtn = CCCrypt(op, encrAlg, options,
179				keyBytes, keyLen, iv,
180				inp, inTextLen,
181				outBuf, 0, &askedOutSize);
182			if(crtn != kCCBufferTooSmall) {
183				printf("***Did not get kCCBufferTooSmall as expected\n");
184				printf("   alg %d inTextLen %lu cbc %d padding %d keyLen %lu\n",
185					(int)encrAlg, (unsigned long)inTextLen, (int)doCbc, (int)doPadding,
186					(unsigned long)keyLen);
187				printCCError("CCCrypt", crtn);
188				crtn = -1;
189				goto errOut;
190			}
191			outLen = askedOutSize;
192		}
193		crtn = CCCrypt(op, encrAlg, options,
194			keyBytes, keyLen, iv,
195			inp, inTextLen,
196			outBuf, outLen, &outLen);
197		if(crtn) {
198			printCCError("CCCrypt", crtn);
199			goto errOut;
200		}
201		*outText = outBuf;
202		*outTextLen = outLen;
203		goto errOut;
204	}
205
206	/* random multi updates */
207	if(ctxSize) {
208		size_t ctxSizeCreated;
209
210		if(askOutSize) {
211			crtn = CCCryptorCreateFromData(op, encrAlg, options,
212				keyBytes, keyLen, iv,
213				ctx, 0 /* ctxSize */,
214				&cryptor, &askedOutSize);
215			if(crtn != kCCBufferTooSmall) {
216				printf("***Did not get kCCBufferTooSmall as expected\n");
217				printCCError("CCCryptorCreateFromData", crtn);
218				crtn = -1;
219				goto errOut;
220			}
221			ctxSize = askedOutSize;
222		}
223		crtn = CCCryptorCreateFromData(op, encrAlg, options,
224			keyBytes, keyLen, iv,
225			ctx, ctxSize, &cryptor, &ctxSizeCreated);
226		if(crtn) {
227			printCCError("CCCryptorCreateFromData", crtn);
228			return crtn;
229		}
230		ctxMarker = ctx + ctxSizeCreated;
231		memset(ctxMarker, MARKER_BYTE, MARKER_LENGTH);
232	}
233	else {
234		crtn = CCCryptorCreate(op, encrAlg, options,
235			keyBytes, keyLen, iv,
236			&cryptor);
237		if(crtn) {
238			printCCError("CCCryptorCreate", crtn);
239			return crtn;
240		}
241	}
242
243	toMove = inTextLen;		/* total to go */
244	outp = outBuf;
245	outBytes = 0;			/* bytes actually produced in outBuf */
246
247	while(toMove) {
248		uint32 thisMoveIn;			/* input to CCryptUpdate() */
249
250		thisMoveIn = genRand(1, toMove);
251		logSize(("###ptext segment len %lu\n", (unsigned long)thisMoveIn));
252		if(askOutSize) {
253			thisOutLen = CCCryptorGetOutputLength(cryptor, thisMoveIn, false);
254		}
255		else {
256			thisOutLen = outLen;
257		}
258		crtn = CCCryptorUpdate(cryptor, inp, thisMoveIn,
259			outp, thisOutLen, &thisMoveOut);
260		if(crtn) {
261			printCCError("CCCryptorUpdate", crtn);
262			goto errOut;
263		}
264		inp			+= thisMoveIn;
265		toMove		-= thisMoveIn;
266		outp		+= thisMoveOut;
267		outLen   	-= thisMoveOut;
268		outBytes	+= thisMoveOut;
269	}
270
271	if(doPadding) {
272		/* Final is not needed if padding is disabled */
273		if(askOutSize) {
274			thisOutLen = CCCryptorGetOutputLength(cryptor, 0, true);
275		}
276		else {
277			thisOutLen = outLen;
278		}
279		crtn = CCCryptorFinal(cryptor, outp, thisOutLen, &thisMoveOut);
280	}
281	else {
282		thisMoveOut = 0;
283		crtn = kCCSuccess;
284	}
285
286	if(crtn) {
287		printCCError("CCCryptorFinal", crtn);
288		goto errOut;
289	}
290
291	outBytes += thisMoveOut;
292	*outText = outBuf;
293	*outTextLen = outBytes;
294	crtn = kCCSuccess;
295
296	for(dex=0; dex<MARKER_LENGTH; dex++) {
297		if(textMarker[dex] != MARKER_BYTE) {
298			printf("***lib scribbled on our textMarker memory (op=%s)!\n",
299				forEncrypt ? "encrypt" : "decrypt");
300			crtn = (CCCryptorStatus)-1;
301		}
302	}
303	if(ctxSize) {
304		for(dex=0; dex<MARKER_LENGTH; dex++) {
305			if(ctxMarker[dex] != MARKER_BYTE) {
306				printf("***lib scribbled on our ctxMarker memory (op=%s)!\n",
307					forEncrypt ? "encrypt" : "decrypt");
308				crtn = (CCCryptorStatus)-1;
309			}
310		}
311	}
312
313errOut:
314	if(crtn) {
315		if(outBuf) {
316			free(outBuf);
317		}
318	}
319	if(cryptor) {
320		CCCryptorRelease(cryptor);
321	}
322	return crtn;
323}
324
325static int doTest(const uint8_t *ptext,
326	size_t ptextLen,
327	CCAlgorithm encrAlg,
328	bool doCbc,
329	bool doPadding,
330	bool nullIV,			/* if CBC, use NULL IV */
331	uint32 keySizeInBytes,
332	bool stagedEncr,
333	bool stagedDecr,
334	bool inPlace,
335	size_t ctxSize,
336	bool askOutSize,
337	bool quiet)
338{
339	uint8_t			keyBytes[MAX_KEY_SIZE];
340	uint8_t			iv[MAX_BLOCK_SIZE];
341	uint8_t			*ivPtrEncrypt;
342	uint8_t			*ivPtrDecrypt;
343	uint8_t			*ctext = NULL;		/* mallocd by doCCCrypt */
344	size_t			ctextLen = 0;
345	uint8_t			*rptext = NULL;		/* mallocd by doCCCrypt */
346	size_t			rptextLen;
347	CCCryptorStatus	crtn;
348	int				rtn = 0;
349
350	/* random key */
351	appGetRandomBytes(keyBytes, keySizeInBytes);
352
353	/* random IV if needed */
354	if(doCbc) {
355		if(nullIV) {
356			memset(iv, 0, MAX_BLOCK_SIZE);
357
358			/* flip a coin, give one side NULL, the other size zeroes */
359			if(genRand(1,2) == 1) {
360				ivPtrEncrypt = NULL;
361				ivPtrDecrypt = iv;
362			}
363			else {
364				ivPtrEncrypt = iv;
365				ivPtrDecrypt = NULL;
366			}
367		}
368		else {
369			appGetRandomBytes(iv, MAX_BLOCK_SIZE);
370			ivPtrEncrypt = iv;
371			ivPtrDecrypt = iv;
372		}
373	}
374	else {
375		ivPtrEncrypt = NULL;
376		ivPtrDecrypt = NULL;
377	}
378
379	crtn = doCCCrypt(true, encrAlg, doCbc, doPadding,
380		keyBytes, keySizeInBytes, ivPtrEncrypt,
381		stagedEncr, inPlace, ctxSize, askOutSize,
382		ptext, ptextLen,
383		&ctext, &ctextLen);
384	if(crtn) {
385		rtn = testError(quiet);
386		if(rtn) {
387			goto abort;
388		}
389	}
390
391	logSize(("###ctext len %lu\n", ctextLen));
392
393	crtn = doCCCrypt(false, encrAlg, doCbc, doPadding,
394		keyBytes, keySizeInBytes, ivPtrDecrypt,
395		stagedDecr, inPlace, ctxSize, askOutSize,
396		ctext, ctextLen,
397		&rptext, &rptextLen);
398	if(crtn) {
399		rtn = testError(quiet);
400		if(rtn) {
401			goto abort;
402		}
403	}
404
405	logSize(("###rptext len %lu\n", rptextLen));
406
407	/* compare ptext, rptext */
408	if(ptextLen != rptextLen) {
409		printf("Ptext length mismatch: expect %lu, got %lu\n", ptextLen, rptextLen);
410		rtn = testError(quiet);
411		if(rtn) {
412			goto abort;
413		}
414	}
415	if(memcmp(ptext, rptext, ptextLen)) {
416		printf("***data miscompare\n");
417		rtn = testError(quiet);
418	}
419abort:
420	if(ctext) {
421		free(ctext);
422	}
423	if(rptext) {
424		free(rptext);
425	}
426	return rtn;
427}
428
429bool isBitSet(unsigned bit, unsigned word)
430{
431	if(bit > 31) {
432		printf("We don't have that many bits\n");
433		exit(1);
434	}
435	unsigned mask = 1 << bit;
436	return (word & mask) ? true : false;
437}
438
439int main(int argc, char **argv)
440{
441	int					arg;
442	char				*argp;
443	unsigned			loop;
444	uint8				*ptext;
445	size_t				ptextLen;
446	bool				stagedEncr;
447	bool				stagedDecr;
448	bool				doPadding;
449	bool				doCbc;
450	bool				nullIV;
451	const char			*algStr;
452	CCAlgorithm			encrAlg;
453	int					i;
454	int					currAlg;		// ALG_xxx
455	uint32				minKeySizeInBytes;
456	uint32				maxKeySizeInBytes;
457	uint32				keySizeInBytes;
458	int					rtn = 0;
459	uint32				blockSize;		// for noPadding case
460	size_t				ctxSize;		// always set per alg
461	size_t				ctxSizeUsed;	// passed to doTest
462	bool				askOutSize;		// inquire output size each op
463
464	/*
465	 * User-spec'd params
466	 */
467	bool		keySizeSpec = false;		// false: use rand key size
468	SymAlg		minAlg = ALG_FIRST;
469	SymAlg		maxAlg = ALG_LAST;
470	unsigned	loops = LOOPS_DEF;
471	bool		verbose = false;
472	size_t		minPtextSize = MIN_DATA_SIZE;
473	size_t		maxPtextSize = MAX_DATA_SIZE;
474	bool		quiet = false;
475	unsigned	pauseInterval = 0;
476	bool		paddingSpec = false;		// true: user calls doPadding, const
477	bool		cbcSpec = false;			// ditto for doCbc
478	bool		stagedSpec = false;			// ditto for stagedEncr and stagedDecr
479	bool		inPlace = false;			// en/decrypt in place for ECB
480	bool		allocCtxSpec = false;		// use allocCtx
481	bool		allocCtx = false;			// allocate context ourself
482
483	for(arg=1; arg<argc; arg++) {
484		argp = argv[arg];
485		switch(argp[0]) {
486			case 'a':
487				if(argp[1] != '=') {
488					usage(argv);
489				}
490				switch(argp[2]) {
491					case 's':
492						minAlg = maxAlg = ALG_ASC;
493						break;
494					case 'd':
495						minAlg = maxAlg = ALG_DES;
496						break;
497					case '3':
498						minAlg = maxAlg = ALG_3DES;
499						break;
500					case '2':
501						minAlg = maxAlg = ALG_RC2;
502						break;
503					case '4':
504						minAlg = maxAlg = ALG_RC4;
505						break;
506					case '5':
507						minAlg = maxAlg = ALG_RC5;
508						break;
509					case 'a':
510						minAlg = maxAlg = ALG_AES_128;
511						break;
512					case 'n':
513						minAlg = maxAlg = ALG_AES_192;
514						break;
515					case 'A':
516						minAlg = maxAlg = ALG_AES_256;
517						break;
518					case 'b':
519						minAlg = maxAlg = ALG_BFISH;
520						break;
521					case 'c':
522						minAlg = maxAlg = ALG_CAST;
523						break;
524					default:
525						usage(argv);
526				}
527				if(maxAlg > ALG_LAST) {
528					/* we left them in the switch but we can't use them */
529					usage(argv);
530				}
531				break;
532		    case 'l':
533				loops = atoi(&argp[2]);
534				break;
535		    case 'n':
536				minPtextSize = atoi(&argp[2]);
537				break;
538		    case 'm':
539				maxPtextSize = atoi(&argp[2]);
540				break;
541		    case 'k':
542		    	minKeySizeInBytes = maxKeySizeInBytes = atoi(&argp[2]);
543		    	keySizeSpec = true;
544				break;
545			case 'x':
546				allocCtxSpec = true;
547				allocCtx = true;
548				break;
549			case 'X':
550				allocCtxSpec = true;
551				allocCtx = false;
552				break;
553		    case 'v':
554		    	verbose = true;
555				break;
556		    case 'q':
557		    	quiet = true;
558				break;
559		    case 'p':
560		    	pauseInterval = atoi(&argp[2]);;
561				break;
562			case 'o':
563				doPadding = false;
564				paddingSpec = true;
565				break;
566			case 'e':
567				doCbc = false;
568				cbcSpec = true;
569				break;
570			case 'E':
571				doCbc = true;
572				cbcSpec = true;
573				break;
574		    case 'u':
575		    	stagedEncr = false;
576		    	stagedDecr = false;
577				stagedSpec = true;
578				break;
579		    case 'U':
580		    	stagedEncr = true;
581		    	stagedDecr = true;
582				stagedSpec = true;
583				break;
584		    case 'h':
585		    default:
586				usage(argv);
587		}
588	}
589	ptext = (uint8 *)malloc(maxPtextSize);
590	if(ptext == NULL) {
591		printf("Insufficient heap space\n");
592		exit(1);
593	}
594	/* ptext length set in test loop */
595
596	printf("Starting ccSymTest; args: ");
597	for(i=1; i<argc; i++) {
598		printf("%s ", argv[i]);
599	}
600	printf("\n");
601
602	if(pauseInterval) {
603		fpurge(stdin);
604		printf("Top of test; hit CR to proceed: ");
605		getchar();
606	}
607
608	for(currAlg=minAlg; currAlg<=maxAlg; currAlg++) {
609		switch(currAlg) {
610			case ALG_DES:
611				encrAlg = kCCAlgorithmDES;
612				blockSize = kCCBlockSizeDES;
613				minKeySizeInBytes = kCCKeySizeDES;
614				maxKeySizeInBytes = minKeySizeInBytes;
615				ctxSize = kCCContextSizeDES;
616				algStr = "DES";
617				break;
618			case ALG_3DES:
619				encrAlg = kCCAlgorithm3DES;
620				blockSize = kCCBlockSize3DES;
621				minKeySizeInBytes = kCCKeySize3DES;
622				maxKeySizeInBytes = minKeySizeInBytes;
623				ctxSize = kCCContextSize3DES;
624				algStr = "3DES";
625				break;
626			case ALG_AES_128:
627				encrAlg = kCCAlgorithmAES128;
628				blockSize = kCCBlockSizeAES128;
629				minKeySizeInBytes = kCCKeySizeAES128;
630				maxKeySizeInBytes = minKeySizeInBytes;
631				ctxSize = kCCContextSizeAES128;
632				algStr = "AES128";
633				break;
634			case ALG_AES_192:
635				encrAlg = kCCAlgorithmAES128;
636				blockSize = kCCBlockSizeAES128;
637				minKeySizeInBytes = kCCKeySizeAES192;
638				maxKeySizeInBytes = minKeySizeInBytes;
639				ctxSize = kCCContextSizeAES128;
640				algStr = "AES192";
641				break;
642			case ALG_AES_256:
643				encrAlg = kCCAlgorithmAES128;
644				blockSize = kCCBlockSizeAES128;
645				minKeySizeInBytes = kCCKeySizeAES256;
646				maxKeySizeInBytes = minKeySizeInBytes;
647				ctxSize = kCCContextSizeAES128;
648				algStr = "AES256";
649				break;
650			case ALG_CAST:
651				encrAlg = kCCAlgorithmCAST;
652				blockSize = kCCBlockSizeCAST;
653				minKeySizeInBytes = kCCKeySizeMinCAST;
654				maxKeySizeInBytes = kCCKeySizeMaxCAST;
655				ctxSize = kCCContextSizeCAST;
656				algStr = "CAST";
657				break;
658			case ALG_RC4:
659				encrAlg = kCCAlgorithmRC4;
660				blockSize = 0;
661				minKeySizeInBytes = kCCKeySizeMinRC4;
662				maxKeySizeInBytes = kCCKeySizeMaxRC4;
663				ctxSize = kCCContextSizeRC4;
664				algStr = "RC4";
665				break;
666			default:
667				printf("***BRRZAP!\n");
668				exit(1);
669		}
670		if(!quiet || verbose) {
671			printf("Testing alg %s\n", algStr);
672		}
673		for(loop=1; ; loop++) {
674			ptextLen = genRand(minPtextSize, maxPtextSize);
675			appGetRandomBytes(ptext, ptextLen);
676
677			/* per-loop settings */
678			if(!keySizeSpec) {
679				if(minKeySizeInBytes == maxKeySizeInBytes) {
680					keySizeInBytes = minKeySizeInBytes;
681				}
682				else {
683					keySizeInBytes = genRand(minKeySizeInBytes, maxKeySizeInBytes);
684				}
685			}
686			if(blockSize == 0) {
687				/* stream cipher */
688				doCbc = false;
689				doPadding = false;
690			}
691			else {
692				if(!cbcSpec) {
693					doCbc = isBitSet(0, loop);
694				}
695				if(!paddingSpec) {
696					doPadding = isBitSet(1, loop);
697				}
698			}
699			if(!doPadding && (blockSize != 0)) {
700				/* align plaintext */
701				ptextLen = (ptextLen / blockSize) * blockSize;
702				if(ptextLen == 0) {
703					ptextLen = blockSize;
704				}
705			}
706			if(!stagedSpec) {
707				stagedEncr = isBitSet(2, loop);
708				stagedDecr = isBitSet(3, loop);
709			}
710			if(doCbc) {
711				nullIV = isBitSet(4, loop);
712			}
713			else {
714				nullIV = false;
715			}
716			inPlace = isBitSet(5, loop);
717			if(allocCtxSpec) {
718				ctxSizeUsed = allocCtx ? ctxSize : 0;
719			}
720			else if(isBitSet(6, loop)) {
721				ctxSizeUsed = ctxSize;
722			}
723			else {
724				ctxSizeUsed = 0;
725			}
726			askOutSize = isBitSet(7, loop);
727			if(!quiet) {
728			   	if(verbose || ((loop % LOOP_NOTIFY) == 0)) {
729					printf("..loop %3d ptextLen %lu keyLen %d cbc=%d padding=%d stagedEncr=%d "
730							"stagedDecr=%d\n",
731						loop, (unsigned long)ptextLen, (int)keySizeInBytes,
732						(int)doCbc, (int)doPadding,
733					 	(int)stagedEncr, (int)stagedDecr);
734					printf("           nullIV %d inPlace %d ctxSize %d askOutSize %d\n",
735						(int)nullIV, (int)inPlace, (int)ctxSizeUsed, (int)askOutSize);
736				}
737			}
738
739			if(doTest(ptext, ptextLen,
740					encrAlg, doCbc, doPadding, nullIV,
741					keySizeInBytes,
742					stagedEncr,	stagedDecr, inPlace, ctxSizeUsed, askOutSize,
743					quiet)) {
744				rtn = 1;
745				break;
746			}
747			if(pauseInterval && ((loop % pauseInterval) == 0)) {
748				char c;
749				fpurge(stdin);
750				printf("Hit CR to proceed, q to abort: ");
751				c = getchar();
752				if(c == 'q') {
753					goto testDone;
754				}
755			}
756			if(loops && (loop == loops)) {
757				break;
758			}
759		}	/* main loop */
760		if(rtn) {
761			break;
762		}
763
764	}	/* for algs */
765
766testDone:
767	if(pauseInterval) {
768		fpurge(stdin);
769		printf("ModuleDetach/Unload complete; hit CR to exit: ");
770		getchar();
771	}
772	if((rtn == 0) && !quiet) {
773		printf("%s test complete\n", argv[0]);
774	}
775	free(ptext);
776	return rtn;
777}
778