From: Pavel TvrdĂ­k Date: Wed, 29 Apr 2015 11:39:32 +0000 (+0200) Subject: HMAC-SHA256, HMAC-SHA224 according to HMAC-SHA1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e7ac4efd54c9c28c81131023913830c08ff223fd;p=thirdparty%2Fbird.git HMAC-SHA256, HMAC-SHA224 according to HMAC-SHA1 Successfully passed unit tests. --- diff --git a/lib/sha256.c b/lib/sha256.c index bfd6a29c3..f7be5b89f 100644 --- a/lib/sha256.c +++ b/lib/sha256.c @@ -342,120 +342,124 @@ sha256_final(sha256_context *ctx) return ctx->buf; } - /** - * HMAC + * SHA256-HMAC */ -/* Create a new context. On error NULL is returned and errno is set - appropriately. If KEY is given the function computes HMAC using - this key; with KEY given as NULL, a plain SHA-256 digest is - computed. */ -void -sha256_hmac_init(sha256_hmac_context *ctx, const void *key, size_t keylen) +static void +sha256_hash_buffer(byte *outbuf, const byte *buffer, size_t length) { - sha256_init(&ctx->ctx); + sha256_context hd_tmp; - ctx->finalized = 0; - ctx->use_hmac = 0; + sha256_init(&hd_tmp); + sha256_update(&hd_tmp, buffer, length); + memcpy(outbuf, sha256_final(&hd_tmp), SHA256_SIZE); +} - if (key) +void +sha256_hmac_init(sha256_hmac_context *ctx, const byte *key, size_t keylen) +{ + byte keybuf[SHA256_BLOCK_SIZE], buf[SHA256_BLOCK_SIZE]; + + // Hash the key if necessary + if (keylen <= SHA256_BLOCK_SIZE) + { + memcpy(keybuf, key, keylen); + bzero(keybuf + keylen, SHA256_BLOCK_SIZE - keylen); + } + else { - int i; - unsigned char ipad[64]; - - memset(ipad, 0, 64); - memset(ctx->opad, 0, 64); - if (keylen <= 64) - { - memcpy(ipad, key, keylen); - memcpy(ctx->opad, key, keylen); - } - else - { - sha256_hmac_context tmp_ctx; - - sha256_hmac_init(&tmp_ctx, NULL, 0); - sha256_hmac_update(&tmp_ctx, key, keylen); - sha256_final(&tmp_ctx.ctx); - memcpy(ipad, tmp_ctx.ctx.buf, 32); - memcpy(ctx->opad, tmp_ctx.ctx.buf, 32); - } - for(i=0; i < 64; i++) - { - ipad[i] ^= 0x36; - ctx->opad[i] ^= 0x5c; - } - ctx->use_hmac = 1; - sha256_hmac_update(ctx, ipad, 64); + sha256_hash_buffer(keybuf, key, keylen); + bzero(keybuf + SHA256_SIZE, SHA256_BLOCK_SIZE - SHA256_SIZE); } + + // Initialize the inner digest + sha256_init(&ctx->ictx); + int i; + for (i = 0; i < SHA256_BLOCK_SIZE; i++) + buf[i] = keybuf[i] ^ 0x36; + sha256_update(&ctx->ictx, buf, SHA256_BLOCK_SIZE); + + // Initialize the outer digest + sha256_init(&ctx->octx); + for (i = 0; i < SHA256_BLOCK_SIZE; i++) + buf[i] = keybuf[i] ^ 0x5c; + sha256_update(&ctx->octx, buf, SHA256_BLOCK_SIZE); } -void sha224_hmac_init(sha224_hmac_context *ctx, const void *key, size_t keylen) +void sha256_hmac_update(sha256_hmac_context *ctx, const byte *buf, size_t buflen) { - sha224_init(&ctx->ctx); + // Just update the inner digest + sha256_update(&ctx->ictx, buf, buflen); +} - ctx->finalized = 0; - ctx->use_hmac = 0; +byte *sha256_hmac_final(sha256_hmac_context *hd) +{ + // Finish the inner digest + byte *isha = sha256_final(&hd->ictx); - if (key) - { - int i; - unsigned char ipad[64]; - - memset(ipad, 0, 64); - memset(ctx->opad, 0, 64); - if (keylen <= 64) - { - memcpy(ipad, key, keylen); - memcpy(ctx->opad, key, keylen); - } - else - { - sha224_hmac_context tmp_ctx; - - sha224_hmac_init(&tmp_ctx, NULL, 0); - sha224_hmac_update(&tmp_ctx, key, keylen); - sha224_final(&tmp_ctx.ctx); - memcpy(ipad, tmp_ctx.ctx.buf, 32); - memcpy(ctx->opad, tmp_ctx.ctx.buf, 32); - } - for(i=0; i < 64; i++) - { - ipad[i] ^= 0x36; - ctx->opad[i] ^= 0x5c; - } - ctx->use_hmac = 1; - sha224_hmac_update(ctx, ipad, 64); - } + // Finish the outer digest + sha256_update(&hd->octx, isha, SHA256_SIZE); + return sha256_final(&hd->octx); } -/* Update the message digest with the contents of BUFFER containing - LENGTH bytes. */ -void -sha256_hmac_update(sha256_hmac_context *ctx, const void *buffer, size_t length) +/** + * SHA224-HMAC + */ + +static void +sha224_hash_buffer(byte *outbuf, const byte *buffer, size_t length) { - sha256_update(&ctx->ctx, buffer, length); + sha224_context hd_tmp; + + sha224_init(&hd_tmp); + sha224_update(&hd_tmp, buffer, length); + memcpy(outbuf, sha224_final(&hd_tmp), SHA224_SIZE); } -/* Finalize an operation and return the digest. If R_DLEN is not NULL - the length of the digest will be stored at that address. The - returned value is valid as long as the context exists. On error - NULL is returned. */ -byte * -sha256_hmac_final(sha256_hmac_context *ctx) +void +sha224_hmac_init(sha224_hmac_context *ctx, const byte *key, size_t keylen) { - sha256_final(&ctx->ctx); - if (ctx->use_hmac) - { - sha256_hmac_context tmp_ctx; + byte keybuf[SHA224_BLOCK_SIZE], buf[SHA224_BLOCK_SIZE]; - sha256_hmac_init(&tmp_ctx, NULL, 0); - sha256_hmac_update(&tmp_ctx, ctx->opad, 64); - sha256_hmac_update(&tmp_ctx, ctx->ctx.buf, 32); - sha256_final(&tmp_ctx.ctx); - memcpy(ctx->ctx.buf, tmp_ctx.ctx.buf, 32); + // Hash the key if necessary + if (keylen <= SHA224_BLOCK_SIZE) + { + memcpy(keybuf, key, keylen); + bzero(keybuf + keylen, SHA224_BLOCK_SIZE - keylen); + } + else + { + sha224_hash_buffer(keybuf, key, keylen); + bzero(keybuf + SHA224_SIZE, SHA224_BLOCK_SIZE - SHA224_SIZE); } - return ctx->ctx.buf; + + // Initialize the inner digest + sha224_init(&ctx->ictx); + int i; + for (i = 0; i < SHA224_BLOCK_SIZE; i++) + buf[i] = keybuf[i] ^ 0x36; + sha224_update(&ctx->ictx, buf, SHA224_BLOCK_SIZE); + + // Initialize the outer digest + sha224_init(&ctx->octx); + for (i = 0; i < SHA224_BLOCK_SIZE; i++) + buf[i] = keybuf[i] ^ 0x5c; + sha224_update(&ctx->octx, buf, SHA224_BLOCK_SIZE); +} + +void sha224_hmac_update(sha224_hmac_context *ctx, const byte *buf, size_t buflen) +{ + // Just update the inner digest + sha256_update(&ctx->ictx, buf, buflen); } +byte *sha224_hmac_final(sha224_hmac_context *hd) +{ + // Finish the inner digest + byte *isha = sha224_final(&hd->ictx); + + // Finish the outer digest + sha224_update(&hd->octx, isha, SHA224_SIZE); + return sha224_final(&hd->octx); +} diff --git a/lib/sha256.h b/lib/sha256.h index 180cec4f9..bdbc980d2 100644 --- a/lib/sha256.h +++ b/lib/sha256.h @@ -14,15 +14,17 @@ #include "sysdep/config.h" -#define SHA256_SIZE 32 -#define SHA256_HEX_SIZE 65 - #define SHA224_SIZE 28 #define SHA224_HEX_SIZE 57 +#define SHA224_BLOCK_SIZE 64 + +#define SHA256_SIZE 32 +#define SHA256_HEX_SIZE 65 +#define SHA256_BLOCK_SIZE 64 typedef struct { u32 h0,h1,h2,h3,h4,h5,h6,h7; - byte buf[128]; + byte buf[128]; /* 128 is for SHA384 and SHA512 support, otherwise for SHA224 and SHA256 is 64 enough */ u32 nblocks; u32 nblocks_high; int count; @@ -46,30 +48,22 @@ byte* sha224_final(sha224_context *ctx) } /** - * HMAC-SHA256 & HMAC-SHA224 + * HMAC-SHA256, HMAC-SHA224 */ typedef struct { - sha256_context ctx; - int finalized:1; - int use_hmac:1; - byte opad[64]; + sha256_context ictx; + sha256_context octx; } sha256_hmac_context; typedef sha256_hmac_context sha224_hmac_context; -void sha256_hmac_init(sha256_hmac_context *ctx, const void *key, size_t keylen); -void sha224_hmac_init(sha224_hmac_context *ctx, const void *key, size_t keylen); +void sha256_hmac_init(sha256_hmac_context *ctx, const byte *key, size_t keylen); +void sha224_hmac_init(sha224_hmac_context *ctx, const byte *key, size_t keylen); -void sha256_hmac_update(sha256_hmac_context *ctx, const void *buf, size_t buflen); -void sha224_hmac_update(sha224_hmac_context *ctx, const void *buf, size_t buflen) -{ - sha256_hmac_update(ctx, buf, buflen); -} +void sha256_hmac_update(sha256_hmac_context *ctx, const byte *buf, size_t buflen); +void sha224_hmac_update(sha224_hmac_context *ctx, const byte *buf, size_t buflen); byte *sha256_hmac_final(sha256_hmac_context *ctx); -byte *sha224_hmac_final(sha224_hmac_context *ctx) -{ - return sha256_hmac_final(ctx); -} +byte *sha224_hmac_final(sha224_hmac_context *ctx); #endif /* _BIRD_SHA256_H_ */ diff --git a/lib/sha256_hmac.h b/lib/sha256_hmac.h deleted file mode 100644 index cc90357ea..000000000 --- a/lib/sha256_hmac.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * BIRD -- HMAC-SHA256 Message Authentication - * - * (c) 2015 CZ.NIC z.s.p.o. - * - * Based on the code from libgcrypt-1.6.0, which is - * (c) 2003, 2006, 2008, 2009 Free Software Foundation, Inc. - * - * Can be freely distributed and used under the terms of the GNU GPL. - */ - -#ifndef _BIRD_SHA256_HMAC_H_ -#define _BIRD_SHA256_HMAC_H_ - -#define SHA256_SIZE 32 -#define SHA256_HEX_SIZE 65 - -#define SHA224_SIZE 28 -#define SHA224_HEX_SIZE 57 - -/* The context used by this module. */ -typedef struct -{ - u32 h0, h1, h2, h3, h4, h5, h6, h7; - u32 nblocks; - int count; - int finalized:1; - int use_hmac:1; - byte buf[64]; - byte opad[64]; -} sha256_hmac_context; - -void sha256_hmac_init(sha256_hmac_context *ctx, const void *key, size_t keylen); -void sha256_hmac_update(sha256_hmac_context *ctx, const void *buf, size_t buflen); -const byte *sha256_hmac_final(sha256_hmac_context *ctx); - -#endif /* _BIRD_SHA256_HMAC_H_ */ diff --git a/lib/sha256_test.c b/lib/sha256_test.c index 3aeab677a..e4e3ac18a 100644 --- a/lib/sha256_test.c +++ b/lib/sha256_test.c @@ -149,7 +149,6 @@ t_sha256_concating(void) return BT_SUCCESS; } - #define HMAC_BUFFER_SIZE 160 struct hmac_data_in { byte key[HMAC_BUFFER_SIZE]; @@ -169,13 +168,13 @@ get_sha256_hmac(const struct hmac_data_in in, char (*out_hash)[SHA256_HEX_SIZE]) } static void -get_sha224_hmac(const struct hmac_data_in in, char (*out_hash)[SHA256_HEX_SIZE]) +get_sha224_hmac(const struct hmac_data_in in, char (*out_hash)[SHA224_HEX_SIZE]) { sha224_hmac_context ctx; sha224_hmac_init(&ctx, in.key, in.key_len); sha224_hmac_update(&ctx, in.data, in.data_len); byte *hash_byte = sha224_hmac_final(&ctx); - byte_to_hex((char*)out_hash, hash_byte, SHA224_HEX_SIZE); + byte_to_hex((char*)out_hash, hash_byte, SHA224_SIZE); } @@ -317,7 +316,7 @@ t_sha224_hmac(void) { struct in_out { struct hmac_data_in in; - char out[SHA256_HEX_SIZE]; + char out[SHA224_HEX_SIZE]; } in_out[] = { { .in = { @@ -387,7 +386,7 @@ t_sha224_hmac(void) .data = "Test With Truncation", .data_len = 20, }, - .out = "0e2aea68a90c8d37c988bcdb9fca6fa8", + .out = "0e2aea68a90c8d37c988bcdb9fca6fa8099cd857c7ec4a1815cac54c", }, { .in = {