blob: 1e3ceb7d6ea4ee70aaca1d364d9c4117d03fd51f [file] [log] [blame]
/*
Copyright (C) 2012-2013 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/hmac256.h"
typedef struct _hmacSha256Context {
sha256_ctx ctx;
sha256_ctx innerCtx;
sha256_ctx outerCtx;
} hmacSha256Context;
static int32_t hmacSha256Init(hmacSha256Context *ctx, const uint8_t *key, uint32_t kLength)
{
int32_t i;
uint8_t localPad[SHA256_BLOCK_SIZE] = {0};
uint8_t localKey[SHA256_BLOCK_SIZE] = {0};
if (key == NULL)
return 0;
memset(ctx, 0, sizeof(hmacSha256Context));
/* check key length and reduce it if necessary */
if (kLength > SHA256_BLOCK_SIZE) {
sha256_begin(&ctx->ctx);
sha256_hash(key, kLength, &ctx->ctx);
sha256_end(localKey, &ctx->ctx);
}
else {
memcpy(localKey, key, kLength);
}
/* prepare inner hash and hold the context */
for (i = 0; i < SHA256_BLOCK_SIZE; i++)
localPad[i] = localKey[i] ^ 0x36;
sha256_begin(&ctx->innerCtx);
sha256_hash(localPad, SHA256_BLOCK_SIZE, &ctx->innerCtx);
/* prepare outer hash and hold the context */
for (i = 0; i < SHA256_BLOCK_SIZE; i++)
localPad[i] = localKey[i] ^ 0x5c;
sha256_begin(&ctx->outerCtx);
sha256_hash(localPad, SHA256_BLOCK_SIZE, &ctx->outerCtx);
/* copy prepared inner hash to work hash - ready to process data */
memcpy(&ctx->ctx, &ctx->innerCtx, sizeof(sha256_ctx));
memset(localKey, 0, sizeof(localKey));
return 1;
}
static void hmacSha256Reset(hmacSha256Context *ctx)
{
/* copy prepared inner hash to work hash context */
memcpy(&ctx->ctx, &ctx->innerCtx, sizeof(sha256_ctx));
}
static void hmacSha256Update(hmacSha256Context *ctx, const uint8_t *data, uint32_t dLength)
{
/* hash new data to work hash context */
sha256_hash(data, dLength, &ctx->ctx);
}
static void hmacSha256Final(hmacSha256Context *ctx, uint8_t *mac)
{
uint8_t tmpDigest[SHA256_DIGEST_SIZE];
/* finalize work hash context */
sha256_end(tmpDigest, &ctx->ctx);
/* copy prepared outer hash to work hash */
memcpy(&ctx->ctx, &ctx->outerCtx, sizeof(sha256_ctx));
/* hash inner digest to work (outer) hash context */
sha256_hash(tmpDigest, SHA256_DIGEST_SIZE, &ctx->ctx);
/* finalize work hash context to get the hmac*/
sha256_end(mac, &ctx->ctx);
}
void hmac_sha256(uint8_t *key, uint32_t keyLength, uint8_t* data, int32_t dataLength, uint8_t* mac, uint32_t* macLength)
{
hmacSha256Context ctx;
hmacSha256Init(&ctx, key, keyLength);
hmacSha256Update(&ctx, data, dataLength);
hmacSha256Final(&ctx, mac);
*macLength = SHA256_DIGEST_SIZE;
}
void hmac_sha256(uint8_t* key, uint32_t keyLength, uint8_t* dataChunks[], uint32_t dataChunckLength[],
uint8_t* mac, uint32_t* macLength )
{
hmacSha256Context ctx;
hmacSha256Init(&ctx, key, keyLength);
while (*dataChunks) {
hmacSha256Update(&ctx, *dataChunks, *dataChunckLength);
dataChunks ++;
dataChunckLength ++;
}
hmacSha256Final(&ctx, mac);
*macLength = SHA256_DIGEST_SIZE;
}
void* createSha256HmacContext(uint8_t* key, int32_t keyLength)
{
hmacSha256Context *ctx = reinterpret_cast<hmacSha256Context*>(malloc(sizeof(hmacSha256Context)));
hmacSha256Init(ctx, key, keyLength);
return ctx;
}
void hmacSha256Ctx(void* ctx, const uint8_t* data, uint32_t dataLength,
uint8_t* mac, int32_t* macLength)
{
hmacSha256Context *pctx = (hmacSha256Context*)ctx;
hmacSha256Reset(pctx);
hmacSha256Update(pctx, data, dataLength);
hmacSha256Final(pctx, mac);
*macLength = SHA256_DIGEST_SIZE;
}
void hmacSha256Ctx(void* ctx, const uint8_t* data[], uint32_t dataLength[],
uint8_t* mac, int32_t* macLength )
{
hmacSha256Context *pctx = (hmacSha256Context*)ctx;
hmacSha256Reset(pctx);
while (*data) {
hmacSha256Update(pctx, *data, *dataLength);
data++;
dataLength++;
}
hmacSha256Final(pctx, mac);
*macLength = SHA256_DIGEST_SIZE;
}
void freeSha256HmacContext(void* ctx)
{
if (ctx) {
memset(ctx, 0, sizeof(hmacSha256Context));
free(ctx);
}
}