blob: 40b4487a8b3ebd61b37236facac65acb8d8052ce [file] [log] [blame]
/*
Copyright (C) 2012 Werner Dittmann
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the
* OpenSSL library under certain conditions as described in each
* individual source file, and distribute linked combinations
* including the two.
* You must obey the GNU General Public License in all respects
* for all of the code used other than OpenSSL. If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. If you
* do not wish to do so, delete this exception statement from your
* version. If you delete this exception statement from all source
* files in the program, then also delete it here.
*/
/*
* Authors: Werner Dittmann
*/
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "zrtp/crypto/sha2.h"
#include "zrtp/crypto/hmac384.h"
typedef struct _hmacSha384Context {
sha384_ctx ctx;
sha384_ctx innerCtx;
sha384_ctx outerCtx;
} hmacSha384Context;
static int32_t hmacSha384Init(hmacSha384Context *ctx, const uint8_t *key, uint32_t kLength)
{
int32_t i;
uint8_t localPad[SHA384_BLOCK_SIZE] = {0};
uint8_t localKey[SHA384_BLOCK_SIZE] = {0};
if (key == NULL)
return 0;
memset(ctx, 0, sizeof(hmacSha384Context));
/* check key length and reduce it if necessary */
if (kLength > SHA384_BLOCK_SIZE) {
sha384_begin(&ctx->ctx);
sha384_hash(key, kLength, &ctx->ctx);
sha384_end(localKey, &ctx->ctx);
}
else {
memcpy(localKey, key, kLength);
}
/* prepare inner hash and hold the context */
for (i = 0; i < SHA384_BLOCK_SIZE; i++)
localPad[i] = localKey[i] ^ 0x36;
sha384_begin(&ctx->innerCtx);
sha384_hash(localPad, SHA384_BLOCK_SIZE, &ctx->innerCtx);
/* prepare outer hash and hold the context */
for (i = 0; i < SHA384_BLOCK_SIZE; i++)
localPad[i] = localKey[i] ^ 0x5c;
sha384_begin(&ctx->outerCtx);
sha384_hash(localPad, SHA384_BLOCK_SIZE, &ctx->outerCtx);
/* copy prepared inner hash to work hash - ready to process data */
memcpy(&ctx->ctx, &ctx->innerCtx, sizeof(sha384_ctx));
memset(localKey, 0, sizeof(localKey));
return 1;
}
static void hmacSha384Reset(hmacSha384Context *ctx)
{
/* copy prepared inner hash to work hash context */
memcpy(&ctx->ctx, &ctx->innerCtx, sizeof(sha384_ctx));
}
static void hmacSha384Update(hmacSha384Context *ctx, const uint8_t *data, uint32_t dLength)
{
/* hash new data to work hash context */
sha384_hash(data, dLength, &ctx->ctx);
}
static void hmacSha384Final(hmacSha384Context *ctx, uint8_t *mac)
{
uint8_t tmpDigest[SHA384_DIGEST_SIZE];
/* finalize work hash context */
sha384_end(tmpDigest, &ctx->ctx);
/* copy prepared outer hash to work hash */
memcpy(&ctx->ctx, &ctx->outerCtx, sizeof(sha384_ctx));
/* hash inner digest to work (outer) hash context */
sha384_hash(tmpDigest, SHA384_DIGEST_SIZE, &ctx->ctx);
/* finalize work hash context to get the hmac*/
sha384_end(mac, &ctx->ctx);
}
void hmac_sha384(uint8_t *key, uint32_t keyLength, uint8_t* data, int32_t dataLength, uint8_t* mac, uint32_t* macLength)
{
hmacSha384Context ctx;
hmacSha384Init(&ctx, key, keyLength);
hmacSha384Update(&ctx, data, dataLength);
hmacSha384Final(&ctx, mac);
*macLength = SHA384_BLOCK_SIZE;
}
void hmac_sha384( uint8_t* key, uint32_t keyLength, uint8_t* dataChunks[], uint32_t dataChunckLength[],
uint8_t* mac, uint32_t* macLength )
{
hmacSha384Context ctx;
hmacSha384Init(&ctx, key, keyLength);
while (*dataChunks) {
hmacSha384Update(&ctx, *dataChunks, *dataChunckLength);
dataChunks ++;
dataChunckLength ++;
}
hmacSha384Final(&ctx, mac);
*macLength = SHA384_BLOCK_SIZE;
}
void* createSha384HmacContext(uint8_t* key, int32_t keyLength)
{
hmacSha384Context *ctx = reinterpret_cast<hmacSha384Context*>(malloc(sizeof(hmacSha384Context)));
hmacSha384Init(ctx, key, keyLength);
return ctx;
}
void hmacSha384Ctx(void* ctx, const uint8_t* data, uint32_t dataLength,
uint8_t* mac, int32_t* macLength)
{
hmacSha384Context *pctx = (hmacSha384Context*)ctx;
hmacSha384Reset(pctx);
hmacSha384Update(pctx, data, dataLength);
hmacSha384Final(pctx, mac);
*macLength = SHA384_BLOCK_SIZE;
}
void hmacSha384Ctx(void* ctx, const uint8_t* data[], uint32_t dataLength[],
uint8_t* mac, int32_t* macLength )
{
hmacSha384Context *pctx = (hmacSha384Context*)ctx;
hmacSha384Reset(pctx);
while (*data) {
hmacSha384Update(pctx, *data, *dataLength);
data++;
dataLength++;
}
hmacSha384Final(pctx, mac);
*macLength = SHA384_BLOCK_SIZE;
}
void freeSha384HmacContext(void* ctx)
{
if (ctx) {
memset(ctx, 0, sizeof(hmacSha384Context));
free(ctx);
}
}