1/* Copyright (c) 1998,2003-2006,2008 Apple Inc. 2 * 3 * hashTest.c - test CDSA digest functions. 4 * 5 * Revision History 6 * ---------------- 7 * 4 May 2000 Doug Mitchell 8 * Ported to X/CDSA2. 9 * 12 May 1998 Doug Mitchell at Apple 10 * Created. 11 */ 12/* 13 * text size = {random, from 100 bytes to 100k, in 14 * geometrical steps, i.e. the number of 15 * bytes would be 10^r, where r is random out of 16 * {2,3,4,5,6}, plus a random integer in {0,..99}}; 17 * 18 * for loop_count 19 * text contents = {random data, random size as specified above}; 20 * generate digest in one shot; 21 * generate digest with multiple random-sized updates; 22 * verify digests compare; 23 * for various bytes of text { 24 * corrupt text byte; 25 * generate digest in one shot; 26 * veridy digest is different; 27 * restore corrupted byte; 28 * } 29 * } 30 */ 31 32#include <stdlib.h> 33#include <stdio.h> 34#include <time.h> 35#include <string.h> 36#include <Security/cssm.h> 37#include "cspwrap.h" 38#include <Security/cssm.h> 39#include <Security/cssmapple.h> 40#include "cspwrap.h" 41#include "common.h" 42 43/* 44 * Defaults. 45 */ 46#define LOOPS_DEF 50 47#define MIN_EXP 2 /* for data size 10**exp */ 48#define DEFAULT_MAX_EXP 3 49#define MAX_EXP 5 50#define INCR_DEFAULT 0 /* munge every incr bytes - zero means 51 * "adjust per ptext size" */ 52typedef enum { 53 ALG_MD2 = 1, 54 ALG_MD5, 55 ALG_SHA1, 56 ALG_SHA224, 57 ALG_SHA256, 58 ALG_SHA384, 59 ALG_SHA512 60}; 61 62#define ALG_FIRST ALG_MD2 63#define ALG_LAST ALG_SHA512 64#define MAX_DATA_SIZE (100000 + 100) /* bytes */ 65#define LOOP_NOTIFY 20 66 67static void usage(char **argv) 68{ 69 printf("usage: %s [options]\n", argv[0]); 70 printf(" Options:\n"); 71 printf(" a=algorithm (s=SHA1; m=MD5; M=MD2; 4=SHA224; 2=SHA256; 3=SHA384; 5=SHA512; " 72 "default=all\n"); 73 printf(" l=loops (default=%d; 0=forever)\n", LOOPS_DEF); 74 printf(" n=minExp (default=%d)\n", MIN_EXP); 75 printf(" x=maxExp (default=%d, max=%d)\n", DEFAULT_MAX_EXP, MAX_EXP); 76 printf(" i=increment (default=%d)\n", INCR_DEFAULT); 77 printf(" p=pauseInterval (default=0, no pause)\n"); 78 printf(" z (zero data)\n"); 79 printf(" I (incrementing data)\n"); 80 printf(" g (good digest only)\n"); 81 printf(" D (CSP/DL; default = bare CSP)\n"); 82 printf(" v(erbose)\n"); 83 printf(" q(uiet)\n"); 84 printf(" h(elp)\n"); 85 exit(1); 86} 87 88#define LOG_FREQ 20 89 90static int doTest(CSSM_CSP_HANDLE cspHand, 91 uint32 alg, 92 CSSM_DATA_PTR ptext, 93 CSSM_BOOL verbose, 94 CSSM_BOOL quiet, 95 CSSM_BOOL mallocDigest, 96 unsigned incr, 97 CSSM_BOOL goodOnly) 98{ 99 CSSM_DATA refDigest = {0, NULL}; 100 CSSM_DATA testDigest = {0, NULL}; 101 unsigned length; 102 unsigned byte; 103 unsigned char *data; 104 unsigned char origData; 105 unsigned char bits; 106 int rtn = 0; 107 CSSM_RETURN crtn; 108 unsigned loop = 0; 109 110 /* 111 * generate digest in one shot; 112 * generate digest with multiple random-sized updates; 113 * verify digests compare; 114 * for various bytes of ptext { 115 * corrupt ptext byte; 116 * generate digest in one shot; 117 * verify digest is different; 118 * restore corrupted byte; 119 * } 120 */ 121 crtn = cspDigest(cspHand, 122 alg, 123 mallocDigest, 124 ptext, 125 &refDigest); 126 if(crtn) { 127 rtn = testError(quiet); 128 goto abort; 129 } 130 crtn = cspStagedDigest(cspHand, 131 alg, 132 mallocDigest, 133 CSSM_TRUE, // multi updates 134 ptext, 135 &testDigest); 136 if(crtn) { 137 rtn = testError(quiet); 138 goto abort; 139 } 140 if(refDigest.Length != testDigest.Length) { 141 printf("Digest length mismatch (1)\n"); 142 rtn = testError(quiet); 143 goto abort; 144 } 145 if(memcmp(refDigest.Data, testDigest.Data, refDigest.Length)) { 146 printf("Digest miscompare (1)\n"); 147 rtn = testError(quiet); 148 if(rtn) { 149 goto abort; 150 } 151 } 152 if(goodOnly) { 153 rtn = 0; 154 goto abort; 155 } 156 appFreeCssmData(&testDigest, CSSM_FALSE); 157 testDigest.Length = 0; 158 data = (unsigned char *)ptext->Data; 159 length = ptext->Length; 160 for(byte=0; byte<length; byte += incr) { 161 if(verbose && ((loop++ % LOG_FREQ) == 0)) { 162 printf("....byte %d\n", byte); 163 } 164 origData = data[byte]; 165 /* 166 * Generate random non-zero byte 167 */ 168 do { 169 bits = genRand(1, 0xff) & 0xff; 170 } while(bits == 0); 171 data[byte] ^= bits; 172 crtn = cspDigest(cspHand, 173 alg, 174 mallocDigest, 175 ptext, 176 &testDigest); 177 if(crtn) { 178 rtn = testError(quiet); 179 break; 180 } 181 if(!memcmp(refDigest.Data, testDigest.Data, refDigest.Length)) { 182 printf("Unexpected digest compare\n"); 183 rtn = testError(quiet); 184 break; 185 } 186 appFreeCssmData(&testDigest, CSSM_FALSE); 187 testDigest.Length = 0; 188 data[byte] = origData; 189 } 190abort: 191 /* free digests */ 192 if(refDigest.Length) { 193 appFreeCssmData(&refDigest, CSSM_FALSE); 194 } 195 if(testDigest.Length) { 196 appFreeCssmData(&testDigest, CSSM_FALSE); 197 } 198 return rtn; 199} 200 201int main(int argc, char **argv) 202{ 203 int arg; 204 char *argp; 205 unsigned loop; 206 CSSM_DATA ptext; 207 CSSM_CSP_HANDLE cspHand; 208 CSSM_BOOL mallocDigest; 209 const char *algStr; 210 uint32 alg; // ALG_MD5, etc. 211 uint32 cssmAlg; // CSSM_ALGID_MD5, etc. 212 unsigned actualIncr; 213 int i; 214 215 /* 216 * User-spec'd params 217 */ 218 unsigned loops = LOOPS_DEF; 219 CSSM_BOOL verbose = CSSM_FALSE; 220 unsigned minExp = MIN_EXP; 221 unsigned maxExp = DEFAULT_MAX_EXP; 222 CSSM_BOOL quiet = CSSM_FALSE; 223 unsigned incr = INCR_DEFAULT; 224 unsigned minAlg = ALG_FIRST; 225 unsigned maxAlg = ALG_LAST; 226 unsigned pauseInterval = 0; 227 dataType dt; 228 CSSM_BOOL goodOnly = CSSM_FALSE; 229 CSSM_BOOL bareCsp = CSSM_TRUE; 230 231 for(arg=1; arg<argc; arg++) { 232 argp = argv[arg]; 233 switch(argp[0]) { 234 case 'a': 235 if(argp[1] != '=') { 236 usage(argv); 237 } 238 switch(argp[2]) { 239 case 's': 240 minAlg = maxAlg = ALG_SHA1; 241 break; 242 case 'm': 243 minAlg = maxAlg = ALG_MD5; 244 break; 245 case 'M': 246 minAlg = maxAlg = ALG_MD2; 247 break; 248 case '4': 249 minAlg = maxAlg = ALG_SHA224; 250 break; 251 case '2': 252 minAlg = maxAlg = ALG_SHA256; 253 break; 254 case '3': 255 minAlg = maxAlg = ALG_SHA384; 256 break; 257 case '5': 258 minAlg = maxAlg = ALG_SHA512; 259 break; 260 default: 261 usage(argv); 262 } 263 break; 264 case 'l': 265 loops = atoi(&argp[2]); 266 break; 267 case 'n': 268 minExp = atoi(&argp[2]); 269 break; 270 case 'x': 271 maxExp = atoi(&argp[2]); 272 if(maxExp > MAX_EXP) { 273 usage(argv); 274 } 275 break; 276 case 'i': 277 incr = atoi(&argp[2]); 278 break; 279 case 'p': 280 pauseInterval = atoi(&argp[2]);; 281 break; 282 case 'v': 283 verbose = CSSM_TRUE; 284 break; 285 case 'q': 286 quiet = CSSM_TRUE; 287 break; 288 case 'D': 289 bareCsp = CSSM_FALSE; 290 break; 291 case 'z': 292 dt = DT_Zero; 293 break; 294 case 'I': 295 dt = DT_Increment; 296 break; 297 case 'g': 298 goodOnly = CSSM_TRUE; 299 break; 300 case 'h': 301 default: 302 usage(argv); 303 } 304 } 305 ptext.Data = (uint8 *)CSSM_MALLOC(MAX_DATA_SIZE); 306 /* length set in test loop */ 307 if(ptext.Data == NULL) { 308 printf("Insufficient heap\n"); 309 exit(1); 310 } 311 312 printf("Starting hashTest; args: "); 313 for(i=1; i<argc; i++) { 314 printf("%s ", argv[i]); 315 } 316 printf("\n"); 317 cspHand = cspDlDbStartup(bareCsp, NULL); 318 if(cspHand == 0) { 319 exit(1); 320 } 321 322 for(alg=minAlg; alg<=maxAlg; alg++) { 323 switch(alg) { 324 case ALG_MD5: 325 algStr = "MD5"; 326 cssmAlg = CSSM_ALGID_MD5; 327 break; 328 case ALG_MD2: 329 algStr = "MD2"; 330 cssmAlg = CSSM_ALGID_MD2; 331 break; 332 case ALG_SHA1: 333 algStr = "SHA1"; 334 cssmAlg = CSSM_ALGID_SHA1; 335 break; 336 case ALG_SHA224: 337 algStr = "SHA224"; 338 cssmAlg = CSSM_ALGID_SHA224; 339 break; 340 case ALG_SHA256: 341 algStr = "SHA256"; 342 cssmAlg = CSSM_ALGID_SHA256; 343 break; 344 case ALG_SHA384: 345 algStr = "SHA384"; 346 cssmAlg = CSSM_ALGID_SHA384; 347 break; 348 case ALG_SHA512: 349 algStr = "SHA512"; 350 cssmAlg = CSSM_ALGID_SHA512; 351 break; 352 } 353 if(!quiet) { 354 printf("Testing alg %s\n", algStr); 355 } 356 for(loop=1; ; loop++) { 357 ptext.Length = genData(ptext.Data, minExp, maxExp, dt); 358 if(incr == 0) { 359 /* adjust increment as appropriate */ 360 actualIncr = (ptext.Length / 50) + 1; 361 } 362 else { 363 actualIncr = incr; 364 } 365 /* mix up mallocing */ 366 mallocDigest = (loop & 1) ? CSSM_TRUE : CSSM_FALSE; 367 if(!quiet) { 368 if(verbose || ((loop % LOOP_NOTIFY) == 0)) { 369 printf("..loop %d text size %lu mallocDigest %d\n", 370 loop, (unsigned long)ptext.Length, (int)mallocDigest); 371 } 372 } 373 if(doTest(cspHand, 374 cssmAlg, 375 &ptext, 376 verbose, 377 quiet, 378 mallocDigest, 379 actualIncr, 380 goodOnly)) { 381 exit(1); 382 } 383 if(loops && (loop == loops)) { 384 break; 385 } 386 if(pauseInterval && ((loop % pauseInterval) == 0)) { 387 fpurge(stdin); 388 printf("Hit CR to proceed: "); 389 getchar(); 390 } 391 } 392 } 393 if(!quiet) { 394 printf("%s test complete\n", argv[0]); 395 } 396 return 0; 397} 398