#include <CommonCrypto/CommonHMAC.h>
#include <strings.h>
#include <stdlib.h>
#include <assert.h>
#ifndef NDEBUG
#define ASSERT(s)
#else
#define ASSERT(s) assert(s)
#endif
typedef void (*ccDigestInit)(void *ctx);
typedef void (*ccDigestUpdate)(void *ctx, const void *data, CC_LONG len);
typedef void (*ccDigestFinal)(unsigned char *md, void *ctx);
#define HMAC_MAX_BLOCK_SIZE CC_SHA512_BLOCK_BYTES
#define HMAC_MAX_DIGEST_SIZE CC_SHA512_DIGEST_LENGTH
typedef struct {
uint32_t digestLen;
uint32_t blockLen;
union {
CC_MD5_CTX md5Ctx;
CC_SHA1_CTX sha1Ctx;
CC_SHA256_CTX sha256Ctx;
CC_SHA512_CTX sha512Ctx;
} digest;
uint8_t k_opad[HMAC_MAX_BLOCK_SIZE];
ccDigestInit digestInit;
ccDigestUpdate digestUpdate;
ccDigestFinal digestFinal;
} _CCHmacContext;
void CCHmacInit(
CCHmacContext *ctx,
CCHmacAlgorithm algorithm,
const void *key,
size_t keyLength)
{
_CCHmacContext *hmacCtx = (_CCHmacContext *)ctx;
uint8_t tk[HMAC_MAX_DIGEST_SIZE];
uint8_t *keyP;
uint32_t byte;
uint8_t k_ipad[HMAC_MAX_BLOCK_SIZE];
ASSERT(sizeof(_CCHmacContext) < sizeof(CCHmacContext));
if(hmacCtx == NULL) {
return;
}
memset(hmacCtx, 0, sizeof(*hmacCtx));
switch(algorithm) {
case kCCHmacAlgMD5:
hmacCtx->digestLen = CC_MD5_DIGEST_LENGTH;
hmacCtx->blockLen = CC_MD5_BLOCK_BYTES;
hmacCtx->digestInit = (void *)CC_MD5_Init;
hmacCtx->digestUpdate = (void *)CC_MD5_Update;
hmacCtx->digestFinal = (void *)CC_MD5_Final;
break;
case kCCHmacAlgSHA1:
hmacCtx->digestLen = CC_SHA1_DIGEST_LENGTH;
hmacCtx->blockLen = CC_SHA1_BLOCK_BYTES;
hmacCtx->digestInit = (void *)CC_SHA1_Init;
hmacCtx->digestUpdate = (void *)CC_SHA1_Update;
hmacCtx->digestFinal = (void *)CC_SHA1_Final;
break;
case kCCHmacAlgSHA224:
hmacCtx->digestLen = CC_SHA224_DIGEST_LENGTH;
hmacCtx->blockLen = CC_SHA224_BLOCK_BYTES;
hmacCtx->digestInit = (void *)CC_SHA224_Init;
hmacCtx->digestUpdate = (void *)CC_SHA224_Update;
hmacCtx->digestFinal = (void *)CC_SHA224_Final;
break;
case kCCHmacAlgSHA256:
hmacCtx->digestLen = CC_SHA256_DIGEST_LENGTH;
hmacCtx->blockLen = CC_SHA256_BLOCK_BYTES;
hmacCtx->digestInit = (void *)CC_SHA256_Init;
hmacCtx->digestUpdate = (void *)CC_SHA256_Update;
hmacCtx->digestFinal = (void *)CC_SHA256_Final;
break;
case kCCHmacAlgSHA384:
hmacCtx->digestLen = CC_SHA384_DIGEST_LENGTH;
hmacCtx->blockLen = CC_SHA384_BLOCK_BYTES;
hmacCtx->digestInit = (void *)CC_SHA384_Init;
hmacCtx->digestUpdate = (void *)CC_SHA384_Update;
hmacCtx->digestFinal = (void *)CC_SHA384_Final;
break;
case kCCHmacAlgSHA512:
hmacCtx->digestLen = CC_SHA512_DIGEST_LENGTH;
hmacCtx->blockLen = CC_SHA512_BLOCK_BYTES;
hmacCtx->digestInit = (void *)CC_SHA512_Init;
hmacCtx->digestUpdate = (void *)CC_SHA512_Update;
hmacCtx->digestFinal = (void *)CC_SHA512_Final;
break;
default:
return;
}
hmacCtx->digestInit(&hmacCtx->digest);
if (keyLength <= hmacCtx->blockLen)
keyP = (uint8_t *)key;
else {
hmacCtx->digestUpdate(&hmacCtx->digest, key, keyLength);
hmacCtx->digestFinal(tk, &hmacCtx->digest);
keyP = tk;
keyLength = hmacCtx->digestLen;
hmacCtx->digestInit(&hmacCtx->digest);
}
for (byte = 0; byte < keyLength; byte++)
{
k_ipad[byte] = keyP[byte] ^ 0x36;
hmacCtx->k_opad[byte] = keyP[byte] ^ 0x5c;
}
if (keyLength < hmacCtx->blockLen)
{
memset (k_ipad + keyLength, 0x36, hmacCtx->blockLen - keyLength);
memset (hmacCtx->k_opad + keyLength, 0x5c, hmacCtx->blockLen - keyLength);
}
hmacCtx->digestUpdate(&hmacCtx->digest, k_ipad, hmacCtx->blockLen);
}
void CCHmacUpdate(
CCHmacContext *ctx,
const void *dataIn,
size_t dataInLength)
{
_CCHmacContext *hmacCtx = (_CCHmacContext *)ctx;
hmacCtx->digestUpdate(&hmacCtx->digest, dataIn, dataInLength);
}
void CCHmacFinal(
CCHmacContext *ctx,
void *macOut)
{
_CCHmacContext *hmacCtx = (_CCHmacContext *)ctx;
hmacCtx->digestFinal(macOut, &hmacCtx->digest);
hmacCtx->digestInit(&hmacCtx->digest);
hmacCtx->digestUpdate(&hmacCtx->digest, hmacCtx->k_opad, hmacCtx->blockLen);
hmacCtx->digestUpdate(&hmacCtx->digest, macOut, hmacCtx->digestLen);
hmacCtx->digestFinal(macOut, &hmacCtx->digest);
}
void CCHmac(
CCHmacAlgorithm algorithm,
const void *key,
size_t keyLength,
const void *data,
size_t dataLength,
void *macOut)
{
CCHmacContext ctx;
CCHmacInit(&ctx, algorithm, key, keyLength);
CCHmacUpdate(&ctx, data, dataLength);
CCHmacFinal(&ctx, macOut);
}