1/*
2 * hashCompat.c - test compatibilty of two different implementations of a
3 * various digest algorithms - one in the standard AppleCSP, one in BSAFE.
4 *
5 * Written by Doug Mitchell.
6 */
7
8#include <stdlib.h>
9#include <stdio.h>
10#include <time.h>
11#include <Security/cssm.h>
12#include <Security/cssmapple.h>
13#include "cspwrap.h"
14#include "common.h"
15#include "bsafeUtils.h"
16#include <string.h>
17
18/*
19 * Defaults.
20 */
21#define LOOPS_DEF		200
22#define MIN_EXP			2		/* for data size 10**exp */
23#define DEFAULT_MAX_EXP	4
24#define MAX_EXP			5
25
26#define MAX_DATA_SIZE	(100000 + 100)		/* bytes */
27#define LOOP_NOTIFY		20
28
29/*
30 * Enumerate algs our own way to allow iteration.
31 */
32enum {
33	ALG_SHA1	= 1,
34	ALG_MD5,
35	ALG_MD2
36};
37
38#define ALG_FIRST			ALG_SHA1
39#define ALG_LAST			ALG_MD2
40
41static void usage(char **argv)
42{
43	printf("usage: %s [options]\n", argv[0]);
44	printf("   Options:\n");
45	printf("   a=algorithm (s=SHA1; 5=MD5; 2=MD2; default=all\n");
46	printf("   l=loops (default=%d; 0=forever)\n", LOOPS_DEF);
47	printf("   n=minExp (default=%d)\n", MIN_EXP);
48	printf("   x=maxExp (default=%d, max=%d)\n", DEFAULT_MAX_EXP, MAX_EXP);
49	printf("   p=pauseInterval (default=0, no pause)\n");
50	printf("   D (CSP/DL; default = bare CSP)\n");
51	printf("   v(erbose)\n");
52	printf("   q(uiet)\n");
53	printf("   h(elp)\n");
54	exit(1);
55}
56
57/*
58 * generate digest using reference BSAFE.
59 */
60static CSSM_RETURN genDigestBSAFE(
61	CSSM_ALGORITHMS		hashAlg,
62	const CSSM_DATA		*inText,
63	CSSM_DATA_PTR 		outText)			// mallocd and returned
64{
65	CSSM_RETURN crtn;
66
67	crtn = buGenDigest(hashAlg,
68		inText,
69		outText);
70	return crtn;
71}
72
73/*
74 * Generate digest using CSP.
75 */
76static CSSM_RETURN genDigestCSSM(
77	CSSM_CSP_HANDLE		cspHand,
78	CSSM_ALGORITHMS		hashAlg,
79	const CSSM_DATA		*inText,
80	CSSM_DATA_PTR 		outText)			// mallocd and returned if doGen
81{
82
83	outText->Data = NULL;
84	outText->Length = 0;
85	return cspStagedDigest(cspHand,
86		hashAlg,
87		CSSM_TRUE,		// mallocDigest
88		CSSM_TRUE,		// multiUpdates
89		inText,
90		outText);
91}
92
93#define LOG_FREQ	20
94
95static int doTest(CSSM_CSP_HANDLE cspHand,
96	const CSSM_DATA		*ptext,
97	uint32 				hashAlg,
98	CSSM_BOOL 			quiet)
99{
100	CSSM_DATA 		hashRef = {0, NULL};		// digest, BSAFE reference
101	CSSM_DATA		hashTest = {0, NULL};		// digest, CSP test
102	int				rtn = 0;
103	CSSM_RETURN		crtn;
104
105	/*
106	 * generate with each method;
107	 * verify digests compare;
108	 */
109	crtn = genDigestBSAFE(hashAlg,
110		ptext,
111		&hashRef);
112	if(crtn) {
113		return testError(quiet);
114	}
115	crtn = genDigestCSSM(cspHand,
116		hashAlg,
117		ptext,
118		&hashTest);
119	if(crtn) {
120		return testError(quiet);
121	}
122
123	/* ensure both methods resulted in same hash */
124	if(hashRef.Length != hashTest.Length) {
125		printf("hash length mismatch (1)\n");
126		rtn = testError(quiet);
127		if(rtn) {
128			goto abort;
129		}
130	}
131	if(memcmp(hashRef.Data, hashTest.Data, hashTest.Length)) {
132		printf("hash miscompare\n");
133		rtn = testError(quiet);
134	}
135	else {
136		rtn = 0;
137	}
138abort:
139	if(hashTest.Length) {
140		CSSM_FREE(hashTest.Data);
141	}
142	if(hashRef.Length) {
143		CSSM_FREE(hashRef.Data);
144	}
145	return rtn;
146}
147
148
149int main(int argc, char **argv)
150{
151	int					arg;
152	char				*argp;
153	unsigned			loop;
154	CSSM_DATA			ptext;
155	CSSM_CSP_HANDLE 	cspHand;
156	const char			*algStr;
157	uint32				hashAlg;		// CSSM_ALGID_xxx
158	int					i;
159	unsigned			currAlg;		// ALG_xxx
160	int					rtn = 0;
161
162	/*
163	 * User-spec'd params
164	 */
165	unsigned	minAlg = ALG_FIRST;
166	unsigned	maxAlg = ALG_LAST;
167	unsigned	loops = LOOPS_DEF;
168	CSSM_BOOL	verbose = CSSM_FALSE;
169	unsigned	minExp = MIN_EXP;
170	unsigned	maxExp = DEFAULT_MAX_EXP;
171	CSSM_BOOL	quiet = CSSM_FALSE;
172	unsigned	pauseInterval = 0;
173	CSSM_BOOL	bareCsp = CSSM_TRUE;
174
175
176	for(arg=1; arg<argc; arg++) {
177		argp = argv[arg];
178		switch(argp[0]) {
179			case 'a':
180				if(argp[1] != '=') {
181					usage(argv);
182				}
183				switch(argp[2]) {
184					case 's':
185						minAlg = maxAlg = ALG_SHA1;
186						break;
187					case '5':
188						minAlg = maxAlg = ALG_MD5;
189						break;
190					case '2':
191						minAlg = maxAlg = ALG_MD2;
192						break;
193					default:
194						usage(argv);
195				}
196				break;
197		    case 'l':
198				loops = atoi(&argp[2]);
199				break;
200		    case 'n':
201				minExp = atoi(&argp[2]);
202				break;
203		    case 'x':
204				maxExp = atoi(&argp[2]);
205				if(maxExp > MAX_EXP) {
206					usage(argv);
207				}
208				break;
209		    case 'v':
210		    	verbose = CSSM_TRUE;
211				break;
212			case 'D':
213				bareCsp = CSSM_FALSE;
214				break;
215		    case 'q':
216		    	quiet = CSSM_TRUE;
217				break;
218		    case 'p':
219		    	pauseInterval = atoi(&argp[2]);;
220				break;
221		    case 'h':
222		    default:
223				usage(argv);
224		}
225	}
226	if(minExp > maxExp) {
227		printf("***minExp must be <= maxExp\n");
228		usage(argv);
229	}
230	ptext.Data = (uint8 *)CSSM_MALLOC(MAX_DATA_SIZE);
231	if(ptext.Data == NULL) {
232		printf("Insufficient heap space\n");
233		exit(1);
234	}
235	/* ptext length set in test loop */
236
237	printf("Starting hashCompat; args: ");
238	for(i=1; i<argc; i++) {
239		printf("%s ", argv[i]);
240	}
241	printf("\n");
242	cspHand = cspDlDbStartup(bareCsp, NULL);
243	if(cspHand == 0) {
244		exit(1);
245	}
246	if(pauseInterval) {
247		fpurge(stdin);
248		printf("Top of test; hit CR to proceed: ");
249		getchar();
250	}
251	for(currAlg=minAlg; currAlg<=maxAlg; currAlg++) {
252		switch(currAlg) {
253			case ALG_SHA1:
254				hashAlg = CSSM_ALGID_SHA1;
255				algStr = "SHA1";
256				break;
257			case ALG_MD5:
258				hashAlg = CSSM_ALGID_MD5;
259				algStr = "MD5";
260				break;
261			case ALG_MD2:
262				hashAlg = CSSM_ALGID_MD2;
263				algStr = "MD2";
264				break;
265			default:
266				printf("***Brrzap. Bad alg.\n");
267				exit(1);
268		}
269
270		if(!quiet || verbose) {
271			printf("Testing alg %s\n", algStr);
272		}
273		for(loop=1; ; loop++) {
274			/* random ptext length and data */
275			ptext.Length = genData(ptext.Data, minExp, maxExp, DT_Random);
276			if(!quiet) {
277			   	if(verbose || ((loop % LOOP_NOTIFY) == 0)) {
278					printf("..loop %d text size %lu \n", loop, ptext.Length);
279				}
280			}
281
282			if(doTest(cspHand,
283					&ptext,
284					hashAlg,
285					quiet)) {
286				rtn = 1;
287				break;
288			}
289			if(pauseInterval && ((loop % pauseInterval) == 0)) {
290				char c;
291				fpurge(stdin);
292				printf("Hit CR to proceed, q to abort: ");
293				c = getchar();
294				if(c == 'q') {
295					goto testDone;
296				}
297			}
298			if(loops && (loop == loops)) {
299				break;
300			}
301		}	/* main loop */
302		if(rtn) {
303			break;
304		}
305	}	/* for algs */
306
307testDone:
308	cspShutdown(cspHand, bareCsp);
309	if(pauseInterval) {
310		fpurge(stdin);
311		printf("ModuleDetach/Unload complete; hit CR to exit: ");
312		getchar();
313	}
314	if((rtn == 0) && !quiet) {
315		printf("%s complete\n", argv[0]);
316	}
317	CSSM_FREE(ptext.Data);
318	return rtn;
319}
320
321
322