blob: 38028a372ea1bc5bd2237ef697ec0d4aa80d7a27 [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 "crypto/sha1.h"
#include "crypto/hmac.h"
typedef struct _hmacSha1Context {
sha1_ctx ctx;
sha1_ctx innerCtx;
sha1_ctx outerCtx;
} hmacSha1Context;
static int32_t hmacSha1Init(hmacSha1Context *ctx, const uint8_t *key, uint32_t kLength)
{
int32_t i;
uint8_t localPad[SHA1_BLOCK_SIZE] = {0};
uint8_t localKey[SHA1_BLOCK_SIZE] = {0};
if (key == NULL)
return 0;
memset(ctx, 0, sizeof(hmacSha1Context));
/* check key length and reduce it if necessary */
if (kLength > SHA1_BLOCK_SIZE) {
sha1_begin(&ctx->ctx);
sha1_hash(key, kLength, &ctx->ctx);
sha1_end(localKey, &ctx->ctx);
}
else {
memcpy(localKey, key, kLength);
}
/* prepare inner hash and hold the context */
for (i = 0; i < SHA1_BLOCK_SIZE; i++)
localPad[i] = localKey[i] ^ 0x36;
sha1_begin(&ctx->innerCtx);
sha1_hash(localPad, SHA1_BLOCK_SIZE, &ctx->innerCtx);
/* prepare outer hash and hold the context */
for (i = 0; i < SHA1_BLOCK_SIZE; i++)
localPad[i] = localKey[i] ^ 0x5c;
sha1_begin(&ctx->outerCtx);
sha1_hash(localPad, SHA1_BLOCK_SIZE, &ctx->outerCtx);
/* copy prepared inner hash to work hash - ready to process data */
memcpy(&ctx->ctx, &ctx->innerCtx, sizeof(sha1_ctx));
memset(localKey, 0, sizeof(localKey));
return 1;
}
static void hmacSha1Reset(hmacSha1Context *ctx)
{
/* copy prepared inner hash to work hash context */
memcpy(&ctx->ctx, &ctx->innerCtx, sizeof(sha1_ctx));
}
static void hmacSha1Update(hmacSha1Context *ctx, const uint8_t *data, uint32_t dLength)
{
/* hash new data to work hash context */
sha1_hash(data, dLength, &ctx->ctx);
}
static void hmacSha1Final(hmacSha1Context *ctx, uint8_t *mac)
{
uint8_t tmpDigest[SHA1_DIGEST_SIZE];
/* finalize work hash context */
sha1_end(tmpDigest, &ctx->ctx);
/* copy prepared outer hash to work hash */
memcpy(&ctx->ctx, &ctx->outerCtx, sizeof(sha1_ctx));
/* hash inner digest to work (outer) hash context */
sha1_hash(tmpDigest, SHA1_DIGEST_SIZE, &ctx->ctx);
/* finalize work hash context to get the hmac*/
sha1_end(mac, &ctx->ctx);
}
void hmac_sha1(uint8_t *key, int32_t keyLength, const uint8_t* data, uint32_t dataLength, uint8_t* mac, int32_t* macLength)
{
hmacSha1Context ctx;
hmacSha1Init(&ctx, key, keyLength);
hmacSha1Update(&ctx, data, dataLength);
hmacSha1Final(&ctx, mac);
*macLength = SHA1_BLOCK_SIZE;
}
void hmac_sha1( uint8_t* key, int32_t keyLength, const uint8_t* dataChunks[], uint32_t dataChunckLength[],
uint8_t* mac, int32_t* macLength )
{
hmacSha1Context ctx;
hmacSha1Init(&ctx, key, keyLength);
while (*dataChunks) {
hmacSha1Update(&ctx, *dataChunks, *dataChunckLength);
dataChunks ++;
dataChunckLength ++;
}
hmacSha1Final(&ctx, mac);
*macLength = SHA1_BLOCK_SIZE;
}
void* createSha1HmacContext(uint8_t* key, int32_t keyLength)
{
hmacSha1Context *ctx = reinterpret_cast<hmacSha1Context*>(malloc(sizeof(hmacSha1Context)));
hmacSha1Init(ctx, key, keyLength);
return ctx;
}
void hmacSha1Ctx(void* ctx, const uint8_t* data, uint32_t dataLength,
uint8_t* mac, int32_t* macLength)
{
hmacSha1Context *pctx = (hmacSha1Context*)ctx;
hmacSha1Reset(pctx);
hmacSha1Update(pctx, data, dataLength);
hmacSha1Final(pctx, mac);
*macLength = SHA1_BLOCK_SIZE;
}
void hmacSha1Ctx(void* ctx, const uint8_t* data[], uint32_t dataLength[],
uint8_t* mac, int32_t* macLength )
{
hmacSha1Context *pctx = (hmacSha1Context*)ctx;
hmacSha1Reset(pctx);
while (*data) {
hmacSha1Update(pctx, *data, *dataLength);
data++;
dataLength++;
}
hmacSha1Final(pctx, mac);
*macLength = SHA1_BLOCK_SIZE;
}
void freeSha1HmacContext(void* ctx)
{
if (ctx) {
memset(ctx, 0, sizeof(hmacSha1Context));
free(ctx);
}
}