crypto/hmac_sha256: add partial progress functions.
authorRusty Russell <rusty@rustcorp.com.au>
Wed, 30 Nov 2016 03:54:23 +0000 (14:24 +1030)
committerRusty Russell <rusty@rustcorp.com.au>
Wed, 30 Nov 2016 03:54:23 +0000 (14:24 +1030)
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
ccan/crypto/hmac_sha256/hmac_sha256.c
ccan/crypto/hmac_sha256/hmac_sha256.h
ccan/crypto/hmac_sha256/test/api-rfc4231.c

index d252295521fe270ea72cfb0bfc21c75f66324c39..0392afe5c1127134e61e48d864dffe94252aeaa8 100644 (file)
@@ -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 */
index 2ddcbe32619a8248a7150f0eb930aa3e20a38c7d..79f1660cdfe75e0dfd35ce8ee47d6ed1fa5584ef 100644 (file)
@@ -6,12 +6,8 @@
 #include <stdlib.h>
 #include <ccan/crypto/sha256/sha256.h>
 
-/* 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 <openssl/hmac.h>
-#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 */
index 0c2b2ee559bd850878bc1ea82757bbc7eb4d16b1..ed99b0eb8978b8998d132f3554df3fcf8d635cd5 100644 (file)
@@ -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);