1/* 2 * ccOneShot.c - Ensure that one-shot CommonDigest routines behave correctly. 3 * 4 * Written 3/31/06 by Doug Mitchell. 5 */ 6 7#include <stdlib.h> 8#include <stdio.h> 9#include <time.h> 10#include "common.h" 11#include <string.h> 12#include <CommonCrypto/CommonDigest.h> 13#include <openssl/hmac.h> 14 15/* 16 * Defaults. 17 */ 18#define LOOPS_DEF 200 19#define MIN_DATA_SIZE 1 20#define MAX_DATA_SIZE 10000 /* bytes */ 21#define LOOP_NOTIFY 20 22 23/* 24 * Enumerate algs our own way to allow iteration. 25 */ 26typedef enum { 27 ALG_MD2 = 1, 28 ALG_MD4, 29 ALG_MD5, 30 ALG_SHA1, 31 ALG_SHA224, 32 ALG_SHA256, 33 ALG_SHA384, 34 ALG_SHA512 35} HashAlg; 36#define ALG_FIRST ALG_MD2 37#define ALG_LAST ALG_SHA512 38 39static void usage(char **argv) 40{ 41 printf("usage: %s [options]\n", argv[0]); 42 printf(" Options:\n"); 43 printf(" l=loops (default %d)\n", LOOPS_DEF); 44 printf(" q(uiet)\n"); 45 printf(" h(elp)\n"); 46 exit(1); 47} 48 49/* the context pointers are void * here for polymorphism later on */ 50typedef int (*initFcn)(void *ctx); 51typedef int (*updateFcn)(void *ctx, const void *data, CC_LONG len); 52typedef int (*finalFcn)(unsigned char *md, void *ctx); 53typedef unsigned char (*oneShotFcn)(const void *data, CC_LONG len, unsigned char *md); 54 55typedef struct { 56 HashAlg alg; 57 const char *algName; 58 size_t digestSize; 59 initFcn init; 60 updateFcn update; 61 finalFcn final; 62 oneShotFcn oneShot; 63} CommonDigestInfo; 64 65/* casts are necessary to cover the void* context args */ 66static const CommonDigestInfo digests[] = 67{ 68 { ALG_MD2, "MD2", CC_MD2_DIGEST_LENGTH, 69 (initFcn)CC_MD2_Init, (updateFcn)CC_MD2_Update, 70 (finalFcn)CC_MD2_Final, (oneShotFcn)CC_MD2 71 }, 72 { ALG_MD4, "MD4", CC_MD4_DIGEST_LENGTH, 73 (initFcn)CC_MD4_Init, (updateFcn)CC_MD4_Update, 74 (finalFcn)CC_MD4_Final, (oneShotFcn)CC_MD4 75 }, 76 { ALG_MD5, "MD5", CC_MD5_DIGEST_LENGTH, 77 (initFcn)CC_MD5_Init, (updateFcn)CC_MD5_Update, 78 (finalFcn)CC_MD5_Final, (oneShotFcn)CC_MD5 79 }, 80 { ALG_SHA1, "SHA1", CC_SHA1_DIGEST_LENGTH, 81 (initFcn)CC_SHA1_Init, (updateFcn)CC_SHA1_Update, 82 (finalFcn)CC_SHA1_Final, (oneShotFcn)CC_SHA1 83 }, 84 { ALG_SHA224, "SHA224", CC_SHA224_DIGEST_LENGTH, 85 (initFcn)CC_SHA224_Init, (updateFcn)CC_SHA224_Update, 86 (finalFcn)CC_SHA224_Final, (oneShotFcn)CC_SHA224 87 }, 88 { ALG_SHA256, "SHA256", CC_SHA256_DIGEST_LENGTH, 89 (initFcn)CC_SHA256_Init, (updateFcn)CC_SHA256_Update, 90 (finalFcn)CC_SHA256_Final, (oneShotFcn)CC_SHA256 91 }, 92 { ALG_SHA384, "SHA384", CC_SHA384_DIGEST_LENGTH, 93 (initFcn)CC_SHA384_Init, (updateFcn)CC_SHA384_Update, 94 (finalFcn)CC_SHA384_Final, (oneShotFcn)CC_SHA384 95 }, 96 { ALG_SHA512, "SHA512", CC_SHA512_DIGEST_LENGTH, 97 (initFcn)CC_SHA512_Init, (updateFcn)CC_SHA512_Update, 98 (finalFcn)CC_SHA512_Final, (oneShotFcn)CC_SHA512 99 }, 100}; 101#define NUM_DIGESTS (sizeof(digests) / sizeof(digests[0])) 102 103static const CommonDigestInfo *findDigestInfo(unsigned alg) 104{ 105 unsigned dex; 106 for(dex=0; dex<NUM_DIGESTS; dex++) { 107 if((unsigned)(digests[dex].alg) == alg) { 108 return &digests[dex]; 109 } 110 } 111 return NULL; 112} 113 114 115/* 116 * These consts let us allocate context and digest buffers for 117 * any arbitrary algorithm. 118 */ 119#define MAX_DIGEST_SIZE 64 120#define MAX_CONTEXT_SIZE sizeof(CC_SHA512_CTX) 121 122/* staged digest with random updates */ 123static void doStaged( 124 const CommonDigestInfo *digestInfo, 125 const unsigned char *ptext, 126 unsigned ptextLen, 127 unsigned char *md) 128{ 129 char ctx[MAX_CONTEXT_SIZE]; 130 unsigned thisMove; 131 132 digestInfo->init(ctx); 133 while(ptextLen) { 134 thisMove = genRand(1, ptextLen); 135 digestInfo->update(ctx, ptext, thisMove); 136 ptext += thisMove; 137 ptextLen -= thisMove; 138 } 139 digestInfo->final(md, ctx); 140} 141 142static int doTest( 143 const CommonDigestInfo *digestInfo, 144 const unsigned char *ptext, 145 unsigned ptextLen, 146 bool quiet) 147{ 148 unsigned char mdStaged[MAX_DIGEST_SIZE]; 149 unsigned char mdOneShot[MAX_DIGEST_SIZE]; 150 151 digestInfo->oneShot(ptext, ptextLen, mdOneShot); 152 doStaged(digestInfo, ptext, ptextLen, mdStaged); 153 if(memcmp(mdStaged, mdOneShot, digestInfo->digestSize)) { 154 printf("***Digest miscompare for %s\n", digestInfo->algName); 155 if(testError(quiet)) { 156 return 1; 157 } 158 } 159 return 0; 160} 161 162int main(int argc, char **argv) 163{ 164 int arg; 165 char *argp; 166 unsigned loop; 167 uint8 *ptext; 168 size_t ptextLen; 169 unsigned currAlg; 170 const CommonDigestInfo *digestInfo; 171 int rtn = 0; 172 int i; 173 174 /* 175 * User-spec'd params 176 */ 177 unsigned loops = LOOPS_DEF; 178 bool quiet = false; 179 180 for(arg=1; arg<argc; arg++) { 181 argp = argv[arg]; 182 switch(argp[0]) { 183 case 'l': 184 loops = atoi(&argp[2]); 185 break; 186 case 'q': 187 quiet = true; 188 break; 189 case 'h': 190 default: 191 usage(argv); 192 } 193 } 194 ptext = (uint8 *)malloc(MAX_DATA_SIZE); 195 if(ptext == NULL) { 196 printf("Insufficient heap space\n"); 197 exit(1); 198 } 199 /* ptext length set in test loop */ 200 201 printf("Starting ccOneShot; args: "); 202 for(i=1; i<argc; i++) { 203 printf("%s ", argv[i]); 204 } 205 printf("\n"); 206 207 for(currAlg=ALG_FIRST; currAlg<=ALG_LAST; currAlg++) { 208 digestInfo = findDigestInfo(currAlg); 209 if(!quiet) { 210 printf("Testing alg %s\n", digestInfo->algName); 211 } 212 for(loop=1; ; loop++) { 213 ptextLen = genRand(MIN_DATA_SIZE, MAX_DATA_SIZE); 214 appGetRandomBytes(ptext, ptextLen); 215 if(!quiet) { 216 if((loop % LOOP_NOTIFY) == 0) { 217 printf("..loop %d ptextLen %lu\n", 218 loop, (unsigned long)ptextLen); 219 } 220 } 221 222 if(doTest(digestInfo, ptext, ptextLen, quiet)) { 223 rtn = 1; 224 break; 225 } 226 if(loops && (loop == loops)) { 227 break; 228 } 229 } /* main loop */ 230 if(rtn) { 231 break; 232 } 233 234 } /* for algs */ 235 236 if((rtn == 0) && !quiet) { 237 printf("%s test complete\n", argv[0]); 238 } 239 free(ptext); 240 return rtn; 241} 242 243 244