From ce907a7f849c8cce11083864bf39c84a0f6c7810 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 30 Nov 2016 14:24:23 +1030 Subject: [PATCH 1/1] crypto/hmac_sha256: add partial progress functions. Signed-off-by: Rusty Russell --- ccan/crypto/hmac_sha256/hmac_sha256.c | 70 +++++++++++++++------- ccan/crypto/hmac_sha256/hmac_sha256.h | 64 ++++++++++++++++++-- ccan/crypto/hmac_sha256/test/api-rfc4231.c | 11 +++- 3 files changed, 117 insertions(+), 28 deletions(-) diff --git a/ccan/crypto/hmac_sha256/hmac_sha256.c b/ccan/crypto/hmac_sha256/hmac_sha256.c index d2522955..0392afe5 100644 --- a/ccan/crypto/hmac_sha256/hmac_sha256.c +++ b/ccan/crypto/hmac_sha256/hmac_sha256.c @@ -5,7 +5,7 @@ #define IPAD 0x3636363636363636ULL #define OPAD 0x5C5C5C5C5C5C5C5CULL -#define BLOCK_U64S (64 / sizeof(uint64_t)) +#define BLOCK_U64S (HMAC_SHA256_BLOCKSIZE / sizeof(uint64_t)) static inline void xor_block(uint64_t block[BLOCK_U64S], uint64_t pad) { @@ -15,17 +15,15 @@ static inline void xor_block(uint64_t block[BLOCK_U64S], uint64_t pad) block[i] ^= pad; } -#if 1 -void hmac_sha256(struct hmac_sha256 *hmac, - const void *k, size_t ksize, - const void *d, size_t dsize) +void hmac_sha256_init(struct hmac_sha256_ctx *ctx, + const void *k, size_t ksize) { - struct sha256_ctx shactx; - uint64_t block[BLOCK_U64S]; - struct sha256 hash, hashed_key; + struct sha256 hashed_key; + /* We use k_opad as k_ipad temporarily. */ + uint64_t *k_ipad = ctx->k_opad; /* (keys longer than B bytes are first hashed using H) */ - if (ksize > sizeof(block)) { + if (ksize > HMAC_SHA256_BLOCKSIZE) { sha256(&hashed_key, k, ksize); k = &hashed_key; ksize = sizeof(hashed_key); @@ -37,30 +35,48 @@ void hmac_sha256(struct hmac_sha256 *hmac, * (e.g., if K is of length 20 bytes and B=64, then K will be * appended with 44 zero bytes 0x00) */ - memcpy(block, k, ksize); - memset((char *)block + ksize, 0, sizeof(block) - ksize); + memcpy(k_ipad, k, ksize); + memset((char *)k_ipad + ksize, 0, HMAC_SHA256_BLOCKSIZE - ksize); /* * (2) XOR (bitwise exclusive-OR) the B byte string computed * in step (1) with ipad */ - xor_block(block, IPAD); + xor_block(k_ipad, IPAD); /* + * We start (4) here, appending text later: + * * (3) append the stream of data 'text' to the B byte string resulting * from step (2) * (4) apply H to the stream generated in step (3) */ - sha256_init(&shactx); - sha256_update(&shactx, block, sizeof(block)); - sha256_update(&shactx, d, dsize); - sha256_done(&shactx, &hash); + sha256_init(&ctx->sha); + sha256_update(&ctx->sha, k_ipad, HMAC_SHA256_BLOCKSIZE); /* * (5) XOR (bitwise exclusive-OR) the B byte string computed in * step (1) with opad */ - xor_block(block, IPAD^OPAD); + xor_block(ctx->k_opad, IPAD^OPAD); +} + +void hmac_sha256_update(struct hmac_sha256_ctx *ctx, const void *p, size_t size) +{ + /* This is the appending-text part of this: + * + * (3) append the stream of data 'text' to the B byte string resulting + * from step (2) + * (4) apply H to the stream generated in step (3) + */ + sha256_update(&ctx->sha, p, size); +} + +void hmac_sha256_done(struct hmac_sha256_ctx *ctx, + struct hmac_sha256 *hmac) +{ + /* (4) apply H to the stream generated in step (3) */ + sha256_done(&ctx->sha, &hmac->sha); /* * (6) append the H result from step (4) to the B byte string @@ -68,10 +84,22 @@ void hmac_sha256(struct hmac_sha256 *hmac, * (7) apply H to the stream generated in step (6) and output * the result */ - sha256_init(&shactx); - sha256_update(&shactx, block, sizeof(block)); - sha256_update(&shactx, &hash, sizeof(hash)); - sha256_done(&shactx, &hmac->sha); + sha256_init(&ctx->sha); + sha256_update(&ctx->sha, ctx->k_opad, sizeof(ctx->k_opad)); + sha256_update(&ctx->sha, &hmac->sha, sizeof(hmac->sha)); + sha256_done(&ctx->sha, &hmac->sha); +} + +#if 1 +void hmac_sha256(struct hmac_sha256 *hmac, + const void *k, size_t ksize, + const void *d, size_t dsize) +{ + struct hmac_sha256_ctx ctx; + + hmac_sha256_init(&ctx, k, ksize); + hmac_sha256_update(&ctx, d, dsize); + hmac_sha256_done(&ctx, hmac); } #else /* Direct mapping from MD5 example in RFC2104 */ diff --git a/ccan/crypto/hmac_sha256/hmac_sha256.h b/ccan/crypto/hmac_sha256/hmac_sha256.h index 2ddcbe32..79f1660c 100644 --- a/ccan/crypto/hmac_sha256/hmac_sha256.h +++ b/ccan/crypto/hmac_sha256/hmac_sha256.h @@ -6,12 +6,8 @@ #include #include -/* Uncomment this to use openssl's HMAC routines (and link with -lcrypto) */ -/*#define CCAN_CRYPTO_HMAC_USE_OPENSSL 1*/ - -#ifdef CCAN_CRYPTO_HMAC_USE_OPENSSL -#include -#endif +/* Number of bytes per block. */ +#define HMAC_SHA256_BLOCKSIZE 64 /** * struct hmac_sha256 - structure representing a completed HMAC. @@ -31,4 +27,60 @@ struct hmac_sha256 { void hmac_sha256(struct hmac_sha256 *hmac, const void *k, size_t ksize, const void *d, size_t dsize); + +/** + * struct hmac_sha256_ctx - structure to store running context for hmac_sha256 + */ +struct hmac_sha256_ctx { + struct sha256_ctx sha; + uint64_t k_opad[HMAC_SHA256_BLOCKSIZE / sizeof(uint64_t)]; +}; + +/** + * hmac_sha256_init - initialize an HMAC_SHA256 context. + * @ctx: the hmac_sha256_ctx to initialize + * @k: pointer to the key, + * @ksize: the number of bytes pointed to by @k + * + * This must be called before hmac_sha256_update or hmac_sha256_done. + * + * If it was already initialized, this forgets anything which was + * hashed before. + * + * Example: + * static void hmac_all(const char *key, + * const char **arr, struct hmac_sha256 *hash) + * { + * size_t i; + * struct hmac_sha256_ctx ctx; + * + * hmac_sha256_init(&ctx, key, strlen(key)); + * for (i = 0; arr[i]; i++) + * hmac_sha256_update(&ctx, arr[i], strlen(arr[i])); + * hmac_sha256_done(&ctx, hash); + * } + */ +void hmac_sha256_init(struct hmac_sha256_ctx *ctx, + const void *k, size_t ksize); + +/** + * hmac_sha256_update - include some memory in the hash. + * @ctx: the hmac_sha256_ctx to use + * @p: pointer to memory, + * @size: the number of bytes pointed to by @p + * + * You can call this multiple times to hash more data, before calling + * hmac_sha256_done(). + */ +void hmac_sha256_update(struct hmac_sha256_ctx *ctx, const void *p, size_t size); + +/** + * hmac_sha256_done - finish HMAC_SHA256 and return the hash + * @ctx: the hmac_sha256_ctx to complete + * @res: the hash to return. + * + * Note that @ctx is *destroyed* by this, and must be reinitialized. + * To avoid that, pass a copy instead. + */ +void hmac_sha256_done(struct hmac_sha256_ctx *hmac_sha256, struct hmac_sha256 *res); #endif /* CCAN_CRYPTO_HMAC_SHA256_H */ diff --git a/ccan/crypto/hmac_sha256/test/api-rfc4231.c b/ccan/crypto/hmac_sha256/test/api-rfc4231.c index 0c2b2ee5..ed99b0eb 100644 --- a/ccan/crypto/hmac_sha256/test/api-rfc4231.c +++ b/ccan/crypto/hmac_sha256/test/api-rfc4231.c @@ -129,11 +129,12 @@ int main(void) size_t i; struct hmac_sha256 hmac; - plan_tests(sizeof(tests) / sizeof(tests[0])); + plan_tests(sizeof(tests) / sizeof(tests[0]) * 2); for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { size_t ksize, dsize, hmacsize; void *k, *d, *expect; + struct hmac_sha256_ctx ctx; k = fromhex(tests[i].key, &ksize); d = fromhex(tests[i].data, &dsize); @@ -141,6 +142,14 @@ int main(void) assert(hmacsize == sizeof(hmac)); hmac_sha256(&hmac, k, ksize, d, dsize); ok1(memcmp(&hmac, expect, hmacsize) == 0); + + /* Now test partial API. */ + hmac_sha256_init(&ctx, k, ksize); + hmac_sha256_update(&ctx, d, dsize / 2); + hmac_sha256_update(&ctx, (char *)d + dsize/2, dsize - dsize/2); + hmac_sha256_done(&ctx, &hmac); + ok1(memcmp(&hmac, expect, hmacsize) == 0); + free(k); free(d); free(expect); -- 2.39.2