Provide alternative HMAC interface, with context struct having just derived key and single hash state instead of three hash states at once.
Signed-off-by: Dmitry Eremin-Solenikov dbaryshkov@gmail.com --- hmac.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ hmac.h | 32 ++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+)
diff --git a/hmac.c b/hmac.c index 6ac5e11a0686..6d57f8c9197c 100644 --- a/hmac.c +++ b/hmac.c @@ -115,3 +115,69 @@ hmac_digest(const void *outer, const void *inner, void *state,
memcpy(state, inner, hash->context_size); } + +static void +hmac2_reinit_state(void *state, void *derived_key, + const struct nettle_hash *hash, + uint8_t padc) +{ + TMP_DECL(pad, uint8_t, NETTLE_MAX_HASH_BLOCK_SIZE); + TMP_ALLOC(pad, hash->block_size); + + memset(pad, padc, hash->block_size); + memxor(pad, derived_key, hash->block_size); + + hash->init(state); + hash->update(state, hash->block_size, pad); +} + +void +hmac2_set_key(void *state, void *derived_key, + const struct nettle_hash *hash, + size_t key_length, const uint8_t *key) +{ + memset(derived_key, 0, hash->block_size); + + if (key_length > hash->block_size) + { + assert(hash->digest_size <= hash->block_size); + + /* Reduce key to the algorithm's hash size. Use the area pointed + * to by state for the temporary state. */ + hash->init(state); + hash->update(state, key_length, key); + hash->digest(state, hash->digest_size, derived_key); + } + else + { + memcpy(derived_key, key, key_length); + } + + hmac2_reinit_state(state, derived_key, hash, IPAD); +} + +void +hmac2_update(void *state, + const struct nettle_hash *hash, + size_t length, const uint8_t *data) +{ + hash->update(state, length, data); +} + +void +hmac2_digest(void *state, void *derived_key, + const struct nettle_hash *hash, + size_t length, uint8_t *dst) +{ + TMP_DECL(digest, uint8_t, NETTLE_MAX_HASH_DIGEST_SIZE); + TMP_ALLOC(digest, hash->digest_size); + + hash->digest(state, hash->digest_size, digest); + + hmac2_reinit_state(state, derived_key, hash, OPAD); + + hash->update(state, hash->digest_size, digest); + hash->digest(state, length, dst); + + hmac2_reinit_state(state, derived_key, hash, IPAD); +} diff --git a/hmac.h b/hmac.h index 40a8e77aab6d..29a2798ffc21 100644 --- a/hmac.h +++ b/hmac.h @@ -49,6 +49,9 @@ extern "C" { #define hmac_set_key nettle_hmac_set_key #define hmac_update nettle_hmac_update #define hmac_digest nettle_hmac_digest +#define hmac2_set_key nettle_hmac2_set_key +#define hmac2_update nettle_hmac2_update +#define hmac2_digest nettle_hmac2_digest #define hmac_md5_set_key nettle_hmac_md5_set_key #define hmac_md5_update nettle_hmac_md5_update #define hmac_md5_digest nettle_hmac_md5_digest @@ -87,6 +90,24 @@ hmac_digest(const void *outer, const void *inner, void *state, size_t length, uint8_t *digest);
+void +hmac2_set_key(void *state, void *derived_key, + const struct nettle_hash *hash, + size_t length, const uint8_t *key); + +/* This function is not strictly needed, it's s just the same as the + * hash update or hmac2_update functions. */ +void +hmac2_update(void *state, + const struct nettle_hash *hash, + size_t length, const uint8_t *data); + +void +hmac2_digest(void *state, void *derived_key, + const struct nettle_hash *hash, + size_t length, uint8_t *digest); + + #define HMAC_CTX(type) \ { type outer; type inner; type state; }
@@ -98,6 +119,17 @@ hmac_digest(const void *outer, const void *inner, void *state, hmac_digest( &(ctx)->outer, &(ctx)->inner, &(ctx)->state, \ (hash), (length), (digest) )
+#define HMAC2_CTX(type, block_size) \ +{ type state; uint8_t key[block_size]; } + +#define HMAC2_SET_KEY(ctx, hash, length, key) \ + hmac2_set_key( &(ctx)->state, &(ctx)->key, \ + (hash), (length), (key) ) + +#define HMAC2_DIGEST(ctx, hash, length, digest) \ + hmac2_digest( &(ctx)->state, &(ctx)->key, \ + (hash), (length), (digest) ) + /* HMAC using specific hash functions */
/* hmac-md5 */