#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <time.h>
#include <string.h>
#include <CommonCrypto/CommonCryptor.h>
#include <CommonCrypto/CommonDigest.h>
#include <CommonCrypto/CommonHMAC.h>
#include <CommonCrypto/CommonHMacSPI.h>
#include <CommonCrypto/CommonKeyDerivationSPI.h>
#include <CommonCrypto/CommonDigestSPI.h>
#include "testmore.h"
#include "testbyteBuffer.h"
#include "capabilities.h"
#if (CCHMACCLONE == 0)
entryPoint(CommonHMacClone,"Common HMac Cloning")
#else
#define LOOPS_DEF 200
#define MIN_DATA_SIZE 8
#define MAX_DATA_SIZE 10000
#define MIN_KEY_SIZE 1
#define MAX_KEY_SIZE 256
#define LOOP_NOTIFY 20
typedef enum {
ALG_MD5 = 1,
ALG_SHA1,
ALG_SHA224,
ALG_SHA256,
ALG_SHA384,
ALG_SHA512,
} HmacAlg;
#define ALG_FIRST ALG_MD5
#define ALG_LAST ALG_SHA512
#define LOG_SIZE 0
#if LOG_SIZE
#define logSize(s) diag(s)
#else
#define logSize(s)
#endif
static void hmacRun(
CCHmacContext *ctx,
bool randomUpdates,
const unsigned char *ptext,
size_t ptextLen,
void *dataOut)
{
while(ptextLen) {
size_t thisMoveIn;
if(randomUpdates) {
thisMoveIn = genRandomSize(1, ptextLen);
}
else {
thisMoveIn = ptextLen;
}
logSize(("###ptext segment (1) len %lu\n", (unsigned long)thisMoveIn));
CCHmacUpdate(ctx, ptext, thisMoveIn);
ptext += thisMoveIn;
ptextLen -= thisMoveIn;
}
CCHmacFinal(ctx, dataOut);
}
#define MAX_HMAC_SIZE CC_SHA512_DIGEST_LENGTH
static int doHMacCloneTest(const uint8_t *ptext,
size_t ptextLen,
CCHmacAlgorithm hmacAlg,
uint32_t keySizeInBytes,
bool stagedOrig,
bool stagedClone,
bool quiet,
bool verbose)
{
uint8_t *keyBytes;
uint8_t hmacOrig[MAX_HMAC_SIZE];
uint8_t hmacClone[MAX_HMAC_SIZE];
int rtn = 1;
CCHmacContext ctxOrig;
CCHmacContext ctxClone;
unsigned die;
unsigned loopNum = 0;
size_t hmacLen;
bool didClone = false;
switch(hmacAlg) {
case kCCHmacAlgSHA1:
if(verbose) diag("hmac-sha1\n");
hmacLen = CC_SHA1_DIGEST_LENGTH;
break;
case kCCHmacAlgMD5:
if(verbose) diag("hmac-md5\n");
hmacLen = CC_MD5_DIGEST_LENGTH;
break;
case kCCHmacAlgSHA224:
if(verbose) diag("hmac-sha224\n");
hmacLen = CC_SHA224_DIGEST_LENGTH;
break;
case kCCHmacAlgSHA256:
if(verbose) diag("hmac-sha256\n");
hmacLen = CC_SHA256_DIGEST_LENGTH;
break;
case kCCHmacAlgSHA384:
if(verbose) diag("hmac-sha384\n");
hmacLen = CC_SHA384_DIGEST_LENGTH;
break;
case kCCHmacAlgSHA512:
if(verbose) diag("hmac-sha512\n");
hmacLen = CC_SHA512_DIGEST_LENGTH;
break;
default:
if(verbose) diag("***BRRRZAP!\n");
return 0;
}
byteBuffer keyBuffer = genRandomByteBuffer(keySizeInBytes, keySizeInBytes);
keyBytes = keyBuffer->bytes;
CCHmacInit(&ctxOrig, hmacAlg, keyBytes, keySizeInBytes);
die = (unsigned) genRandomSize(0, 3);
while(ptextLen) {
if((die == loopNum) || !stagedOrig) {
if(verbose) {
diag(" ...cloning at loop %u\n", loopNum);
}
ctxClone = ctxOrig;
didClone = true;
if(memcmp(&ctxClone, &ctxOrig, CC_HMAC_CONTEXT_SIZE * sizeof(uint32_t))) {
if(verbose) diag("*** context miscompare\n");
} else {
if(verbose) diag("*** context clone worked\n");
}
hmacRun(&ctxClone, stagedClone, ptext, ptextLen, hmacClone);
hmacRun(&ctxOrig, stagedOrig, ptext, ptextLen, hmacOrig);
break;
}
size_t thisMove;
if(stagedOrig) {
thisMove = genRandomSize(1, ptextLen);
}
else {
thisMove = ptextLen;
}
logSize(("###ptext segment (2) len %lu\n", (unsigned long)thisMove));
CCHmacUpdate(&ctxOrig, ptext, thisMove);
ptext += thisMove;
ptextLen -= thisMove;
loopNum++;
}
if(!didClone) {
if(verbose) {
diag("...ctxOrig finished before we cloned; skipping test\n");
}
return 1;
}
if(memcmp(hmacOrig, hmacClone, hmacLen)) {
diag("***data miscompare\n");
rtn = 0;
} else {
if(verbose) diag("*** clone worked\n");
rtn = 1;
}
if(keyBuffer) free(keyBuffer);
return rtn;
}
static bool isBitSet(unsigned bit, unsigned word)
{
if(bit > 31) {
diag("We don't have that many bits\n");
return -1;
}
unsigned mask = 1 << bit;
return (word & mask) ? true : false;
}
static int kTestTestCount = 1200;
int CommonHMacClone(int argc, char *const *argv)
{
unsigned loop;
uint8_t *ptext;
size_t ptextLen;
bool stagedOrig;
bool stagedClone;
const char *algStr;
CCHmacAlgorithm hmacAlg;
HmacAlg currAlg; uint32_t keySizeInBytes;
int rtn = 0;
bool keySizeSpec = false; HmacAlg minAlg = ALG_FIRST;
HmacAlg maxAlg = ALG_LAST;
unsigned loops = LOOPS_DEF;
bool verbose = false;
size_t minPtextSize = MIN_DATA_SIZE;
size_t maxPtextSize = MAX_DATA_SIZE;
bool quiet = true;
bool stagedSpec = false;
plan_tests(kTestTestCount);
for(currAlg=minAlg; currAlg<=maxAlg; currAlg++) {
switch(currAlg) {
case ALG_MD5:
hmacAlg = kCCHmacAlgMD5;
algStr = "HMACMD5";
break;
case ALG_SHA1:
hmacAlg = kCCHmacAlgSHA1;
algStr = "HMACSHA1";
break;
case ALG_SHA224:
hmacAlg = kCCHmacAlgSHA224;
algStr = "HMACSHA224";
break;
case ALG_SHA256:
hmacAlg = kCCHmacAlgSHA256;
algStr = "HMACSHA256";
break;
case ALG_SHA384:
hmacAlg = kCCHmacAlgSHA384;
algStr = "HMACSHA384";
break;
case ALG_SHA512:
hmacAlg = kCCHmacAlgSHA512;
algStr = "HMACSHA512";
break;
default:
diag("***BRRZAP!\n");
return -1;
}
if(verbose) {
diag("Testing alg %s\n", algStr);
}
for(loop=0; loop < loops; loop++) {
byteBuffer bb = genRandomByteBuffer(minPtextSize, maxPtextSize);
ptextLen = bb->len; ptext = bb->bytes;
if(!keySizeSpec) {
keySizeInBytes = (uint32_t)genRandomSize(MIN_KEY_SIZE, MAX_KEY_SIZE);
}
if(!stagedSpec) {
stagedOrig = isBitSet(1, loop);
stagedClone = isBitSet(2, loop);
}
if(!quiet) {
if(verbose || ((loop % LOOP_NOTIFY) == 0)) {
diag("..loop %d ptextLen %4lu keySize %3lu stagedOrig=%d "
"stagedClone=%d\n",
loop, (unsigned long)ptextLen, (unsigned long)keySizeInBytes,
(int)stagedOrig, (int)stagedClone);
}
}
ok(doHMacCloneTest(ptext, ptextLen, hmacAlg, keySizeInBytes, stagedOrig, stagedClone, quiet, verbose), "HMacClone Test");
free(bb);
if(loops && (loop == loops)) {
break;
}
}
}
if((rtn != 0) && verbose) {
diag("%s test complete\n", argv[0]);
}
return rtn;
}
#endif