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