1/*
2 * hashClone.c - test CSSM_DigestDataClone function
3 */
4
5#include <stdlib.h>
6#include <stdio.h>
7#include <time.h>
8#include <Security/cssm.h>
9#include <Security/cssmapple.h>
10#include "cspwrap.h"
11#include "common.h"
12
13/*
14 * Defaults
15 */
16#define LOOPS_DEF		50
17#define MAX_PTEXT		(8 * 1024)
18#define MIN_PTEXT		16
19#define LOOP_NOTIFY		20
20
21/*
22 * Enumerated algs
23 */
24typedef unsigned privAlg;
25enum  {
26	ALG_MD5 = 1,
27	ALG_SHA1,
28	ALG_MD2,
29	ALG_SHA224,
30	ALG_SHA256,
31	ALG_SHA384,
32	ALG_SHA512
33};
34
35#define ALG_FIRST	ALG_MD5
36#define ALG_LAST	ALG_SHA512
37
38static void usage(char **argv)
39{
40	printf("usage: %s [options]\n", argv[0]);
41	printf("   Options:\n");
42	printf("   a=algorithm (s=SHA1; m=MD5; M=MD2; 4=SHA224; 2=SHA256; 3=SHA384; 5=SHA512; "
43					"default=all\n");
44	printf("   l=loops (default=%d; 0=forever)\n", LOOPS_DEF);
45	printf("   p=pauseInterval (default=0, no pause)\n");
46	printf("   D (CSP/DL; default = bare CSP)\n");
47	printf("   v(erbose)\n");
48	printf("   q(uiet)\n");
49	printf("   h(elp)\n");
50	exit(1);
51}
52
53static int doTest(CSSM_CSP_HANDLE cspHand,
54	CSSM_ALGORITHMS alg,
55	const char *algStr,
56	CSSM_DATA_PTR ptext,
57	CSSM_BOOL verbose,
58	CSSM_BOOL quiet)
59{
60	CSSM_CC_HANDLE		digHand1 = 0;	// reference
61	CSSM_CC_HANDLE		digHand2 = 0;	// to be cloned
62	CSSM_CC_HANDLE		digHand3 = 0;	// cloned from digHand2
63	CSSM_DATA 			dig1 = {0, NULL};
64	CSSM_DATA 			dig2 = {0, NULL};
65	CSSM_DATA 			dig3 = {0, NULL};
66	CSSM_RETURN			crtn;
67	unsigned			thisMove;		// this update
68	unsigned			toMove;			// total to go
69	unsigned			totalRequest;	// originally requested
70	CSSM_DATA			thisText;		// actually passed to update
71
72	/* cook up two digest contexts */
73	crtn = CSSM_CSP_CreateDigestContext(cspHand,
74		alg,
75		&digHand1);
76	if(crtn) {
77		printError("CSSM_CSP_CreateDigestContext (1)", crtn);
78		return testError(quiet);
79	}
80	crtn = CSSM_CSP_CreateDigestContext(cspHand,
81		alg,
82		&digHand2);
83	if(crtn) {
84		printError("CSSM_CSP_CreateDigestContext (2)", crtn);
85		return testError(quiet);
86	}
87	crtn = CSSM_DigestDataInit(digHand1);
88	if(crtn) {
89		printError("CSSM_DigestDataInit (1)", crtn);
90		return testError(quiet);
91	}
92	crtn = CSSM_DigestDataInit(digHand2);
93	if(crtn) {
94		printError("CSSM_DigestDataInit (2)", crtn);
95		return testError(quiet);
96	}
97
98	/* do some random updates to first two digests, until we've digested
99	 * at least half of the requested data */
100	totalRequest = ptext->Length;
101	toMove = ptext->Length;
102	thisText.Data = ptext->Data;
103	while(toMove > (totalRequest / 2)) {
104		thisMove = genRand((MIN_PTEXT / 2), toMove);
105		thisText.Length = thisMove;
106		if(verbose) {
107			printf("  ..updating digest1, digest2 with %d bytes\n", thisMove);
108		}
109		crtn = CSSM_DigestDataUpdate(digHand1, &thisText, 1);
110		if(crtn) {
111			printError("CSSM_DigestDataUpdate (1)", crtn);
112			return testError(quiet);
113		}
114		crtn = CSSM_DigestDataUpdate(digHand2, &thisText, 1);
115		if(crtn) {
116			printError("CSSM_DigestDataUpdate (2)", crtn);
117			return testError(quiet);
118		}
119		thisText.Data += thisMove;
120		toMove -= thisMove;
121	}
122
123	/* digest3 := clone(digest2) */
124	crtn = CSSM_DigestDataClone(digHand2, &digHand3);
125	if(crtn) {
126		printError("CSSM_DigestDataClone", crtn);
127		return testError(quiet);
128	}
129
130	/* finish off remaining ptext, updating all 3 digests identically */
131	while(toMove) {
132		thisMove = genRand(1, toMove);
133		thisText.Length = thisMove;
134		if(verbose) {
135			printf("  ..updating all three digests with %d bytes\n", thisMove);
136		}
137		crtn = CSSM_DigestDataUpdate(digHand1, &thisText, 1);
138		if(crtn) {
139			printError("CSSM_DigestDataUpdate (3)", crtn);
140			return testError(quiet);
141		}
142		crtn = CSSM_DigestDataUpdate(digHand2, &thisText, 1);
143		if(crtn) {
144			printError("CSSM_DigestDataUpdate (4)", crtn);
145			return testError(quiet);
146		}
147		crtn = CSSM_DigestDataUpdate(digHand3, &thisText, 1);
148		if(crtn) {
149			printError("CSSM_DigestDataUpdate (5)", crtn);
150			return testError(quiet);
151		}
152		thisText.Data += thisMove;
153		toMove -= thisMove;
154	}
155
156	/* obtain all three digests */
157	crtn = CSSM_DigestDataFinal(digHand1, &dig1);
158	if(crtn) {
159		printError("CSSM_DigestDataFinal (1)", crtn);
160		return testError(quiet);
161	}
162	crtn = CSSM_DigestDataFinal(digHand2, &dig2);
163	if(crtn) {
164		printError("CSSM_DigestDataFinal (2)", crtn);
165		return testError(quiet);
166	}
167	crtn = CSSM_DigestDataFinal(digHand3, &dig3);
168	if(crtn) {
169		printError("CSSM_DigestDataFinal (3)", crtn);
170		return testError(quiet);
171	}
172
173	/* ensure all three digests identical */
174	if(!appCompareCssmData(&dig1, &dig2)) {
175		printf("***Digest miscompare(dig1, dig2)***\n");
176		if(testError(quiet)) {
177			return 1;
178		}
179	}
180	if(!appCompareCssmData(&dig2, &dig3)) {
181		printf("***Digest miscompare(dig2, dig3)***\n");
182		if(testError(quiet)) {
183			return 1;
184		}
185	}
186
187	/* free resources */
188	appFreeCssmData(&dig1, CSSM_FALSE);
189	appFreeCssmData(&dig2, CSSM_FALSE);
190	appFreeCssmData(&dig3, CSSM_FALSE);
191	CSSM_DeleteContext(digHand1);
192	CSSM_DeleteContext(digHand2);
193	CSSM_DeleteContext(digHand3);
194	return 0;
195}
196
197int main(int argc, char **argv)
198{
199	int					arg;
200	char				*argp;
201	unsigned			loop;
202	CSSM_DATA			ptext;
203	CSSM_CSP_HANDLE 	cspHand;
204	const char 			*algStr;
205	privAlg				alg;		// ALG_MD5, etc.
206	CSSM_ALGORITHMS		cssmAlg;	// CSSM_ALGID_MD5, etc.
207	int					j;
208
209	/*
210	 * User-spec'd params
211	 */
212	unsigned	loops = LOOPS_DEF;
213	CSSM_BOOL	verbose = CSSM_FALSE;
214	CSSM_BOOL	quiet = CSSM_FALSE;
215	unsigned	minAlg = ALG_FIRST;
216	unsigned	maxAlg = ALG_LAST;
217	unsigned	pauseInterval = 0;
218	CSSM_BOOL	bareCsp = CSSM_TRUE;
219
220	for(arg=1; arg<argc; arg++) {
221		argp = argv[arg];
222		switch(argp[0]) {
223			case 'a':
224				if(argp[1] != '=') {
225					usage(argv);
226				}
227				switch(argp[2]) {
228					case 's':
229						minAlg = maxAlg = ALG_SHA1;
230						break;
231					case 'm':
232						minAlg = maxAlg = ALG_MD5;
233						break;
234					case 'M':
235						minAlg = maxAlg = ALG_MD2;
236						break;
237					case '4':
238						minAlg = maxAlg = ALG_SHA224;
239						break;
240					case '2':
241						minAlg = maxAlg = ALG_SHA256;
242						break;
243					case '3':
244						minAlg = maxAlg = ALG_SHA384;
245						break;
246					case '5':
247						minAlg = maxAlg = ALG_SHA512;
248						break;
249					default:
250						usage(argv);
251				}
252				break;
253		    case 'l':
254				loops = atoi(&argp[2]);
255				break;
256		    case 'p':
257		    	pauseInterval = atoi(&argp[2]);;
258				break;
259		    case 'v':
260		    	verbose = CSSM_TRUE;
261				break;
262		    case 'q':
263		    	quiet = CSSM_TRUE;
264				break;
265			case 'D':
266				bareCsp = CSSM_FALSE;
267				break;
268		    case 'h':
269		    default:
270				usage(argv);
271		}
272	}
273	ptext.Data = (uint8 *)CSSM_MALLOC(MAX_PTEXT);
274	/* length set in test loop */
275	if(ptext.Data == NULL) {
276		printf("Insufficient heap\n");
277		exit(1);
278	}
279
280	printf("Starting hashClone; args: ");
281	for(j=1; j<argc; j++) {
282		printf("%s ", argv[j]);
283	}
284	printf("\n");
285	cspHand = cspDlDbStartup(bareCsp, NULL);
286	if(cspHand == 0) {
287		exit(1);
288	}
289
290	for(alg=minAlg; alg<=maxAlg; alg++) {
291		switch(alg) {
292			case ALG_MD5:
293				algStr = "MD5";
294				cssmAlg = CSSM_ALGID_MD5;
295				break;
296			case ALG_MD2:
297				algStr = "MD2";
298				cssmAlg = CSSM_ALGID_MD2;
299				break;
300			case ALG_SHA1:
301				algStr = "SHA1";
302				cssmAlg = CSSM_ALGID_SHA1;
303				break;
304			case ALG_SHA224:
305				algStr = "SHA224";
306				cssmAlg = CSSM_ALGID_SHA224;
307				break;
308			case ALG_SHA256:
309				algStr = "SHA256";
310				cssmAlg = CSSM_ALGID_SHA256;
311				break;
312			case ALG_SHA384:
313				algStr = "SHA384";
314				cssmAlg = CSSM_ALGID_SHA384;
315				break;
316			case ALG_SHA512:
317				algStr = "SHA512";
318				cssmAlg = CSSM_ALGID_SHA512;
319				break;
320		}
321		if(!quiet) {
322			printf("Testing alg %s\n", algStr);
323		}
324		for(loop=1; ; loop++) {
325			simpleGenData(&ptext, MIN_PTEXT, MAX_PTEXT);
326			if(!quiet) {
327			   	if(verbose || ((loop % LOOP_NOTIFY) == 0)) {
328					printf("..loop %d text size %lu\n", loop, ptext.Length);
329				}
330			}
331			if(doTest(cspHand,
332					cssmAlg,
333					algStr,
334					&ptext,
335					verbose,
336					quiet)) {
337				exit(1);
338			}
339			if(loops && (loop == loops)) {
340				break;
341			}
342			if(pauseInterval && ((loop % pauseInterval) == 0)) {
343				fpurge(stdin);
344				printf("Hit CR to proceed: ");
345				getchar();
346			}
347		}
348	}
349	cspShutdown(cspHand, bareCsp);
350	if(!quiet) {
351		printf("%s test complete\n", argv[0]);
352	}
353	return 0;
354}
355