]> git.saurik.com Git - apple/security.git/blob - SecurityTests/cspxutils/ccHmacCompat/ccHmacCompat.c
Security-57740.31.2.tar.gz
[apple/security.git] / SecurityTests / cspxutils / ccHmacCompat / ccHmacCompat.c
1 /*
2 * ccHmacCompat.c - test compatibilty of CommonCrypto's HMAC implementation with
3 * openssl.
4 *
5 * Written by Doug Mitchell.
6 */
7
8 #include <stdlib.h>
9 #include <stdio.h>
10 #include <time.h>
11 #include "common.h"
12 #include <string.h>
13 #include <CommonCrypto/CommonHMAC.h>
14 #include <openssl/hmac.h>
15
16 /* SHA2-based HMAC testing disabled until openssl provides it */
17 #define HMAC_SHA2_ENABLE 0
18
19 /*
20 * Defaults.
21 */
22 #define LOOPS_DEF 200
23
24 #define MIN_DATA_SIZE 8
25 #define MAX_DATA_SIZE 10000 /* bytes */
26 #define MIN_KEY_SIZE 1
27 #define MAX_KEY_SIZE 256 /* bytes */
28 #define LOOP_NOTIFY 20
29
30 /*
31 * Enumerate algs our own way to allow iteration.
32 */
33 typedef enum {
34 ALG_MD5 = 1,
35 ALG_SHA1,
36 ALG_SHA224,
37 ALG_SHA256,
38 ALG_SHA384,
39 ALG_SHA512,
40 } HmacAlg;
41 #define ALG_FIRST ALG_MD5
42 #if HMAC_SHA2_ENABLE
43 #define ALG_LAST ALG_SHA512
44 #else
45 #define ALG_LAST ALG_SHA1
46 #endif /* HMAC_SHA2_ENABLE */
47
48 #define LOG_SIZE 0
49 #if LOG_SIZE
50 #define logSize(s) printf s
51 #else
52 #define logSize(s)
53 #endif
54
55 static void usage(char **argv)
56 {
57 printf("usage: %s [options]\n", argv[0]);
58 printf(" Options:\n");
59 printf(" a=algorithm (5=MD5; s=SHA1; 4=SHA224; 2=SHA256; 3=SHA384; 1=SHA512; default=all)\n");
60 printf(" l=loops (default=%d; 0=forever)\n", LOOPS_DEF);
61 printf(" k=keySizeInBytes\n");
62 printf(" m=maxPtextSize (default=%d)\n", MAX_DATA_SIZE);
63 printf(" n=minPtextSize (default=%d)\n", MIN_DATA_SIZE);
64 printf(" p=pauseInterval (default=0, no pause)\n");
65 printf(" s (all ops single-shot, not staged)\n");
66 printf(" z (keys and plaintext all zeroes)\n");
67 printf(" v(erbose)\n");
68 printf(" q(uiet)\n");
69 printf(" h(elp)\n");
70 exit(1);
71 }
72
73 /*
74 * Test harness for CCCryptor/HMAC with lots of options.
75 */
76 static void doHmacCC(
77 CCHmacAlgorithm hmacAlg, bool randUpdates,
78 const void *keyBytes, size_t keyLen,
79 const uint8_t *inText, size_t inTextLen,
80 uint8_t *outText) /* returned, caller mallocs */
81 {
82 CCHmacContext ctx;
83 size_t toMove; /* total to go */
84 const uint8 *inp;
85
86 if(!randUpdates) {
87 /* one shot */
88 CCHmac(hmacAlg, keyBytes, keyLen, inText, inTextLen, outText);
89 return;
90 }
91
92 /* random multi updates */
93 CCHmacInit(&ctx, hmacAlg, keyBytes, keyLen);
94
95 toMove = inTextLen; /* total to go */
96 inp = (const uint8 *)inText;
97
98 while(toMove) {
99 uint32 thisMoveIn; /* input to CCryptUpdate() */
100
101 thisMoveIn = genRand(1, toMove);
102 logSize(("###ptext segment len %lu\n", (unsigned long)thisMoveIn));
103 CCHmacUpdate(&ctx, inp, thisMoveIn);
104 inp += thisMoveIn;
105 toMove -= thisMoveIn;
106 }
107
108 CCHmacFinal(&ctx, outText);
109 }
110
111 /*
112 * Produce HMAC with reference implementation (currently, openssl)
113 */
114 static int doHmacRef(
115 CCHmacAlgorithm hmacAlg,
116 const void *keyBytes, size_t keyLen,
117 const uint8_t *inText, size_t inTextLen,
118 uint8_t *outText, size_t *outTextLen) /* caller mallocs */
119 {
120 const EVP_MD *md;
121
122 switch(hmacAlg) {
123 case kCCHmacAlgMD5:
124 md = EVP_md5();
125 break;
126 case kCCHmacAlgSHA1:
127 md = EVP_sha1();
128 break;
129 #if HMAC_SHA2_ENABLE
130 case kCCHmacAlgSHA224:
131 md = EVP_sha224();
132 break;
133 case kCCHmacAlgSHA256:
134 md = EVP_sha256();
135 break;
136 case kCCHmacAlgSHA384:
137 md = EVP_sha384();
138 break;
139 case kCCHmacAlgSHA512:
140 md = EVP_sha512();
141 break;
142 #endif /* HMAC_SHA2_ENABLE */
143 default:
144 printf("***Bad hmacAlg (%d)\n", (int)hmacAlg);
145 return -1;
146 }
147 unsigned md_len = *outTextLen;
148 HMAC(md, keyBytes, (int)keyLen,
149 (const unsigned char *)inText, (int)inTextLen,
150 (unsigned char *)outText, &md_len);
151 *outTextLen = md_len;
152 return 0;
153 }
154
155
156 #define LOG_FREQ 20
157 #define MAX_HMAC_SIZE CC_SHA512_DIGEST_LENGTH
158
159 static int doTest(const uint8_t *ptext,
160 size_t ptextLen,
161 CCHmacAlgorithm hmacAlg,
162 uint32 keySizeInBytes,
163 bool staged,
164 bool allZeroes,
165 bool quiet)
166 {
167 uint8_t keyBytes[MAX_KEY_SIZE];
168 uint8_t hmacCC[MAX_HMAC_SIZE];
169 size_t hmacCCLen;
170 uint8_t hmacRef[MAX_HMAC_SIZE];
171 size_t hmacRefLen;
172 int rtn = 0;
173
174 if(allZeroes) {
175 memset(keyBytes, 0, keySizeInBytes);
176 }
177 else {
178 /* random key */
179 appGetRandomBytes(keyBytes, keySizeInBytes);
180 }
181
182 hmacCCLen = MAX_HMAC_SIZE;
183 doHmacCC(hmacAlg, staged,
184 keyBytes, keySizeInBytes,
185 ptext, ptextLen,
186 hmacCC);
187
188 hmacRefLen = MAX_HMAC_SIZE;
189 rtn = doHmacRef(hmacAlg,
190 keyBytes, keySizeInBytes,
191 ptext, ptextLen,
192 hmacRef, &hmacRefLen);
193 if(rtn) {
194 rtn = testError(quiet);
195 if(rtn) {
196 goto abort;
197 }
198 }
199
200 if(memcmp(hmacRef, hmacCC, hmacRefLen)) {
201 printf("***data miscompare\n");
202 rtn = testError(quiet);
203 }
204 abort:
205 return rtn;
206 }
207
208 bool isBitSet(unsigned bit, unsigned word)
209 {
210 if(bit > 31) {
211 printf("We don't have that many bits\n");
212 exit(1);
213 }
214 unsigned mask = 1 << bit;
215 return (word & mask) ? true : false;
216 }
217
218 int main(int argc, char **argv)
219 {
220 int arg;
221 char *argp;
222 unsigned loop;
223 uint8 *ptext;
224 size_t ptextLen;
225 bool staged;
226 const char *algStr;
227 CCHmacAlgorithm hmacAlg;
228 int i;
229 int currAlg; // ALG_xxx
230 uint32 keySizeInBytes;
231 int rtn = 0;
232
233 /*
234 * User-spec'd params
235 */
236 bool keySizeSpec = false; // false: use rand key size
237 HmacAlg minAlg = ALG_FIRST;
238 HmacAlg maxAlg = ALG_LAST;
239 unsigned loops = LOOPS_DEF;
240 bool verbose = false;
241 size_t minPtextSize = MIN_DATA_SIZE;
242 size_t maxPtextSize = MAX_DATA_SIZE;
243 bool quiet = false;
244 unsigned pauseInterval = 0;
245 bool stagedSpec = false; // ditto for stagedEncr and stagedDecr
246 bool allZeroes = false;
247
248 for(arg=1; arg<argc; arg++) {
249 argp = argv[arg];
250 switch(argp[0]) {
251 case 'a':
252 if(argp[1] != '=') {
253 usage(argv);
254 }
255 switch(argp[2]) {
256 case '5':
257 minAlg = maxAlg = ALG_MD5;
258 break;
259 case 's':
260 minAlg = maxAlg = ALG_SHA1;
261 break;
262 case '2':
263 minAlg = maxAlg = ALG_SHA256;
264 break;
265 case '3':
266 minAlg = maxAlg = ALG_SHA384;
267 break;
268 case '1':
269 minAlg = maxAlg = ALG_SHA512;
270 break;
271 default:
272 usage(argv);
273 }
274 break;
275 case 'l':
276 loops = atoi(&argp[2]);
277 break;
278 case 'n':
279 minPtextSize = atoi(&argp[2]);
280 break;
281 case 'm':
282 maxPtextSize = atoi(&argp[2]);
283 break;
284 case 'k':
285 keySizeInBytes = atoi(&argp[2]);
286 keySizeSpec = true;
287 break;
288 case 'v':
289 verbose = true;
290 break;
291 case 'q':
292 quiet = true;
293 break;
294 case 'p':
295 pauseInterval = atoi(&argp[2]);;
296 break;
297 case 's':
298 staged = false;
299 stagedSpec = true;
300 break;
301 case 'z':
302 allZeroes = true;
303 break;
304 case 'h':
305 default:
306 usage(argv);
307 }
308 }
309 ptext = (uint8 *)malloc(maxPtextSize);
310 if(ptext == NULL) {
311 printf("Insufficient heap space\n");
312 exit(1);
313 }
314 /* ptext length set in test loop */
315 if(allZeroes) {
316 memset(ptext, 0, maxPtextSize);
317 }
318
319 printf("Starting ccHmacCompat; args: ");
320 for(i=1; i<argc; i++) {
321 printf("%s ", argv[i]);
322 }
323 printf("\n");
324
325 if(pauseInterval) {
326 fpurge(stdin);
327 printf("Top of test; hit CR to proceed: ");
328 getchar();
329 }
330
331 for(currAlg=minAlg; currAlg<=maxAlg; currAlg++) {
332 /* when zero, set size randomly or per user setting */
333 switch(currAlg) {
334 case ALG_MD5:
335 hmacAlg = kCCHmacAlgMD5;
336 algStr = "HMACMD5";
337 break;
338 case ALG_SHA1:
339 hmacAlg = kCCHmacAlgSHA1;
340 algStr = "HMACSHA1";
341 break;
342 case ALG_SHA256:
343 hmacAlg = kCCHmacAlgSHA256;
344 algStr = "HMACSHA256";
345 break;
346 case ALG_SHA384:
347 hmacAlg = kCCHmacAlgSHA384;
348 algStr = "HMACSHA384";
349 break;
350 case ALG_SHA512:
351 hmacAlg = kCCHmacAlgSHA512;
352 algStr = "HMACSHA512";
353 break;
354 default:
355 printf("***BRRZAP!\n");
356 exit(1);
357 }
358 if(!quiet || verbose) {
359 printf("Testing alg %s\n", algStr);
360 }
361 for(loop=1; ; loop++) {
362 ptextLen = genRand(minPtextSize, maxPtextSize);
363 if(!allZeroes) {
364 appGetRandomBytes(ptext, ptextLen);
365 }
366 if(!keySizeSpec) {
367 keySizeInBytes = genRand(MIN_KEY_SIZE, MAX_KEY_SIZE);
368 }
369
370 /* per-loop settings */
371 if(!stagedSpec) {
372 staged = isBitSet(1, loop);
373 }
374
375 if(!quiet) {
376 if(verbose || ((loop % LOOP_NOTIFY) == 0)) {
377 printf("..loop %d ptextLen %lu keySize %lu staged=%d\n",
378 loop, (unsigned long)ptextLen, (unsigned long)keySizeInBytes,
379 (int)staged);
380 }
381 }
382
383 if(doTest(ptext, ptextLen,
384 hmacAlg, keySizeInBytes,
385 staged, allZeroes, quiet)) {
386 rtn = 1;
387 break;
388 }
389 if(pauseInterval && ((loop % pauseInterval) == 0)) {
390 char c;
391 fpurge(stdin);
392 printf("Hit CR to proceed, q to abort: ");
393 c = getchar();
394 if(c == 'q') {
395 goto testDone;
396 }
397 }
398 if(loops && (loop == loops)) {
399 break;
400 }
401 } /* main loop */
402 if(rtn) {
403 break;
404 }
405
406 } /* for algs */
407
408 testDone:
409 if(pauseInterval) {
410 fpurge(stdin);
411 printf("ModuleDetach/Unload complete; hit CR to exit: ");
412 getchar();
413 }
414 if((rtn == 0) && !quiet) {
415 printf("%s test complete\n", argv[0]);
416 }
417 free(ptext);
418 return rtn;
419 }
420
421