#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <Security/cssm.h>
#include <Security/cssmapple.h>
#include "cspwrap.h"
#include "common.h"
#define LOOPS_DEF 50
#define MAX_PTEXT (8 * 1024)
#define MIN_PTEXT 16
#define LOOP_NOTIFY 20
typedef unsigned privAlg;
enum {
ALG_MD5 = 1,
ALG_SHA1,
ALG_MD2,
ALG_SHA224,
ALG_SHA256,
ALG_SHA384,
ALG_SHA512
};
#define ALG_FIRST ALG_MD5
#define ALG_LAST ALG_SHA512
static void usage(char **argv)
{
printf("usage: %s [options]\n", argv[0]);
printf(" Options:\n");
printf(" a=algorithm (s=SHA1; m=MD5; M=MD2; 4=SHA224; 2=SHA256; 3=SHA384; 5=SHA512; "
"default=all\n");
printf(" l=loops (default=%d; 0=forever)\n", LOOPS_DEF);
printf(" p=pauseInterval (default=0, no pause)\n");
printf(" D (CSP/DL; default = bare CSP)\n");
printf(" v(erbose)\n");
printf(" q(uiet)\n");
printf(" h(elp)\n");
exit(1);
}
static int doTest(CSSM_CSP_HANDLE cspHand,
CSSM_ALGORITHMS alg,
const char *algStr,
CSSM_DATA_PTR ptext,
CSSM_BOOL verbose,
CSSM_BOOL quiet)
{
CSSM_CC_HANDLE digHand1 = 0; CSSM_CC_HANDLE digHand2 = 0; CSSM_CC_HANDLE digHand3 = 0; CSSM_DATA dig1 = {0, NULL};
CSSM_DATA dig2 = {0, NULL};
CSSM_DATA dig3 = {0, NULL};
CSSM_RETURN crtn;
unsigned thisMove; unsigned toMove; unsigned totalRequest; CSSM_DATA thisText;
crtn = CSSM_CSP_CreateDigestContext(cspHand,
alg,
&digHand1);
if(crtn) {
printError("CSSM_CSP_CreateDigestContext (1)", crtn);
return testError(quiet);
}
crtn = CSSM_CSP_CreateDigestContext(cspHand,
alg,
&digHand2);
if(crtn) {
printError("CSSM_CSP_CreateDigestContext (2)", crtn);
return testError(quiet);
}
crtn = CSSM_DigestDataInit(digHand1);
if(crtn) {
printError("CSSM_DigestDataInit (1)", crtn);
return testError(quiet);
}
crtn = CSSM_DigestDataInit(digHand2);
if(crtn) {
printError("CSSM_DigestDataInit (2)", crtn);
return testError(quiet);
}
totalRequest = ptext->Length;
toMove = ptext->Length;
thisText.Data = ptext->Data;
while(toMove > (totalRequest / 2)) {
thisMove = genRand((MIN_PTEXT / 2), toMove);
thisText.Length = thisMove;
if(verbose) {
printf(" ..updating digest1, digest2 with %d bytes\n", thisMove);
}
crtn = CSSM_DigestDataUpdate(digHand1, &thisText, 1);
if(crtn) {
printError("CSSM_DigestDataUpdate (1)", crtn);
return testError(quiet);
}
crtn = CSSM_DigestDataUpdate(digHand2, &thisText, 1);
if(crtn) {
printError("CSSM_DigestDataUpdate (2)", crtn);
return testError(quiet);
}
thisText.Data += thisMove;
toMove -= thisMove;
}
crtn = CSSM_DigestDataClone(digHand2, &digHand3);
if(crtn) {
printError("CSSM_DigestDataClone", crtn);
return testError(quiet);
}
while(toMove) {
thisMove = genRand(1, toMove);
thisText.Length = thisMove;
if(verbose) {
printf(" ..updating all three digests with %d bytes\n", thisMove);
}
crtn = CSSM_DigestDataUpdate(digHand1, &thisText, 1);
if(crtn) {
printError("CSSM_DigestDataUpdate (3)", crtn);
return testError(quiet);
}
crtn = CSSM_DigestDataUpdate(digHand2, &thisText, 1);
if(crtn) {
printError("CSSM_DigestDataUpdate (4)", crtn);
return testError(quiet);
}
crtn = CSSM_DigestDataUpdate(digHand3, &thisText, 1);
if(crtn) {
printError("CSSM_DigestDataUpdate (5)", crtn);
return testError(quiet);
}
thisText.Data += thisMove;
toMove -= thisMove;
}
crtn = CSSM_DigestDataFinal(digHand1, &dig1);
if(crtn) {
printError("CSSM_DigestDataFinal (1)", crtn);
return testError(quiet);
}
crtn = CSSM_DigestDataFinal(digHand2, &dig2);
if(crtn) {
printError("CSSM_DigestDataFinal (2)", crtn);
return testError(quiet);
}
crtn = CSSM_DigestDataFinal(digHand3, &dig3);
if(crtn) {
printError("CSSM_DigestDataFinal (3)", crtn);
return testError(quiet);
}
if(!appCompareCssmData(&dig1, &dig2)) {
printf("***Digest miscompare(dig1, dig2)***\n");
if(testError(quiet)) {
return 1;
}
}
if(!appCompareCssmData(&dig2, &dig3)) {
printf("***Digest miscompare(dig2, dig3)***\n");
if(testError(quiet)) {
return 1;
}
}
appFreeCssmData(&dig1, CSSM_FALSE);
appFreeCssmData(&dig2, CSSM_FALSE);
appFreeCssmData(&dig3, CSSM_FALSE);
CSSM_DeleteContext(digHand1);
CSSM_DeleteContext(digHand2);
CSSM_DeleteContext(digHand3);
return 0;
}
int main(int argc, char **argv)
{
int arg;
char *argp;
unsigned loop;
CSSM_DATA ptext;
CSSM_CSP_HANDLE cspHand;
const char *algStr;
privAlg alg; CSSM_ALGORITHMS cssmAlg; int j;
unsigned loops = LOOPS_DEF;
CSSM_BOOL verbose = CSSM_FALSE;
CSSM_BOOL quiet = CSSM_FALSE;
unsigned minAlg = ALG_FIRST;
unsigned maxAlg = ALG_LAST;
unsigned pauseInterval = 0;
CSSM_BOOL bareCsp = CSSM_TRUE;
for(arg=1; arg<argc; arg++) {
argp = argv[arg];
switch(argp[0]) {
case 'a':
if(argp[1] != '=') {
usage(argv);
}
switch(argp[2]) {
case 's':
minAlg = maxAlg = ALG_SHA1;
break;
case 'm':
minAlg = maxAlg = ALG_MD5;
break;
case 'M':
minAlg = maxAlg = ALG_MD2;
break;
case '4':
minAlg = maxAlg = ALG_SHA224;
break;
case '2':
minAlg = maxAlg = ALG_SHA256;
break;
case '3':
minAlg = maxAlg = ALG_SHA384;
break;
case '5':
minAlg = maxAlg = ALG_SHA512;
break;
default:
usage(argv);
}
break;
case 'l':
loops = atoi(&argp[2]);
break;
case 'p':
pauseInterval = atoi(&argp[2]);;
break;
case 'v':
verbose = CSSM_TRUE;
break;
case 'q':
quiet = CSSM_TRUE;
break;
case 'D':
bareCsp = CSSM_FALSE;
break;
case 'h':
default:
usage(argv);
}
}
ptext.Data = (uint8 *)CSSM_MALLOC(MAX_PTEXT);
if(ptext.Data == NULL) {
printf("Insufficient heap\n");
exit(1);
}
printf("Starting hashClone; args: ");
for(j=1; j<argc; j++) {
printf("%s ", argv[j]);
}
printf("\n");
cspHand = cspDlDbStartup(bareCsp, NULL);
if(cspHand == 0) {
exit(1);
}
for(alg=minAlg; alg<=maxAlg; alg++) {
switch(alg) {
case ALG_MD5:
algStr = "MD5";
cssmAlg = CSSM_ALGID_MD5;
break;
case ALG_MD2:
algStr = "MD2";
cssmAlg = CSSM_ALGID_MD2;
break;
case ALG_SHA1:
algStr = "SHA1";
cssmAlg = CSSM_ALGID_SHA1;
break;
case ALG_SHA224:
algStr = "SHA224";
cssmAlg = CSSM_ALGID_SHA224;
break;
case ALG_SHA256:
algStr = "SHA256";
cssmAlg = CSSM_ALGID_SHA256;
break;
case ALG_SHA384:
algStr = "SHA384";
cssmAlg = CSSM_ALGID_SHA384;
break;
case ALG_SHA512:
algStr = "SHA512";
cssmAlg = CSSM_ALGID_SHA512;
break;
}
if(!quiet) {
printf("Testing alg %s\n", algStr);
}
for(loop=1; ; loop++) {
simpleGenData(&ptext, MIN_PTEXT, MAX_PTEXT);
if(!quiet) {
if(verbose || ((loop % LOOP_NOTIFY) == 0)) {
printf("..loop %d text size %lu\n", loop, ptext.Length);
}
}
if(doTest(cspHand,
cssmAlg,
algStr,
&ptext,
verbose,
quiet)) {
exit(1);
}
if(loops && (loop == loops)) {
break;
}
if(pauseInterval && ((loop % pauseInterval) == 0)) {
fpurge(stdin);
printf("Hit CR to proceed: ");
getchar();
}
}
}
cspShutdown(cspHand, bareCsp);
if(!quiet) {
printf("%s test complete\n", argv[0]);
}
return 0;
}