#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include "common.h"
#include <string.h>
#include <CommonCrypto/CommonDigest.h>
#include <openssl/hmac.h>
#define LOOPS_DEF 200
#define MIN_DATA_SIZE 1
#define MAX_DATA_SIZE 10000
#define LOOP_NOTIFY 20
typedef enum {
ALG_MD2 = 1,
ALG_MD4,
ALG_MD5,
ALG_SHA1,
ALG_SHA224,
ALG_SHA256,
ALG_SHA384,
ALG_SHA512
} HashAlg;
#define ALG_FIRST ALG_MD2
#define ALG_LAST ALG_SHA512
static void usage(char **argv)
{
printf("usage: %s [options]\n", argv[0]);
printf(" Options:\n");
printf(" l=loops (default %d)\n", LOOPS_DEF);
printf(" q(uiet)\n");
printf(" h(elp)\n");
exit(1);
}
typedef int (*initFcn)(void *ctx);
typedef int (*updateFcn)(void *ctx, const void *data, CC_LONG len);
typedef int (*finalFcn)(unsigned char *md, void *ctx);
typedef unsigned char (*oneShotFcn)(const void *data, CC_LONG len, unsigned char *md);
typedef struct {
HashAlg alg;
const char *algName;
size_t digestSize;
initFcn init;
updateFcn update;
finalFcn final;
oneShotFcn oneShot;
} CommonDigestInfo;
static const CommonDigestInfo digests[] =
{
{ ALG_MD2, "MD2", CC_MD2_DIGEST_LENGTH,
(initFcn)CC_MD2_Init, (updateFcn)CC_MD2_Update,
(finalFcn)CC_MD2_Final, (oneShotFcn)CC_MD2
},
{ ALG_MD4, "MD4", CC_MD4_DIGEST_LENGTH,
(initFcn)CC_MD4_Init, (updateFcn)CC_MD4_Update,
(finalFcn)CC_MD4_Final, (oneShotFcn)CC_MD4
},
{ ALG_MD5, "MD5", CC_MD5_DIGEST_LENGTH,
(initFcn)CC_MD5_Init, (updateFcn)CC_MD5_Update,
(finalFcn)CC_MD5_Final, (oneShotFcn)CC_MD5
},
{ ALG_SHA1, "SHA1", CC_SHA1_DIGEST_LENGTH,
(initFcn)CC_SHA1_Init, (updateFcn)CC_SHA1_Update,
(finalFcn)CC_SHA1_Final, (oneShotFcn)CC_SHA1
},
{ ALG_SHA224, "SHA224", CC_SHA224_DIGEST_LENGTH,
(initFcn)CC_SHA224_Init, (updateFcn)CC_SHA224_Update,
(finalFcn)CC_SHA224_Final, (oneShotFcn)CC_SHA224
},
{ ALG_SHA256, "SHA256", CC_SHA256_DIGEST_LENGTH,
(initFcn)CC_SHA256_Init, (updateFcn)CC_SHA256_Update,
(finalFcn)CC_SHA256_Final, (oneShotFcn)CC_SHA256
},
{ ALG_SHA384, "SHA384", CC_SHA384_DIGEST_LENGTH,
(initFcn)CC_SHA384_Init, (updateFcn)CC_SHA384_Update,
(finalFcn)CC_SHA384_Final, (oneShotFcn)CC_SHA384
},
{ ALG_SHA512, "SHA512", CC_SHA512_DIGEST_LENGTH,
(initFcn)CC_SHA512_Init, (updateFcn)CC_SHA512_Update,
(finalFcn)CC_SHA512_Final, (oneShotFcn)CC_SHA512
},
};
#define NUM_DIGESTS (sizeof(digests) / sizeof(digests[0]))
static const CommonDigestInfo *findDigestInfo(unsigned alg)
{
unsigned dex;
for(dex=0; dex<NUM_DIGESTS; dex++) {
if((unsigned)(digests[dex].alg) == alg) {
return &digests[dex];
}
}
return NULL;
}
#define MAX_DIGEST_SIZE 64
#define MAX_CONTEXT_SIZE sizeof(CC_SHA512_CTX)
static void doStaged(
const CommonDigestInfo *digestInfo,
const unsigned char *ptext,
unsigned ptextLen,
unsigned char *md)
{
char ctx[MAX_CONTEXT_SIZE];
unsigned thisMove;
digestInfo->init(ctx);
while(ptextLen) {
thisMove = genRand(1, ptextLen);
digestInfo->update(ctx, ptext, thisMove);
ptext += thisMove;
ptextLen -= thisMove;
}
digestInfo->final(md, ctx);
}
static int doTest(
const CommonDigestInfo *digestInfo,
const unsigned char *ptext,
unsigned ptextLen,
bool quiet)
{
unsigned char mdStaged[MAX_DIGEST_SIZE];
unsigned char mdOneShot[MAX_DIGEST_SIZE];
digestInfo->oneShot(ptext, ptextLen, mdOneShot);
doStaged(digestInfo, ptext, ptextLen, mdStaged);
if(memcmp(mdStaged, mdOneShot, digestInfo->digestSize)) {
printf("***Digest miscompare for %s\n", digestInfo->algName);
if(testError(quiet)) {
return 1;
}
}
return 0;
}
int main(int argc, char **argv)
{
int arg;
char *argp;
unsigned loop;
uint8 *ptext;
size_t ptextLen;
unsigned currAlg;
const CommonDigestInfo *digestInfo;
int rtn = 0;
int i;
unsigned loops = LOOPS_DEF;
bool quiet = false;
for(arg=1; arg<argc; arg++) {
argp = argv[arg];
switch(argp[0]) {
case 'l':
loops = atoi(&argp[2]);
break;
case 'q':
quiet = true;
break;
case 'h':
default:
usage(argv);
}
}
ptext = (uint8 *)malloc(MAX_DATA_SIZE);
if(ptext == NULL) {
printf("Insufficient heap space\n");
exit(1);
}
printf("Starting ccOneShot; args: ");
for(i=1; i<argc; i++) {
printf("%s ", argv[i]);
}
printf("\n");
for(currAlg=ALG_FIRST; currAlg<=ALG_LAST; currAlg++) {
digestInfo = findDigestInfo(currAlg);
if(!quiet) {
printf("Testing alg %s\n", digestInfo->algName);
}
for(loop=1; ; loop++) {
ptextLen = genRand(MIN_DATA_SIZE, MAX_DATA_SIZE);
appGetRandomBytes(ptext, ptextLen);
if(!quiet) {
if((loop % LOOP_NOTIFY) == 0) {
printf("..loop %d ptextLen %lu\n",
loop, (unsigned long)ptextLen);
}
}
if(doTest(digestInfo, ptext, ptextLen, quiet)) {
rtn = 1;
break;
}
if(loops && (loop == loops)) {
break;
}
}
if(rtn) {
break;
}
}
if((rtn == 0) && !quiet) {
printf("%s test complete\n", argv[0]);
}
free(ptext);
return rtn;
}