#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <CommonCrypto/CommonDigest.h>
#include "MD5.h"
#include "SHA1.h"
#include <Security/cssmtype.h>
#include <Security/cssmapple.h>
#include <CoreFoundation/CFDate.h>
typedef int HT_Alg;
enum {
HA_MD5 = 0,
HA_SHA1,
HA_SHA224,
HA_SHA256,
HA_SHA384,
HA_SHA512
};
#define FIRST_ALG HA_MD5
#define LAST_ALG HA_SHA512
static void usage(char **argv)
{
printf("Usage: %s c|k [option ...]\n", argv[0]);
printf(" c=CommonCrypto; k=CryptKit\n");
printf("Options:\n");
printf(" a=alg; default=all\n");
printf(" algs: m : MD5\n");
printf(" s : SHA1\n");
printf(" 4 : SHA224\n");
printf(" 2 : SHA256\n");
printf(" 3 : SHA384\n");
printf(" 5 : SHA512\n");
printf(" l=loops (only valid if testspec is given)\n");
printf(" v verify digest by printing it\n");
exit(1);
}
static void dumpDigest(
const unsigned char *digest,
unsigned len)
{
for(unsigned dex=0; dex<len; dex++) {
printf("%02X", *digest++);
if((dex % 4) == 3) {
printf(" ");
}
}
printf("\n");
}
static void initPtext(
unsigned char *ptext,
unsigned len)
{
srandom(1);
for(unsigned dex=0; dex<len; dex++) {
*ptext++ = random();
}
}
typedef struct {
unsigned loops;
CSSM_ALGORITHMS algId; bool dumpDigest;
} TestParams;
#define MAX_DIGEST_SIZE 64 // we provide, no malloc below CSSM
#define PTEXT_SIZE 1000 // to digest in bytes
#define INNER_LOOPS 500
static void ckSha1Final(
void *ctx,
unsigned char *digest)
{
sha1GetDigest((sha1Obj)ctx, digest);
}
typedef void (*ckInitFcn)(void *digestCtx);
typedef void (*ckUpdateFcn)(void *digestCtx, const void *data, unsigned len);
typedef void (*ckFinalFcn)(void *digestCtx, unsigned char *digest);
static CSSM_RETURN hashDataRateCryptKit(
TestParams *params)
{
ckUpdateFcn updatePtr = NULL;
ckFinalFcn finalPtr = NULL;
ckInitFcn initPtr = NULL;
struct MD5Context md5;
sha1Obj sha;
void *ctx;
unsigned loop;
unsigned iloop;
double startTime, endTime;
double timeSpent, timeSpentMs;
uint8 ptext[PTEXT_SIZE];
uint8 digest[MAX_DIGEST_SIZE];
unsigned digestLen = 16;
switch(params->algId) {
case CSSM_ALGID_SHA1:
sha = sha1Alloc();
ctx = sha;
initPtr = (ckInitFcn)sha1Reinit;
updatePtr = (ckUpdateFcn)sha1AddData;
finalPtr = (ckFinalFcn)ckSha1Final;
digestLen = 20;
break;
case CSSM_ALGID_MD5:
ctx = &md5;
initPtr = (ckInitFcn)MD5Init;
updatePtr = (ckUpdateFcn)MD5Update;
finalPtr = (ckFinalFcn)MD5Final;
break;
default:
printf("***Sorry, CryptKit can only do SHA1 and MD5.\n");
return 1;
}
initPtext(ptext, PTEXT_SIZE);
startTime = CFAbsoluteTimeGetCurrent();
for(loop=0; loop<params->loops; loop++) {
initPtr(ctx);
for(iloop=0; iloop<INNER_LOOPS; iloop++) {
updatePtr(ctx, ptext, PTEXT_SIZE);
}
finalPtr(ctx, digest);
}
endTime = CFAbsoluteTimeGetCurrent();
timeSpent = endTime - startTime;
timeSpentMs = timeSpent * 1000.0;
float bytesPerLoop = INNER_LOOPS * PTEXT_SIZE;
float totalBytes = params->loops * bytesPerLoop;
printf(" Digest %.0f bytes : %u ops in %.2f ms; %f ms/op, %.0f KBytes/s\n",
bytesPerLoop, params->loops,
timeSpentMs, timeSpentMs / (double)params->loops,
((float)totalBytes / 1024.0) / timeSpent);
if(params->dumpDigest) {
dumpDigest(digest, digestLen);
}
return CSSM_OK;
}
typedef union {
CC_MD5_CTX md5;
CC_SHA1_CTX sha;
CC_SHA256_CTX sha256;
CC_SHA512_CTX sha512;
} CC_CTX;
typedef void (*ccInitFcn)(void *digestCtx);
typedef void (*ccUpdateFcn)(void *digestCtx, const void *data, CC_LONG len);
typedef void (*ccFinalFcn)(unsigned char *digest, void *digestCtx);
static CSSM_RETURN hashDataRateCommonCrypto(
TestParams *params)
{
CC_CTX ctx;
ccUpdateFcn updatePtr = NULL;
ccFinalFcn finalPtr = NULL;
ccInitFcn initPtr = NULL;
unsigned loop;
unsigned iloop;
double startTime, endTime;
double timeSpent, timeSpentMs;
uint8 ptext[PTEXT_SIZE];
uint8 digest[MAX_DIGEST_SIZE];
unsigned digestLen = 16;
switch(params->algId) {
case CSSM_ALGID_SHA1:
initPtr = (ccInitFcn)CC_SHA1_Init;
updatePtr = (ccUpdateFcn)CC_SHA1_Update;
finalPtr = (ccFinalFcn)CC_SHA1_Final;
digestLen = 20;
break;
case CSSM_ALGID_SHA224:
initPtr = (ccInitFcn)CC_SHA224_Init;
updatePtr = (ccUpdateFcn)CC_SHA224_Update;
finalPtr = (ccFinalFcn)CC_SHA224_Final;
digestLen = 28;
break;
case CSSM_ALGID_SHA256:
initPtr = (ccInitFcn)CC_SHA256_Init;
updatePtr = (ccUpdateFcn)CC_SHA256_Update;
finalPtr = (ccFinalFcn)CC_SHA256_Final;
digestLen = 32;
break;
case CSSM_ALGID_SHA384:
initPtr = (ccInitFcn)CC_SHA384_Init;
updatePtr = (ccUpdateFcn)CC_SHA384_Update;
finalPtr = (ccFinalFcn)CC_SHA384_Final;
digestLen = 48;
break;
case CSSM_ALGID_SHA512:
initPtr = (ccInitFcn)CC_SHA512_Init;
updatePtr = (ccUpdateFcn)CC_SHA512_Update;
finalPtr = (ccFinalFcn)CC_SHA512_Final;
digestLen = 64;
break;
case CSSM_ALGID_MD5:
initPtr = (ccInitFcn)CC_MD5_Init;
updatePtr = (ccUpdateFcn)CC_MD5_Update;
finalPtr = (ccFinalFcn)CC_MD5_Final;
digestLen = 16;
break;
default:
printf("***BRRRZAP!\n");
return 1;
}
initPtext(ptext, PTEXT_SIZE);
startTime = CFAbsoluteTimeGetCurrent();
for(loop=0; loop<params->loops; loop++) {
initPtr(&ctx);
for(iloop=0; iloop<INNER_LOOPS; iloop++) {
updatePtr(&ctx, ptext, PTEXT_SIZE);
}
finalPtr(digest, &ctx);
}
endTime = CFAbsoluteTimeGetCurrent();
timeSpent = endTime - startTime;
timeSpentMs = timeSpent * 1000.0;
float bytesPerLoop = INNER_LOOPS * PTEXT_SIZE;
float totalBytes = params->loops * bytesPerLoop;
printf(" Digest %.0f bytes : %u ops in %.2f ms; %f ms/op, %.0f KBytes/s\n",
bytesPerLoop, params->loops,
timeSpentMs, timeSpentMs / (double)params->loops,
((float)totalBytes / 1024.0) / timeSpent);
if(params->dumpDigest) {
dumpDigest(digest, digestLen);
}
return CSSM_OK;
}
typedef CSSM_RETURN (*testRunFcn)(TestParams *testParams);
typedef struct {
const char *testName;
unsigned loops;
testRunFcn run;
char testSpec; } TestDefs;
static TestDefs testDefsCryptKit =
{ "Large data digest, CryptKit",
1000,
hashDataRateCryptKit,
'd',
};
static TestDefs testDefsCommonCrypto =
{ "Large data digest, CommonCrypto",
1000,
hashDataRateCommonCrypto,
'd',
};
static void algToAlgId(
HT_Alg alg,
CSSM_ALGORITHMS *algId,
const char **algStr)
{
switch(alg) {
case HA_MD5:
*algId = CSSM_ALGID_MD5;
*algStr = "MD5";
break;
case HA_SHA1:
*algId = CSSM_ALGID_SHA1;
*algStr = "SHA1";
break;
case HA_SHA224:
*algId = CSSM_ALGID_SHA224;
*algStr = "SHA224";
break;
case HA_SHA256:
*algId = CSSM_ALGID_SHA256;
*algStr = "SHA256";
break;
case HA_SHA384:
*algId = CSSM_ALGID_SHA384;
*algStr = "SHA384";
break;
case HA_SHA512:
*algId = CSSM_ALGID_SHA512;
*algStr = "SHA512";
break;
default:
printf("***algToAlgId screwup\n");
exit(1);
}
}
int main(int argc, char **argv)
{
TestParams testParams;
TestDefs *testDefs = NULL;
CSSM_RETURN crtn;
int arg;
char *argp;
unsigned cmdLoops = 0; HT_Alg alg;
const char *algStr;
int firstAlg = FIRST_ALG;
int lastAlg = LAST_ALG;
memset(&testParams, 0, sizeof(testParams));
if(argc < 2) {
usage(argv);
}
switch(argv[1][0]) {
case 'c':
testDefs = &testDefsCommonCrypto;
break;
case 'k':
testDefs = &testDefsCryptKit;
break;
default:
usage(argv);
}
for(arg=2; arg<argc; arg++) {
argp = argv[arg];
switch(argp[0]) {
case 'l':
cmdLoops = atoi(&argp[2]);
break;
case 'a':
if(argp[1] == '\0') {
usage(argv);
}
switch(argp[2]) {
case 'm':
firstAlg = lastAlg = HA_MD5;
break;
case 's':
firstAlg = lastAlg = HA_SHA1;
break;
case '4':
firstAlg = lastAlg = HA_SHA224;
break;
case '2':
firstAlg = lastAlg = HA_SHA256;
break;
case '3':
firstAlg = lastAlg = HA_SHA384;
break;
case '5':
firstAlg = lastAlg = HA_SHA512;
break;
default:
usage(argv);
}
break;
case 'v':
testParams.dumpDigest = true;
break;
default:
usage(argv);
}
}
printf("%s:\n", testDefs->testName);
if(cmdLoops) {
testParams.loops = cmdLoops;
}
else {
testParams.loops = testDefs->loops;
}
if((lastAlg > HA_SHA1) && (testDefs == &testDefsCryptKit)) {
lastAlg = HA_SHA1;
}
for(alg=firstAlg; alg<=lastAlg; alg++) {
algToAlgId(alg, &testParams.algId, &algStr);
printf(" === %s ===\n", algStr);
crtn = testDefs->run(&testParams);
if(crtn) {
printf("***Error detected in test, somehow....aborting.\n");
exit(1);
}
}
return 0;
}