1/*
2 * Copyright (c) 1996-1997,2011,2014 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25/*
26 * text size =       {random, from 100 bytes to 1 megabyte, in
27 *                   geometrical steps, i.e. the number of
28 *                   bytes would be 10^r, where r is random out of
29 *                   {2,3,4,5,6}, plus a random integer in {0,..99}};
30 *
31 * password size = constant;
32 *
33 * for loop_count
34 *     text contents = {random data, random size as specified above};
35 *     passsword data = random;
36 *
37       Alternate between ECDSA and ElGamal on sucessive loops:
38 *     generate signature, validate;
39 *     for each byte of signature {
40 *        corrupt text byte;
41 *        verify bad signature;
42 *        restore corrupted byte;
43 *     }
44 *  }
45 */
46
47#import "Crypt.h"
48#include "ckconfig.h"
49
50#if !CRYPTKIT_HIGH_LEVEL_SIG
51#error Can not build this program against a lib with !CRYPTKIT_HIGH_LEVEL_SIG.
52#endif
53
54#import <sys/param.h>
55#import <libc.h>
56
57static unsigned char *passwdPool;	/* all passwords come from here */
58static unsigned char *dataPool;		/* plaintext comes from here */
59
60#define MAX_DATA_SIZE		((1024 * 1024) + 100)	/* bytes */
61
62/*
63 * Defaults.
64 */
65#define LOOPS_DEF	1
66#define MIN_EXP		2		/* for data size 10**exp */
67#define MAX_EXP		4
68#define PWD_LENGTH	15		/* bytes */
69#define DEPTH_DEFAULT	FEE_DEPTH_DEFAULT
70#define INCR_DEFAULT	1		/* munge every incr bytes */
71
72///#define DEPTH_DEFAULT	FEE_DEPTH_5
73
74static void usage(char **argv)
75{
76	printf("usage: %s [options]\n", argv[0]);
77	printf("   Options:\n");
78	printf("   l=loops (default=%d; 0=forever)\n", LOOPS_DEF);
79	printf("   n=minExp (default=%d)\n", MIN_EXP);
80	printf("   x=maxExp (default=max=%d)\n", MAX_EXP);
81	printf("   p=passwdLength (default=%d)\n", PWD_LENGTH);
82	printf("   D=depth (default=%d)\n", DEPTH_DEFAULT);
83	printf("   i=increment (default=%d)\n", INCR_DEFAULT);
84	#if CRYPTKIT_ECDSA_ENABLE
85	printf("   e (ElGamal only, no ECDSA)\n");
86	#endif
87	printf("   s=seed\n");
88	printf("   v(erbose)\n");
89	printf("   q(uiet)\n");
90	printf("   h(elp)\n");
91	exit(1);
92}
93
94/*
95 * ...min <= return <= max
96 */
97static int genRand(int min, int max)
98{
99
100    /* note random() only yields a 31-bit number... */
101
102    if(max == min)			/* avoid % 1 ! */
103	return(max);
104    else
105	return(min + (random() % (max-min+1)));
106}
107
108static unsigned char *genPasswd(unsigned passwdLength)
109{
110	unsigned *ip = (unsigned *)passwdPool;
111	unsigned intCount = passwdLength / 4;
112	int i;
113	unsigned char *cp;
114	unsigned residue = passwdLength & 0x3;
115
116	for (i=0; i<intCount; i++) {
117		*ip++ = random();
118	}
119	cp = (unsigned char *)ip;
120	for(i=0; i<residue; i++) {
121		*cp = (unsigned char)random();
122	}
123	return passwdPool;
124}
125
126/*
127 * Calculate random data size, fill dataPool with that many random bytes.
128 */
129typedef enum {
130	DT_Random,
131	DT_Zero,
132	DT_ASCII
133} dataType;
134
135#define MIN_OFFSET	0
136#define MAX_OFFSET	99
137
138#define MIN_ASCII	' '
139#define MAX_ASCII	'~'
140
141static unsigned char *genData(unsigned minExp,
142	unsigned maxExp,
143	dataType type,
144	unsigned *length)		// RETURNED
145{
146	int 		exp;
147	int 		offset;
148	int 		size;
149	unsigned 	*ip;
150	unsigned 	intCount;
151	unsigned 	residue;
152	char 		*cp;
153	int 		i;
154	char		ac;
155
156	/*
157	 * Calculate "random" size : (10 ** (random exponent)) + random offset
158	 */
159	exp = genRand(minExp, maxExp);
160	offset = genRand(MIN_OFFSET, MAX_OFFSET);
161	size = 1;
162	while(exp--) {			// size = 10 ** exp
163		size *= 10;
164	}
165	size += offset;
166
167	switch(type) {
168	    case DT_Zero:
169		bzero(dataPool, size);
170		break;
171	    case DT_ASCII:
172	    	ac = MIN_ASCII;
173		cp = dataPool;
174	    	for(i=0; i<size; i++) {
175		 	*cp++ = ac++;
176			if(ac > MAX_ASCII) {
177				ac = MIN_ASCII;
178			}
179		}
180		break;
181	    case DT_Random:
182		intCount = size >> 2;
183		ip = (unsigned *)dataPool;
184		for(i=0; i<intCount; i++) {
185			*ip++ = random();
186		}
187
188		residue = size & 0x3;
189		cp = (unsigned char *)ip;
190		for(i=0; i<residue; i++) {
191			*cp++ = (unsigned char)random();
192		}
193		break;
194	}
195	*length = size;
196	return dataPool;
197}
198
199
200static int sigError()
201{
202	char resp[100];
203
204	printf("Attach via debugger for more info.\n");
205	printf("a to abort, c to continue: ");
206	gets(resp);
207	return (resp[0] != 'c');
208}
209
210#define LOG_FREQ	200
211
212int doTest(unsigned char *ptext,
213	unsigned ptextLen,
214	unsigned char *passwd,
215	unsigned passwdLen,
216	int verbose,
217	int quiet,
218	unsigned depth,
219	unsigned incr,
220	int doECDSA,
221	int doECDSAVfy)			// ignored if doECDSASig == 0
222{
223	feePubKey	*pubKey;
224	unsigned char	*sig;
225	unsigned	sigLen;
226	unsigned	byte;
227	unsigned char	origData;
228	unsigned char	bits;
229	feeReturn	frtn;
230
231	pubKey = feePubKeyAlloc();
232	frtn = feePubKeyInitFromPrivDataDepth(pubKey,
233		passwd,
234		passwdLen,
235		depth,
236		1);
237	if(frtn) {
238		printf("feePubKeyInitFromPrivData returned %s\n",
239			feeReturnString(frtn));
240		return sigError();
241	}
242	#if CRYPTKIT_ECDSA_ENABLE
243	if(doECDSA) {
244	    frtn = feePubKeyCreateECDSASignature(pubKey,
245		    ptext,
246		    ptextLen,
247		    &sig,
248		    &sigLen);
249	    if(frtn) {
250		    printf("feePubKeyCreateECDSASignature returned %s\n",
251			    feeReturnString(frtn));
252		    return sigError();
253	    }
254	    if(doECDSAVfy) {
255		frtn = feePubKeyVerifyECDSASignature(pubKey,
256		    ptext,
257		    ptextLen,
258		    sig,
259		    sigLen);
260	    }
261	    else {
262		frtn = feePubKeyVerifySignature(pubKey,
263		    ptext,
264		    ptextLen,
265		    sig,
266		    sigLen);
267	    }
268	}
269	else {
270	#else
271	{
272	#endif	/* CRYPTKIT_ECDSA_ENABLE */
273	    frtn = feePubKeyCreateSignature(pubKey,
274		    ptext,
275		    ptextLen,
276		    &sig,
277		    &sigLen);
278	    if(frtn) {
279		    printf("feePubKeyCreateSignature returned %s\n",
280			    feeReturnString(frtn));
281		    return sigError();
282	    }
283	    frtn = feePubKeyVerifySignature(pubKey,
284	    	ptext,
285		ptextLen,
286		sig,
287		sigLen);
288	}
289	if(frtn) {
290	    printf("**Unexpected BAD signature\n");
291	    return sigError();
292	}
293	for(byte=0; byte<ptextLen; byte += incr) {
294	    if(!quiet && (verbose || ((byte % LOG_FREQ) == 0))) {
295		    printf("....byte %d\n", byte);
296	    }
297	    origData = ptext[byte];
298
299	    /*
300	     * Generate random non-zero byte
301	     */
302	    do {
303		    bits = random() & 0xff;
304	    } while(bits == 0);
305
306	    ptext[byte] ^= bits;
307	    #if CRYPTKIT_ECDSA_ENABLE
308	    if(doECDSA && doECDSAVfy) {
309	    	frtn = feePubKeyVerifyECDSASignature(pubKey,
310		    ptext,
311		    ptextLen,
312		    sig,
313		    sigLen);
314	    }
315	    else {
316	    #else
317	    {
318	    #endif  /* CRYPTKIT_ECDSA_ENABLE */
319	    	frtn = feePubKeyVerifySignature(pubKey,
320		    ptext,
321		    ptextLen,
322		    sig,
323		    sigLen);
324	    }
325	    if(frtn == FR_Success) {
326		printf("**Unexpected GOOD signature\n");
327		return sigError();
328	    }
329	    ptext[byte] = origData;
330	}
331	feePubKeyFree(pubKey);
332	return 0;
333}
334
335int main(int argc, char **argv)
336{
337	int		arg;
338	char		*argp;
339	int		loop;
340	unsigned char	*ptext;
341	unsigned	ptextLen;
342	unsigned char	*passwd;
343	int		doECDSA;
344	int		doECDSAVfy;
345
346	/*
347	 * User-spec'd params
348	 */
349	unsigned	passwdLen = PWD_LENGTH;
350	unsigned	loops = LOOPS_DEF;
351	int		seedSpec = 0;
352	unsigned	seed;
353	int		verbose = 0;
354	unsigned	minExp = MIN_EXP;
355	unsigned	maxExp = MAX_EXP;
356	int		quiet = 0;
357	unsigned	depth = DEPTH_DEFAULT;
358	unsigned	incr = INCR_DEFAULT;
359	#if CRYPTKIT_ECDSA_ENABLE
360	int		elGamalOnly = 0;
361	#else
362	int		elGamalOnly = 1;
363	#endif
364
365	for(arg=1; arg<argc; arg++) {
366		argp = argv[arg];
367		switch(argp[0]) {
368		    case 'l':
369			loops = atoi(&argp[2]);
370			break;
371		    case 'n':
372			minExp = atoi(&argp[2]);
373			break;
374		    case 'x':
375			maxExp = atoi(&argp[2]);
376			if(maxExp > MAX_EXP) {
377				usage(argv);
378			}
379			break;
380		    case 'D':
381			depth = atoi(&argp[2]);
382			break;
383		    case 'i':
384			incr = atoi(&argp[2]);
385			break;
386		    case 's':
387			seed = atoi(&argp[2]);
388			seedSpec = 1;
389			break;
390		    case 'p':
391			passwdLen = atoi(&argp[2]);
392			if(passwdLen == 0) {
393				usage(argv);
394			}
395			break;
396		    case 'e':
397		    	elGamalOnly = 1;
398			break;
399		    case 'v':
400		    	verbose = 1;
401			break;
402		    case 'q':
403		    	quiet = 1;
404			break;
405		    case 'h':
406		    default:
407			usage(argv);
408		}
409	}
410
411	if(seedSpec == 0) {
412		time((long *)(&seed));
413	}
414	srandom(seed);
415	passwdPool = malloc(passwdLen);
416	dataPool = malloc(MAX_DATA_SIZE);
417
418	printf("Starting %s test: loops %d seed %d elGamalOnly %d depth %d\n",
419		argv[0], loops, seed, elGamalOnly, depth);
420
421	#if	0
422	/* debug only */
423	{
424		char s[20];
425		printf("attach, then CR to continue: ");
426		gets(s);
427	}
428	#endif	0
429
430	for(loop=1; ; loop++) {
431
432		ptext = genData(minExp, maxExp, DT_Random, &ptextLen);
433		passwd = genPasswd(passwdLen);
434
435		/*
436		 * Alternate between ECDSA and ElGamal
437		 */
438		if(elGamalOnly) {
439		    doECDSA = 0;
440		    doECDSAVfy = 0;
441		}
442		else {
443		    if(loop & 1) {
444			doECDSA = 1;
445			if(loop & 2) {
446			    doECDSAVfy = 1;
447			}
448			else {
449			    doECDSAVfy = 0;
450			}
451		    }
452		    else {
453			doECDSA = 0;
454			doECDSAVfy = 0;
455		    }
456		 }
457		if(!quiet) {
458		    printf("..loop %d text size %d  ECDSA %d ECDSAVfy %d\n",
459			loop, ptextLen, doECDSA, doECDSAVfy);
460		}
461		if(doTest(ptext, ptextLen, passwd, passwdLen,
462				verbose, quiet, depth, incr,
463				doECDSA, doECDSAVfy)) {
464		    exit(1);
465		}
466
467		if(loops && (loop == loops)) {
468			break;
469		}
470	}
471	if(!quiet) {
472		printf("%s test complete\n", argv[0]);
473	}
474	return 0;
475}
476