1/* Copyright (c) 1998,2003-2005,2008 Apple Inc.
2 *
3 * pbeTest.c - test CSP PBE-style DeriveKey().
4 *
5 * Revision History
6 * ----------------
7 *  15 May 2000 Doug Mitchell
8 *		Ported to X/CDSA2.
9 *  13 Aug 1998	Doug Mitchell at NeXT
10 *		Created.
11 */
12#include <stdlib.h>
13#include <stdio.h>
14#include <time.h>
15#include <string.h>
16#include <Security/cssm.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_PASSWORD_SIZE	64
31#define MAX_SALT_SIZE		32
32#define MIN_ITER_COUNT		1000
33#define MAX_ITER_COUNT		2000
34#define MAX_IV_SIZE			AES_BLOCK_SIZE
35
36/* min values not currently exported by CSP */
37#define APPLE_PBE_MIN_PASSWORD	8
38#define APPLE_PBE_MIN_SALT		8
39
40/* static IV for derive algorithms which don't create one */
41CSSM_DATA staticIv = {MAX_IV_SIZE, (uint8 *)"someIvOrOther..."};
42
43/*
44 * Enumerate algs our own way to allow iteration.
45 */
46typedef unsigned privAlg;
47enum {
48	/* PBE algs */
49	pbe_pbkdf2 = 1,
50	// other unsupported for now
51	pbe_PKCS12 = 1,
52	pbe_MD5,
53	pbe_MD2,
54	pbe_SHA1,
55
56	/* key gen algs */
57	pka_ASC,
58	pka_RC4,
59	pka_DES,
60	pka_RC2,
61	pka_RC5,
62	pka_3DES,
63	pka_AES
64};
65
66#define PBE_ALG_FIRST			pbe_pbkdf2
67#define PBE_ALG_LAST			pbe_pbkdf2
68#define ENCR_ALG_FIRST			pka_ASC
69#define ENCR_ALG_LAST			pka_AES
70#define ENCR_ALG_LAST_EXPORT	pka_RC5
71
72/*
73 * Args passed to each test
74 */
75typedef struct {
76	CSSM_CSP_HANDLE 	cspHand;
77	CSSM_ALGORITHMS		keyAlg;
78	CSSM_ALGORITHMS		encrAlg;
79	uint32				keySizeInBits;
80	uint32				effectiveKeySizeInBits;	// 0 means not used
81	const char 			*keyAlgStr;
82	CSSM_ENCRYPT_MODE	encrMode;
83	CSSM_PADDING		encrPad;
84	CSSM_ALGORITHMS		deriveAlg;
85	const char 			*deriveAlgStr;
86	CSSM_DATA_PTR		ptext;
87	CSSM_DATA_PTR		password;
88	CSSM_DATA_PTR 		salt;
89	uint32 				iterCount;
90	CSSM_BOOL 			useInitVector;		// encrypt needs an IV
91	uint32				ivSize;
92	CSSM_BOOL			genInitVector;		// DeriveKey generates an IV
93	CSSM_BOOL			useRefKey;
94	CSSM_BOOL			quiet;
95} testArgs;
96
97static void usage(char **argv)
98{
99	printf("usage: %s [options]\n", argv[0]);
100	printf("   Options:\n");
101	printf("   l=loops (default=%d; 0=forever)\n", LOOPS_DEF);
102	printf("   e(xport)\n");
103	printf("   r(epeatOnly)\n");
104	printf("   z(ero length password)\n");
105	printf("   p(ause after each loop)\n");
106	printf("   D (CSP/DL; default = bare CSP)\n");
107	printf("   q(uiet)\n");
108	printf("   h(elp)\n");
109	exit(1);
110}
111
112/*
113 * Given a privAlg value, return various associated stuff.
114 */
115static void algInfo(privAlg alg,			// pbe_MD5, etc.
116	CSSM_ALGORITHMS		*cdsaAlg,		// CSSM_ALGID_MD5_PBE, etc. RETURNED
117										//   key alg for key gen algs
118	CSSM_ALGORITHMS		*encrAlg,		// encrypt/decrypt alg for key
119										//   gen algs
120	CSSM_ENCRYPT_MODE	*mode,			// RETURNED
121	CSSM_PADDING 		*padding,		// RETURNED
122	CSSM_BOOL			*useInitVector,	// RETURNED, for encrypt/decrypt
123	uint32				*ivSize,		// RETURNED, in bytes
124	CSSM_BOOL			*genInitVector,	// RETURNED, for deriveKey
125	const char			**algStr)		// RETURNED
126{
127	/* default or irrelevant fields */
128	*mode = CSSM_ALGMODE_NONE;
129	*useInitVector = CSSM_FALSE;
130	*genInitVector = CSSM_FALSE;		// DeriveKey doesn't do this now
131	*padding = CSSM_PADDING_PKCS1;
132	*ivSize = 8;						// thje usual size, if needed
133	*encrAlg = CSSM_ALGID_NONE;
134
135	switch(alg) {
136		case pbe_pbkdf2:
137			*cdsaAlg = CSSM_ALGID_PKCS5_PBKDF2;
138			*algStr = "PBKDF2";
139			return;
140		/* these are not supported */
141		#if 0
142		case pbe_PKCS12:
143			*cdsaAlg = CSSM_ALGID_SHA1_PBE_PKCS12;
144			*algStr = "PKCS12";
145			return;
146		case pbe_MD5:
147			*cdsaAlg = CSSM_ALGID_MD5_PBE;
148			*algStr = "MD5";
149			return;
150		case pbe_MD2:
151			*cdsaAlg = CSSM_ALGID_MD2_PBE;
152			*algStr = "MD2";
153			return;
154		case pbe_SHA1:
155			*cdsaAlg = CSSM_ALGID_SHA1_PBE;
156			*algStr = "SHA1";
157			return;
158		case pka_ASC:
159			*cdsaAlg = CSSM_ALGID_ASC;
160			*algStr = "ASC";
161			return;
162		#endif
163		case pka_DES:
164			*cdsaAlg = *encrAlg = CSSM_ALGID_DES;
165			*useInitVector = CSSM_TRUE;
166			*mode = CSSM_ALGMODE_CBCPadIV8;
167			*algStr = "DES";
168			return;
169		case pka_3DES:
170			*cdsaAlg = CSSM_ALGID_3DES_3KEY;
171			*encrAlg = CSSM_ALGID_3DES_3KEY_EDE;
172			*useInitVector = CSSM_TRUE;
173			*mode = CSSM_ALGMODE_CBCPadIV8;
174			*algStr = "3DES";
175			return;
176		case pka_AES:
177			*cdsaAlg = *encrAlg = CSSM_ALGID_AES;
178			*useInitVector = CSSM_TRUE;
179			*mode = CSSM_ALGMODE_CBCPadIV8;
180			*padding = CSSM_PADDING_PKCS5;
181			*ivSize = AES_BLOCK_SIZE;			// per the default block size
182			*algStr = "AES";
183			return;
184		case pka_RC2:
185			*cdsaAlg = *encrAlg = CSSM_ALGID_RC2;
186			*useInitVector = CSSM_TRUE;
187			*mode = CSSM_ALGMODE_CBCPadIV8;
188			*algStr = "RC2";
189			return;
190		case pka_RC4:
191			*cdsaAlg = *encrAlg = CSSM_ALGID_RC4;
192			/* initVector false */
193			*mode = CSSM_ALGMODE_NONE;
194			*algStr = "RC4";
195			return;
196		case pka_RC5:
197			*cdsaAlg = *encrAlg = CSSM_ALGID_RC5;
198			*algStr = "RC5";
199			*mode = CSSM_ALGMODE_CBCPadIV8;
200			*useInitVector = CSSM_TRUE;
201			return;
202		case pka_ASC:
203			*cdsaAlg = *encrAlg = CSSM_ALGID_ASC;
204			/* initVector false */
205			*algStr = "ASC";
206			*mode = CSSM_ALGMODE_NONE;
207			return;
208		default:
209			printf("BRRZZZT! Update algInfo()!\n");
210			testError(CSSM_TRUE);
211	}
212}
213
214/* a handy "compare two CSSM_DATAs" ditty */
215static CSSM_BOOL compareData(const CSSM_DATA_PTR d1,
216	const CSSM_DATA_PTR d2)
217{
218	if(d1->Length != d2->Length) {
219		return CSSM_FALSE;
220	}
221	if(memcmp(d1->Data, d2->Data, d1->Length)) {
222		return CSSM_FALSE;
223	}
224	return CSSM_TRUE;
225}
226
227/* generate random one-bit byte */
228static uint8 randBit()
229{
230	return 1 << genRand(0, 7);
231}
232
233/*
234 * Writer debug - assertion failure when ctext[1].Data is NULL
235 * but length is nonzero
236 */
237#define SAFE_CTEXT_ARRAY	0
238
239/*
240 * Encrypt ptext using specified key, IV, effectiveKeySizeInBits
241 */
242static int encryptCom(CSSM_CSP_HANDLE cspHand,
243	const char *testName,
244	CSSM_DATA_PTR ptext,
245	CSSM_KEY_PTR key,
246	CSSM_ALGORITHMS alg,
247	CSSM_ENCRYPT_MODE mode,
248	CSSM_PADDING padding,			// CSSM_PADDING_PKCS1, etc.
249	CSSM_DATA_PTR iv,				// may be NULL
250	uint32 effectiveKeySizeInBits,	// may be 0
251	CSSM_DATA_PTR ctext,			// RETURNED
252	CSSM_BOOL quiet)
253{
254	CSSM_CC_HANDLE cryptHand;
255	CSSM_RETURN crtn;
256	CSSM_SIZE bytesEncrypted;
257	CSSM_DATA remData;
258	int rtn;
259	#if 	SAFE_CTEXT_ARRAY
260	CSSM_DATA safeCtext[2];
261	safeCtext[0] = *ctext;
262	safeCtext[1].Data = NULL;
263	safeCtext[1].Length = 10;		// lie, but shouldn't use this!
264	#else
265	//	printf("+++ ctext[0] = %d:0x%x; ctext[1] = %d:0x%x\n",
266	//		ctext[0].Length, ctext[0].Data,
267	//		ctext[1].Length, ctext[1].Data);
268	#endif
269
270	cryptHand = genCryptHandle(cspHand,
271		alg,
272		mode,
273		padding,
274		key,
275		NULL,			// no 2nd key
276		iv,				// InitVector
277		effectiveKeySizeInBits,
278		0);				// rounds
279	if(cryptHand == 0) {
280		return testError(quiet);
281	}
282
283	remData.Data = NULL;
284	remData.Length = 0;
285	crtn = CSSM_EncryptData(cryptHand,
286		ptext,
287		1,
288		#if 	SAFE_CTEXT_ARRAY
289		&safeCtext[0],
290		#else
291		ctext,
292		#endif
293		1,
294		&bytesEncrypted,
295		&remData);
296	#if 	SAFE_CTEXT_ARRAY
297	*ctext = safeCtext[0];
298	#endif
299
300	if(crtn) {
301		printError("CSSM_EncryptData", crtn);
302		rtn = testError(quiet);
303		goto done;
304	}
305	if(remData.Length != 0) {
306		//printf("***WARNING: nonzero remData on encrypt!\n");
307		/* new for CDSA2 - possible remData even if we ask the CSP to
308		 * malloc ctext */
309		ctext->Data = (uint8 *)appRealloc(ctext->Data, bytesEncrypted, NULL);
310		memmove(ctext->Data + ctext->Length,
311			remData.Data,
312			bytesEncrypted - ctext->Length);
313		appFreeCssmData(&remData, CSSM_FALSE);
314	}
315	/* new for CDSA 2 */
316	ctext->Length = bytesEncrypted;
317	rtn = 0;
318done:
319	if(CSSM_DeleteContext(cryptHand)) {
320		printError("CSSM_DeleteContext", 0);
321		rtn = 1;
322	}
323	return rtn;
324}
325
326/*
327 * Decrypt ctext using specified key, IV, effectiveKeySizeInBits
328 */
329static int decryptCom(CSSM_CSP_HANDLE cspHand,
330	const char *testName,
331	CSSM_DATA_PTR ctext,
332	CSSM_KEY_PTR key,
333	CSSM_ALGORITHMS alg,
334	CSSM_ENCRYPT_MODE mode,
335	CSSM_PADDING padding,
336	CSSM_DATA_PTR iv,				// may be NULL
337	uint32 effectiveKeySizeInBits,	// may be 0
338	CSSM_DATA_PTR ptext,			// RETURNED
339	CSSM_BOOL quiet)
340{
341	CSSM_CC_HANDLE cryptHand;
342	CSSM_RETURN crtn;
343	CSSM_SIZE bytesDecrypted;
344	CSSM_DATA remData;
345	int rtn;
346
347	cryptHand = genCryptHandle(cspHand,
348		alg,
349		mode,
350		padding,
351		key,
352		NULL,			// no 2nd key
353		iv,				// InitVector
354		effectiveKeySizeInBits,
355		0);				// rounds
356	if(cryptHand == 0) {
357		return testError(quiet);
358	}
359	remData.Data = NULL;
360	remData.Length = 0;
361	crtn = CSSM_DecryptData(cryptHand,
362		ctext,
363		1,
364		ptext,
365		1,
366		&bytesDecrypted,
367		&remData);
368	if(crtn) {
369		printError("CSSM_DecryptData", crtn);
370		rtn = testError(quiet);
371		goto done;
372	}
373	if(remData.Length != 0) {
374		//printf("***WARNING: nonzero remData on decrypt!\n");
375		/* new for CDSA2 - possible remData even if we ask the CSP to
376		 * malloc ptext */
377		ptext->Data = (uint8 *)appRealloc(ptext->Data, bytesDecrypted, NULL);
378		memmove(ptext->Data + ptext->Length,
379			remData.Data,
380			bytesDecrypted - ptext->Length);
381		appFreeCssmData(&remData, CSSM_FALSE);
382	}
383	/* new for CDSA 2 */
384	ptext->Length = bytesDecrypted;
385	rtn = 0;
386done:
387	if(CSSM_DeleteContext(cryptHand)) {
388		printError("CSSM_DeleteContext", 0);
389		rtn = 1;
390	}
391	return rtn;
392}
393
394/*
395 * Common test portion
396 *   encrypt ptext with key1, iv1
397 *   encrypt ptext with key2, iv2
398 *	 compare 2 ctexts; expect failure;
399 */
400
401#define TRAP_WRITER_ERR	1
402
403static int testCommon(CSSM_CSP_HANDLE cspHand,
404	const char *testName,
405	CSSM_ALGORITHMS encrAlg,
406	CSSM_ENCRYPT_MODE encrMode,
407	CSSM_PADDING encrPad,
408	uint32 effectiveKeySizeInBits,
409	CSSM_DATA_PTR ptext,
410	CSSM_KEY_PTR key1,
411	CSSM_DATA_PTR iv1,
412	CSSM_KEY_PTR key2,
413	CSSM_DATA_PTR iv2,
414	CSSM_BOOL quiet)
415{
416	CSSM_DATA		ctext1;
417	CSSM_DATA		ctext2;
418	ctext1.Data = NULL;
419	ctext1.Length = 0;
420	ctext2.Data = NULL;
421	ctext2.Length = 0;
422	if(encryptCom(cspHand,
423			testName,
424			ptext,
425			key1,
426			encrAlg,
427			encrMode,
428			encrPad,
429			iv1,
430			effectiveKeySizeInBits,
431			&ctext1,
432			quiet)) {
433		return 1;
434	}
435	#if	TRAP_WRITER_ERR
436	if(ctext2.Data != NULL){
437		printf("Hey! encryptCom(ptext, ctext1 modified ctext2!\n");
438		if(testError(quiet)) {
439			return 1;
440		}
441	}
442	#endif
443	if(encryptCom(cspHand,
444			testName,
445			ptext,
446			key2,
447			encrAlg,
448			encrMode,
449			encrPad,
450			iv2,
451			effectiveKeySizeInBits,
452			&ctext2,
453			quiet)) {
454		return 1;
455	}
456	if(compareData(&ctext1, &ctext2)) {
457		printf("***%s: Unexpected Data compare!\n", testName);
458		return testError(quiet);
459	}
460	appFreeCssmData(&ctext1, CSSM_FALSE);
461	appFreeCssmData(&ctext2, CSSM_FALSE);
462	return 0;
463}
464
465/**
466 ** inidividual tests.
467 **/
468#define KEY_LABEL1		"noLabel1"
469#define KEY_LABEL2		"noLabel2"
470#define KEY_LABEL_LEN	strlen(KEY_LABEL1)
471#define REPEAT_ON_ERROR	1
472
473/* test repeatability - the only test here which actually decrypts */
474static int repeatTest(testArgs *targs)
475{
476	/*
477	generate two keys with same params;
478	encrypt ptext with key1;
479	decrypt ctext with key2;
480	compare; expect success;
481	*/
482	CSSM_KEY_PTR	key1;
483	CSSM_KEY_PTR	key2;
484	CSSM_DATA		iv1;
485	CSSM_DATA		iv2;
486	CSSM_DATA_PTR	ivp1;
487	CSSM_DATA_PTR	ivp2;
488	CSSM_DATA		ctext;
489	CSSM_DATA		rptext;
490	CSSM_BOOL		gotErr = CSSM_FALSE;
491
492	if(targs->useInitVector) {
493		if(targs->genInitVector) {
494			ivp1 = &iv1;
495			ivp2 = &iv2;
496		}
497		else {
498			staticIv.Length = targs->ivSize;
499			ivp1 = ivp2 = &staticIv;
500		}
501	}
502	else {
503		ivp1 = ivp2 = NULL;
504	}
505	/* these need to be init'd regardless */
506	iv1.Data = NULL;
507	iv1.Length = 0;
508	iv2.Data = NULL;
509	iv2.Length = 0;
510	ctext.Data = NULL;
511	ctext.Length = 0;
512	rptext.Data = NULL;
513	rptext.Length = 0;
514repeatDerive:
515	key1 = cspDeriveKey(targs->cspHand,
516		targs->deriveAlg,
517		targs->keyAlg,
518		KEY_LABEL1,
519		KEY_LABEL_LEN,
520		CSSM_KEYUSE_ENCRYPT,
521		targs->keySizeInBits,
522		targs->useRefKey,
523		targs->password,
524		targs->salt,
525		targs->iterCount,
526		&iv1);
527	if(key1 == NULL) {
528		return testError(targs->quiet);
529	}
530	key2 = cspDeriveKey(targs->cspHand,
531		targs->deriveAlg,
532		targs->keyAlg,
533		KEY_LABEL2,
534		KEY_LABEL_LEN,
535		CSSM_KEYUSE_DECRYPT,
536		targs->keySizeInBits,
537		targs->useRefKey,
538		targs->password,
539		targs->salt,
540		targs->iterCount,
541		&iv2);
542	if(key2 == NULL) {
543		return testError(targs->quiet);
544	}
545repeatEnc:
546	if(encryptCom(targs->cspHand,
547			"repeatTest",
548			targs->ptext,
549			key1,
550			targs->encrAlg,
551			targs->encrMode,
552			targs->encrPad,
553			ivp1,
554			targs->effectiveKeySizeInBits,
555			&ctext,
556			targs->quiet)) {
557		return 1;
558	}
559	if(decryptCom(targs->cspHand,
560			"repeatTest",
561			&ctext,
562			key2,
563			targs->encrAlg,
564			targs->encrMode,
565			targs->encrPad,
566			ivp2,
567			targs->effectiveKeySizeInBits,
568			&rptext,
569			targs->quiet)) {
570		return 1;
571	}
572	if(gotErr || !compareData(targs->ptext, &rptext)) {
573		printf("***Data miscompare in repeatTest\n");
574		if(REPEAT_ON_ERROR) {
575			char str;
576
577			gotErr = CSSM_TRUE;
578			fpurge(stdin);
579			printf("Repeat enc/dec (r), repeat derive (d), continue (c), abort (any)? ");
580			str = getchar();
581			switch(str) {
582				case 'r':
583					appFreeCssmData(&ctext, CSSM_FALSE);
584					appFreeCssmData(&rptext, CSSM_FALSE);
585					goto repeatEnc;
586				case 'd':
587					appFreeCssmData(&ctext, CSSM_FALSE);
588					appFreeCssmData(&rptext, CSSM_FALSE);
589					appFreeCssmData(&iv1, CSSM_FALSE);
590					appFreeCssmData(&iv2, CSSM_FALSE);
591					cspFreeKey(targs->cspHand, key1);
592					cspFreeKey(targs->cspHand, key2);
593					goto repeatDerive;
594				case 'c':
595					break;
596				default:
597					return 1;
598			}
599		}
600		else {
601			return testError(targs->quiet);
602		}
603	}
604	appFreeCssmData(&ctext, CSSM_FALSE);
605	appFreeCssmData(&rptext, CSSM_FALSE);
606	appFreeCssmData(&iv1, CSSM_FALSE);
607	appFreeCssmData(&iv2, CSSM_FALSE);
608	cspFreeKey(targs->cspHand, key1);
609	cspFreeKey(targs->cspHand, key2);
610	CSSM_FREE(key1);
611	CSSM_FREE(key2);
612	return 0;
613}
614
615/* ensure iterCount alters key */
616static int iterTest(testArgs *targs)
617{
618	/*
619	generate key1(iterCount), key2(iterCount+1);
620	encrypt ptext with key1;
621	encrypt ptext with key2;
622	compare 2 ctexts; expect failure;
623	*/
624	CSSM_KEY_PTR	key1;
625	CSSM_KEY_PTR	key2;
626	CSSM_DATA		iv1;
627	CSSM_DATA		iv2;
628	CSSM_DATA_PTR	ivp1;
629	CSSM_DATA_PTR	ivp2;
630	if(targs->useInitVector) {
631		if(targs->genInitVector) {
632			ivp1 = &iv1;
633			ivp2 = &iv2;
634		}
635		else {
636			staticIv.Length = targs->ivSize;
637			ivp1 = ivp2 = &staticIv;
638		}
639	}
640	else {
641		ivp1 = ivp2 = NULL;
642	}
643	/* these need to be init'd regardless */
644	iv1.Data = NULL;
645	iv1.Length = 0;
646	iv2.Data = NULL;
647	iv2.Length = 0;
648	key1 = cspDeriveKey(targs->cspHand,
649		targs->deriveAlg,
650		targs->keyAlg,
651		KEY_LABEL1,
652		KEY_LABEL_LEN,
653		CSSM_KEYUSE_ENCRYPT,
654		targs->keySizeInBits,
655		targs->useRefKey,
656		targs->password,
657		targs->salt,
658		targs->iterCount,
659		&iv1);
660	if(key1 == NULL) {
661		return testError(targs->quiet);
662	}
663	key2 = cspDeriveKey(targs->cspHand,
664		targs->deriveAlg,
665		targs->keyAlg,
666		KEY_LABEL2,
667		KEY_LABEL_LEN,
668		CSSM_KEYUSE_ENCRYPT,
669		targs->keySizeInBits,
670		targs->useRefKey,
671		targs->password,
672		targs->salt,
673		targs->iterCount + 1,		// the changed param
674		&iv2);
675	if(key2 == NULL) {
676		return testError(targs->quiet);
677	}
678	if(testCommon(targs->cspHand,
679				"iterTest",
680				targs->encrAlg,
681				targs->encrMode,
682				targs->encrPad,
683				targs->effectiveKeySizeInBits,
684				targs->ptext,
685			 	key1,
686				ivp1,
687				key2,
688				ivp2,
689				targs->quiet)) {
690		return 1;
691	}
692	appFreeCssmData(&iv1, CSSM_FALSE);
693	appFreeCssmData(&iv2, CSSM_FALSE);
694	cspFreeKey(targs->cspHand, key1);
695	cspFreeKey(targs->cspHand, key2);
696	CSSM_FREE(key1);
697	CSSM_FREE(key2);
698	return 0;
699}
700
701/* ensure password alters key */
702static int passwordTest(testArgs *targs)
703{
704	/*
705	generate key1(password), key2(munged password);
706	encrypt ptext with key1;
707	encrypt ptext with key2;
708	compare 2 ctexts; expect failure;
709	*/
710	CSSM_KEY_PTR	key1;
711	CSSM_KEY_PTR	key2;
712	CSSM_DATA		iv1;
713	CSSM_DATA		iv2;
714	CSSM_DATA_PTR	ivp1;
715	CSSM_DATA_PTR	ivp2;
716	uint32			mungeDex;
717	uint32			mungeBits;
718	if(targs->useInitVector) {
719		if(targs->genInitVector) {
720			ivp1 = &iv1;
721			ivp2 = &iv2;
722		}
723		else {
724			staticIv.Length = targs->ivSize;
725			ivp1 = ivp2 = &staticIv;
726		}
727	}
728	else {
729		ivp1 = ivp2 = NULL;
730	}
731	/* these need to be init'd regardless */
732	iv1.Data = NULL;
733	iv1.Length = 0;
734	iv2.Data = NULL;
735	iv2.Length = 0;
736	key1 = cspDeriveKey(targs->cspHand,
737		targs->deriveAlg,
738		targs->keyAlg,
739		KEY_LABEL1,
740		KEY_LABEL_LEN,
741		CSSM_KEYUSE_ENCRYPT,
742		targs->keySizeInBits,
743		targs->useRefKey,
744		targs->password,
745		targs->salt,
746		targs->iterCount,
747		&iv1);
748	if(key1 == NULL) {
749		return testError(targs->quiet);
750	}
751	/* munge password */
752	mungeDex = genRand(0, targs->password->Length - 1);
753	mungeBits = randBit();
754	targs->password->Data[mungeDex] ^= mungeBits;
755	key2 = cspDeriveKey(targs->cspHand,
756		targs->deriveAlg,
757		targs->keyAlg,
758		KEY_LABEL2,
759		KEY_LABEL_LEN,
760		CSSM_KEYUSE_ENCRYPT,
761		targs->keySizeInBits,
762		targs->useRefKey,
763		targs->password,			// the changed param
764		targs->salt,
765		targs->iterCount,
766		&iv2);
767	if(key2 == NULL) {
768		return testError(targs->quiet);
769	}
770	if(testCommon(targs->cspHand,
771				"passwordTest",
772				targs->encrAlg,
773				targs->encrMode,
774				targs->encrPad,
775				targs->effectiveKeySizeInBits,
776				targs->ptext,
777			 	key1,
778				ivp1,
779				key2,
780				ivp2,
781				targs->quiet)) {
782		return 1;
783	}
784	/* restore  */
785	targs->password->Data[mungeDex] ^= mungeBits;
786	appFreeCssmData(&iv1, CSSM_FALSE);
787	appFreeCssmData(&iv2, CSSM_FALSE);
788	cspFreeKey(targs->cspHand, key1);
789	cspFreeKey(targs->cspHand, key2);
790	CSSM_FREE(key1);
791	CSSM_FREE(key2);
792	return 0;
793}
794
795/* ensure salt alters key */
796static int saltTest(testArgs *targs)
797{
798	/*
799	generate key1(seed), key2(munged seed);
800	encrypt ptext with key1;
801	encrypt ptext with key2;
802	compare 2 ctexts; expect failure;
803	*/
804	CSSM_KEY_PTR	key1;
805	CSSM_KEY_PTR	key2;
806	CSSM_DATA		iv1;
807	CSSM_DATA		iv2;
808	CSSM_DATA_PTR	ivp1;
809	CSSM_DATA_PTR	ivp2;
810	uint32			mungeDex;
811	uint32			mungeBits;
812	if(targs->useInitVector) {
813		if(targs->genInitVector) {
814			ivp1 = &iv1;
815			ivp2 = &iv2;
816		}
817		else {
818			staticIv.Length = targs->ivSize;
819			ivp1 = ivp2 = &staticIv;
820		}
821	}
822	else {
823		ivp1 = ivp2 = NULL;
824	}
825	/* these need to be init'd regardless */
826	iv1.Data = NULL;
827	iv1.Length = 0;
828	iv2.Data = NULL;
829	iv2.Length = 0;
830	key1 = cspDeriveKey(targs->cspHand,
831		targs->deriveAlg,
832		targs->keyAlg,
833		KEY_LABEL1,
834		KEY_LABEL_LEN,
835		CSSM_KEYUSE_ENCRYPT,
836		targs->keySizeInBits,
837		targs->useRefKey,
838		targs->password,
839		targs->salt,
840		targs->iterCount,
841		&iv1);
842	if(key1 == NULL) {
843		return testError(targs->quiet);
844	}
845	/* munge salt */
846	mungeDex = genRand(0, targs->salt->Length - 1);
847	mungeBits = randBit();
848	targs->salt->Data[mungeDex] ^= mungeBits;
849	key2 = cspDeriveKey(targs->cspHand,
850		targs->deriveAlg,
851		targs->keyAlg,
852		KEY_LABEL2,
853		KEY_LABEL_LEN,
854		CSSM_KEYUSE_ENCRYPT,
855		targs->keySizeInBits,
856		targs->useRefKey,
857		targs->password,
858		targs->salt,				// the changed param
859		targs->iterCount,
860		&iv2);
861	if(key2 == NULL) {
862		return testError(targs->quiet);
863	}
864	if(testCommon(targs->cspHand,
865				"saltTest",
866				targs->encrAlg,
867				targs->encrMode,
868				targs->encrPad,
869				targs->effectiveKeySizeInBits,
870				targs->ptext,
871			 	key1,
872				ivp1,
873				key2,
874				ivp2,
875				targs->quiet)) {
876		return 1;
877	}
878	/* restore  */
879	targs->salt->Data[mungeDex] ^= mungeBits;
880	appFreeCssmData(&iv1, CSSM_FALSE);
881	appFreeCssmData(&iv2, CSSM_FALSE);
882	cspFreeKey(targs->cspHand, key1);
883	cspFreeKey(targs->cspHand, key2);
884	CSSM_FREE(key1);
885	CSSM_FREE(key2);
886	return 0;
887}
888
889/* ensure initVector alters ctext. This isn't testing PBE per se, but
890 * it's a handy place to verify this function. */
891static int initVectTest(testArgs *targs)
892{
893	/*
894	generate key1;
895	encrypt ptext with key1 and initVector;
896	encrypt ptext with key1 and munged initVector;
897	compare 2 ctexts; expect failure;
898	*/
899	CSSM_KEY_PTR	key1;
900	CSSM_DATA		iv1;
901	CSSM_DATA		iv2;
902	uint32			mungeDex;
903	uint32			mungeBits;
904
905	if(targs->genInitVector) {
906		iv1.Data = NULL;
907		iv1.Length = 0;
908	}
909	else  {
910		iv1 = staticIv;
911	}
912	key1 = cspDeriveKey(targs->cspHand,
913		targs->deriveAlg,
914		targs->keyAlg,
915		KEY_LABEL1,
916		KEY_LABEL_LEN,
917		CSSM_KEYUSE_ENCRYPT,
918		targs->keySizeInBits,
919		targs->useRefKey,
920		targs->password,
921		targs->salt,
922		targs->iterCount,
923		&iv1);
924	if(key1 == NULL) {
925		return testError(targs->quiet);
926	}
927
928	/* get munged copy of iv */
929	iv2.Data = (uint8 *)CSSM_MALLOC(iv1.Length);
930	iv2.Length = iv1.Length;
931	memmove(iv2.Data, iv1.Data, iv1.Length);
932	mungeDex = genRand(0, iv1.Length - 1);
933	mungeBits = randBit();
934	iv2.Data[mungeDex] ^= mungeBits;
935	if(testCommon(targs->cspHand,
936				"initVectTest",
937				targs->encrAlg,
938				targs->encrMode,
939				targs->encrPad,
940				targs->effectiveKeySizeInBits,
941				targs->ptext,
942			 	key1,
943				&iv1,
944				key1,
945				&iv2,	// the changed param
946				targs->quiet)) {
947		return 1;
948	}
949	if(targs->genInitVector) {
950		appFreeCssmData(&iv1, CSSM_FALSE);
951	}
952	appFreeCssmData(&iv2, CSSM_FALSE);
953	cspFreeKey(targs->cspHand, key1);
954	CSSM_FREE(key1);
955	return 0;
956}
957
958#if 0
959/* only one algorithm supported */
960/* ensure deriveAlg alters key */
961static int deriveAlgTest(testArgs *targs)
962{
963	/*
964	generate key1(deriveAlg), key2(some other deriveAlg);
965	encrypt ptext with key1;
966	encrypt ptext with key2;
967	compare 2 ctexts; expect failure;
968	*/
969	CSSM_KEY_PTR    key1;
970	CSSM_KEY_PTR    key2;
971	CSSM_DATA       iv1;
972	CSSM_DATA       iv2;
973	CSSM_DATA_PTR   ivp1;
974	CSSM_DATA_PTR   ivp2;
975	uint32          mungeAlg;
976
977	if(targs->useInitVector) {
978		if(targs->genInitVector) {
979			ivp1 = &iv1;
980			ivp2 = &iv2;
981		}
982		else {
983			staticIv.Length = targs->ivSize;
984			ivp1 = ivp2 = &staticIv;
985		}
986	}
987	else {
988		ivp1 = ivp2 = NULL;
989	}
990
991	/* these need to be init'd regardless */
992	iv1.Data = NULL;
993	iv1.Length = 0;
994	iv2.Data = NULL;
995	iv2.Length = 0;
996	key1 = cspDeriveKey(targs->cspHand,
997		targs->deriveAlg,
998		targs->keyAlg,
999		KEY_LABEL1,
1000		KEY_LABEL_LEN,
1001		CSSM_KEYUSE_ENCRYPT,
1002		targs->keySizeInBits,
1003		targs->useRefKey,
1004		targs->password,
1005		targs->salt,
1006		targs->iterCount,
1007		&iv1);
1008	if(key1 == NULL) {
1009		return testError(quiet);
1010	}
1011
1012	/* munge deriveAlg */
1013	switch(targs->deriveAlg) {
1014		case CSSM_ALGID_MD5_PBE:
1015			mungeAlg = CSSM_ALGID_MD2_PBE;
1016			break;
1017		case CSSM_ALGID_MD2_PBE:
1018			mungeAlg = CSSM_ALGID_SHA1_PBE;
1019			break;
1020		case CSSM_ALGID_SHA1_PBE:
1021			mungeAlg = CSSM_ALGID_SHA1_PBE_PKCS12;
1022			break;
1023		case CSSM_ALGID_SHA1_PBE_PKCS12:
1024			mungeAlg = CSSM_ALGID_MD5_PBE;
1025			break;
1026		default:
1027			printf("BRRRZZZT! Update deriveAlgTest()!\n");
1028			return testError(quiet);
1029	}
1030	key2 = cspDeriveKey(targs->cspHand,
1031		mungeAlg,                               // the changed param
1032		targs->keyAlg,
1033		KEY_LABEL2,
1034		KEY_LABEL_LEN,
1035		CSSM_KEYUSE_ENCRYPT,
1036		targs->keySizeInBits,
1037		targs->useRefKey,
1038		targs->password,                        // the changed param
1039		targs->salt,
1040		targs->iterCount,
1041		&iv2);
1042	if(key2 == NULL) {
1043		return testError(quiet);
1044	}
1045	if(testCommon(targs->cspHand,
1046			"deriveAlgTest",
1047			targs->encrAlg,
1048			targs->encrMode,
1049			targs->encrPad,
1050			targs->effectiveKeySizeInBits,
1051			targs->ptext,
1052			key1,
1053			ivp1,
1054			key2,
1055			ivp2,
1056			targs->quiet)) {
1057		return 1;
1058	}
1059	appFreeCssmData(&iv1, CSSM_FALSE);
1060	appFreeCssmData(&iv2, CSSM_FALSE);
1061	cspFreeKey(targs->cspHand, key1);
1062	cspFreeKey(targs->cspHand, key2);
1063	CSSM_FREE(key1);
1064	CSSM_FREE(key2);
1065	return 0;
1066}
1067#endif
1068
1069int main(int argc, char **argv)
1070{
1071	int					arg;
1072	char				*argp;
1073	unsigned			loop;
1074	CSSM_DATA			ptext;
1075	testArgs			targs;
1076	CSSM_DATA			pwd;
1077	CSSM_DATA			salt;
1078	privAlg				pbeAlg;
1079	privAlg				encrAlg;
1080	privAlg				lastEncrAlg;
1081	int 				rtn = 0;
1082	CSSM_BOOL 			fooBool;
1083	CSSM_BOOL			refKeysOnly = CSSM_FALSE;
1084	int					i;
1085
1086	/*
1087	 * User-spec'd params
1088	 */
1089	unsigned	loops = LOOPS_DEF;
1090	CSSM_BOOL	quiet = CSSM_FALSE;
1091	CSSM_BOOL	doPause = CSSM_FALSE;
1092	CSSM_BOOL	doExport = CSSM_FALSE;
1093	CSSM_BOOL	repeatOnly = CSSM_FALSE;
1094	CSSM_BOOL	bareCsp = CSSM_TRUE;
1095	CSSM_BOOL	zeroLenPassword = CSSM_FALSE;
1096
1097	#if	macintosh
1098	argc = ccommand(&argv);
1099	#endif
1100	for(arg=1; arg<argc; arg++) {
1101		argp = argv[arg];
1102		switch(argp[0]) {
1103		    case 'l':
1104				loops = atoi(&argp[2]);
1105				break;
1106		    case 'q':
1107		    	quiet = CSSM_TRUE;
1108				break;
1109			case 'D':
1110				bareCsp = CSSM_FALSE;
1111				#if CSPDL_ALL_KEYS_ARE_REF
1112				refKeysOnly = CSSM_TRUE;
1113				#endif
1114				break;
1115		    case 'p':
1116		    	doPause = CSSM_TRUE;
1117				break;
1118			case 'e':
1119				doExport = CSSM_TRUE;
1120				break;
1121			case 'r':
1122				repeatOnly = CSSM_TRUE;
1123				break;
1124			case 'z':
1125				zeroLenPassword = CSSM_TRUE;
1126				break;
1127		    case 'h':
1128		    default:
1129				usage(argv);
1130		}
1131	}
1132
1133	/* statically allocate ptext, password and seed; data and length
1134	 * change in test loop */
1135	pwd.Data = (uint8 *)CSSM_MALLOC(MAX_PASSWORD_SIZE);
1136	ptext.Data = (uint8 *)CSSM_MALLOC(MAX_PTEXT_SIZE);
1137	salt.Data = (uint8 *)CSSM_MALLOC(MAX_SALT_SIZE);
1138	printf("Starting pbeTest; args: ");
1139	for(i=1; i<argc; i++) {
1140		printf("%s ", argv[i]);
1141	}
1142	printf("\n");
1143	targs.cspHand = cspDlDbStartup(bareCsp, NULL);
1144	if(targs.cspHand == 0) {
1145		exit(1);
1146	}
1147	targs.ptext 	= &ptext;
1148	targs.password 	= &pwd;
1149	targs.salt 		= &salt;
1150	targs.quiet     = quiet;
1151	if(doExport) {
1152		lastEncrAlg = ENCR_ALG_LAST_EXPORT;
1153	}
1154	else {
1155		lastEncrAlg = ENCR_ALG_LAST;
1156	}
1157	for(loop=1; ; loop++) {
1158		if(!quiet) {
1159			printf("...loop %d\n", loop);
1160		}
1161		/* change once per outer loop */
1162		simpleGenData(&ptext, MIN_PTEXT_SIZE, MAX_PTEXT_SIZE);
1163		if(zeroLenPassword) {
1164			pwd.Length = 0;	// fixed
1165		}
1166		else {
1167			simpleGenData(&pwd, APPLE_PBE_MIN_PASSWORD, MAX_PASSWORD_SIZE);
1168		}
1169		simpleGenData(&salt, APPLE_PBE_MIN_SALT, MAX_SALT_SIZE);
1170		targs.iterCount = genRand(MIN_ITER_COUNT, MAX_ITER_COUNT);
1171		if(refKeysOnly) {
1172			targs.useRefKey = CSSM_TRUE;
1173		}
1174		else {
1175			targs.useRefKey = (loop & 1) ? CSSM_FALSE : CSSM_TRUE;
1176		}
1177
1178		for(encrAlg=ENCR_ALG_FIRST; encrAlg<=lastEncrAlg; encrAlg++) {
1179			/* Cook up encryption-related args */
1180			algInfo(encrAlg,
1181				&targs.keyAlg,
1182				&targs.encrAlg,
1183				&targs.encrMode,
1184				&targs.encrPad,
1185				&targs.useInitVector,
1186				&targs.ivSize,
1187				&fooBool,				// genInitVector
1188				&targs.keyAlgStr);
1189			/* random key size */
1190			targs.effectiveKeySizeInBits = randKeySizeBits(targs.keyAlg, OT_Encrypt);
1191			targs.keySizeInBits = (targs.effectiveKeySizeInBits + 7) & ~7;
1192			if(targs.keySizeInBits == targs.effectiveKeySizeInBits) {
1193				/* same size, ignore effective */
1194				targs.effectiveKeySizeInBits = 0;
1195			}
1196			if(!quiet) {
1197				printf("   ...Encrypt alg %s keySizeInBits %u effectKeySize %u\n",
1198					targs.keyAlgStr, (unsigned)targs.keySizeInBits,
1199					(unsigned)targs.effectiveKeySizeInBits);
1200			}
1201			for(pbeAlg=PBE_ALG_FIRST; pbeAlg<=PBE_ALG_LAST; pbeAlg++) {
1202				/* Cook up pbe-related args */
1203				uint32 foo;
1204				algInfo(pbeAlg,
1205					&targs.deriveAlg,
1206					&foo, 			// encrAlg
1207					&foo,			// mode
1208					&foo,
1209					&fooBool,		// useInitVector
1210					&foo,			// ivSize
1211					&targs.genInitVector,
1212					&targs.deriveAlgStr);
1213				if(!quiet) {
1214					printf("      ...PBE alg %s\n", targs.deriveAlgStr);
1215				}
1216				/* grind thru the tests */
1217				if(repeatTest(&targs)) {
1218					rtn = 1;
1219					goto testDone;
1220				}
1221				if(repeatOnly) {
1222					continue;
1223				}
1224				if(iterTest(&targs)) {
1225					rtn = 1;
1226					goto testDone;
1227				}
1228				#if 0
1229				// not supported yet
1230				if(deriveAlgTest(&targs)) {
1231					rtn = 1;
1232					goto testDone;
1233				}
1234				#endif
1235				if(!zeroLenPassword) {
1236					/* won't work with zero length password */
1237					if(passwordTest(&targs)) {
1238						rtn = 1;
1239						goto testDone;
1240					}
1241				}
1242				if(saltTest(&targs)) {
1243					rtn = 1;
1244					goto testDone;
1245				}
1246				if(targs.useInitVector) {
1247					if(initVectTest(&targs)) {
1248						rtn = 1;
1249						goto testDone;
1250					}
1251				}
1252			} /* for pbeAlg */
1253		} /* for encrAlg */
1254		if(doPause) {
1255			if(testError(quiet)) {
1256				break;
1257			}
1258		}
1259		if(loops && (loop == loops)) {
1260			break;
1261		}
1262	} /* for loop */
1263
1264testDone:
1265	CSSM_ModuleDetach(targs.cspHand);
1266	if(!quiet && (rtn == 0)) {
1267		printf("%s test complete\n", argv[0]);
1268	}
1269	return rtn;
1270}
1271