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 | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ hmac.h | 34 ++++++++++++++++++++++++++++- 2 files changed, 101 insertions(+), 1 deletion(-)
diff --git a/hmac.c b/hmac.c index 6ac5e11a0686..44ac705856ad 100644 --- a/hmac.c +++ b/hmac.c @@ -115,3 +115,71 @@ hmac_digest(const void *outer, const void *inner, void *state,
memcpy(state, inner, hash->context_size); } + +void +hmac2_set_key(void *outer, void *inner, void *state, + const struct nettle_hash *hash, + size_t key_length, const uint8_t *key) +{ + TMP_DECL(pad, uint8_t, NETTLE_MAX_HASH_BLOCK_SIZE); + TMP_ALLOC(pad, hash->block_size); + + hash->init(state); + if (key_length > hash->block_size) + { + /* Reduce key to the algorithm's hash size. Use the area pointed + * to by state for the temporary state. */ + + TMP_DECL(digest, uint8_t, NETTLE_MAX_HASH_DIGEST_SIZE); + TMP_ALLOC(digest, hash->digest_size); + + hash->update(state, key_length, key); + hash->digest(state, hash->digest_size, digest); + + key = digest; + key_length = hash->digest_size; + } + + assert(key_length <= hash->block_size); + + memset(pad, OPAD, hash->block_size); + memxor(pad, key, key_length); + + /* Init happened before */ + hash->update(state, hash->block_size, pad); + memcpy(outer, state, hash->state_size); + + memset(pad, IPAD, hash->block_size); + memxor(pad, key, key_length); + + hash->init(state); + hash->update(state, hash->block_size, pad); + + memcpy(inner, state, hash->state_size); +} + +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(const void *outer, const void *inner, void *state, + 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); + + memcpy(state, outer, hash->state_size); + + hash->update(state, hash->digest_size, digest); + hash->digest(state, length, dst); + + memcpy(state, inner, hash->state_size); +} diff --git a/hmac.h b/hmac.h index 40a8e77aab6d..e6519023d259 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 *outer, void *inner, void *state, + 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(const void *outer, const void *inner, void *state, + const struct nettle_hash *hash, + size_t length, uint8_t *digest); + + #define HMAC_CTX(type) \ { type outer; type inner; type state; }
@@ -98,10 +119,21 @@ hmac_digest(const void *outer, const void *inner, void *state, hmac_digest( &(ctx)->outer, &(ctx)->inner, &(ctx)->state, \ (hash), (length), (digest) )
+#define HMAC2_CTX(ctx_type, type) \ +{ type outer; type inner; ctx_type state; } + +#define HMAC2_SET_KEY(ctx, hash, length, key) \ + hmac2_set_key( &(ctx)->outer, &(ctx)->inner, &(ctx)->state, \ + (hash), (length), (key) ) + +#define HMAC2_DIGEST(ctx, hash, length, digest) \ + hmac2_digest( &(ctx)->outer, &(ctx)->inner, &(ctx)->state, \ + (hash), (length), (digest) ) + /* HMAC using specific hash functions */
/* hmac-md5 */ -struct hmac_md5_ctx HMAC_CTX(struct md5_ctx); +struct hmac_md5_ctx HMAC2_CTX(struct md5_ctx, struct md5_state);
void hmac_md5_set_key(struct hmac_md5_ctx *ctx,
Signed-off-by: Dmitry Eremin-Solenikov dbaryshkov@gmail.com --- examples/nettle-openssl.c | 2 ++ nettle-meta.h | 13 +++++++++++++ sha512-224-meta.c | 1 + sha512-256-meta.c | 1 + 4 files changed, 17 insertions(+)
diff --git a/examples/nettle-openssl.c b/examples/nettle-openssl.c index bb2e6627514a..fc48a10c40b3 100644 --- a/examples/nettle-openssl.c +++ b/examples/nettle-openssl.c @@ -413,6 +413,7 @@ openssl_md5_digest(void *ctx, const struct nettle_hash nettle_openssl_md5 = { "openssl md5", sizeof(SHA_CTX), + sizeof(SHA_CTX), SHA_DIGEST_LENGTH, SHA_CBLOCK, openssl_md5_init, openssl_md5_update, @@ -449,6 +450,7 @@ openssl_sha1_digest(void *ctx, const struct nettle_hash nettle_openssl_sha1 = { "openssl sha1", sizeof(SHA_CTX), + sizeof(SHA_CTX), SHA_DIGEST_LENGTH, SHA_CBLOCK, openssl_sha1_init, openssl_sha1_update, diff --git a/nettle-meta.h b/nettle-meta.h index 8fe1cf84651b..366bd801b55c 100644 --- a/nettle-meta.h +++ b/nettle-meta.h @@ -98,6 +98,7 @@ struct nettle_hash
/* Size of the context struct */ unsigned context_size; + unsigned state_size;
/* Size of digests */ unsigned digest_size; @@ -113,6 +114,7 @@ struct nettle_hash #define _NETTLE_HASH(name, NAME) { \ #name, \ sizeof(struct name##_ctx), \ + sizeof(struct name##_ctx), \ NAME##_DIGEST_SIZE, \ NAME##_BLOCK_SIZE, \ (nettle_hash_init_func *) name##_init, \ @@ -120,6 +122,17 @@ struct nettle_hash (nettle_hash_digest_func *) name##_digest \ }
+#define _NETTLE_HASH_STATE(name, NAME) { \ + #name, \ + sizeof(struct name##_ctx), \ + sizeof(struct name##_state), \ + NAME##_DIGEST_SIZE, \ + NAME##_BLOCK_SIZE, \ + (nettle_hash_init_func *) name##_init, \ + (nettle_hash_update_func *) name##_update, \ + (nettle_hash_digest_func *) name##_digest \ +} + /* null-terminated list of digests implemented by this version of nettle */ const struct nettle_hash * const * #ifdef __GNUC__ diff --git a/sha512-224-meta.c b/sha512-224-meta.c index 24c42bfc23d9..c134ead0cedd 100644 --- a/sha512-224-meta.c +++ b/sha512-224-meta.c @@ -40,6 +40,7 @@ const struct nettle_hash nettle_sha512_224 = { "sha512-224", sizeof(struct sha512_ctx), + sizeof(struct sha512_ctx), SHA512_224_DIGEST_SIZE, SHA512_224_BLOCK_SIZE, (nettle_hash_init_func *) sha512_224_init, diff --git a/sha512-256-meta.c b/sha512-256-meta.c index 37d17c351878..458aa53ae47b 100644 --- a/sha512-256-meta.c +++ b/sha512-256-meta.c @@ -40,6 +40,7 @@ const struct nettle_hash nettle_sha512_256 = { "sha512-256", sizeof(struct sha512_ctx), + sizeof(struct sha512_ctx), SHA512_256_DIGEST_SIZE, SHA512_256_BLOCK_SIZE, (nettle_hash_init_func *) sha512_256_init,
Signed-off-by: Dmitry Eremin-Solenikov dbaryshkov@gmail.com --- md5-meta.c | 2 +- md5.c | 14 +++++++------- md5.h | 7 ++++++- 3 files changed, 14 insertions(+), 9 deletions(-)
diff --git a/md5-meta.c b/md5-meta.c index e4013edfd233..9d17be000f0a 100644 --- a/md5-meta.c +++ b/md5-meta.c @@ -38,4 +38,4 @@ #include "md5.h"
const struct nettle_hash nettle_md5 -= _NETTLE_HASH(md5, MD5); += _NETTLE_HASH_STATE(md5, MD5); diff --git a/md5.c b/md5.c index cc009b4a8dc8..4ffa064bacc5 100644 --- a/md5.c +++ b/md5.c @@ -56,19 +56,19 @@ md5_init(struct md5_ctx *ctx) 0x98badcfe, 0x10325476, }; - memcpy(ctx->state, iv, sizeof(ctx->state)); - ctx->count = 0; + memcpy(ctx->state.state, iv, sizeof(ctx->state.state)); + ctx->state.count = 0; ctx->index = 0; }
-#define COMPRESS(ctx, data) (nettle_md5_compress((ctx)->state, (data))) +#define COMPRESS(ctx, data) (nettle_md5_compress((ctx)->state.state, (data)))
void md5_update(struct md5_ctx *ctx, size_t length, const uint8_t *data) { - MD_UPDATE(ctx, length, data, COMPRESS, ctx->count++); + MD_UPDATE(ctx, length, data, COMPRESS, ctx->state.count++); }
void @@ -83,11 +83,11 @@ md5_digest(struct md5_ctx *ctx, MD_PAD(ctx, 8, COMPRESS);
/* There are 512 = 2^9 bits in one block */ - bit_count = (ctx->count << 9) | (ctx->index << 3); + bit_count = (ctx->state.count << 9) | (ctx->index << 3);
LE_WRITE_UINT64(ctx->block + (MD5_BLOCK_SIZE - 8), bit_count); - nettle_md5_compress(ctx->state, ctx->block); + nettle_md5_compress(ctx->state.state, ctx->block);
- _nettle_write_le32(length, digest, ctx->state); + _nettle_write_le32(length, digest, ctx->state.state); md5_init(ctx); } diff --git a/md5.h b/md5.h index 6feb39cc380b..258415479354 100644 --- a/md5.h +++ b/md5.h @@ -53,10 +53,15 @@ extern "C" { /* Digest is kept internally as 4 32-bit words. */ #define _MD5_DIGEST_LENGTH 4
-struct md5_ctx +struct md5_state { uint32_t state[_MD5_DIGEST_LENGTH]; uint64_t count; /* Block count */ +}; + +struct md5_ctx +{ + struct md5_state state; uint8_t block[MD5_BLOCK_SIZE]; /* Block buffer */ unsigned index; /* Into buffer */ };
Dmitry Eremin-Solenikov dbaryshkov@gmail.com writes:
--- a/md5.c +++ b/md5.c @@ -56,19 +56,19 @@ md5_init(struct md5_ctx *ctx) 0x98badcfe, 0x10325476, };
- memcpy(ctx->state, iv, sizeof(ctx->state));
- ctx->count = 0;
- memcpy(ctx->state.state, iv, sizeof(ctx->state.state));
- ctx->state.count = 0; ctx->index = 0;
}
Could have the same memcpy handle all of state.
--- a/md5.h +++ b/md5.h @@ -53,10 +53,15 @@ extern "C" { /* Digest is kept internally as 4 32-bit words. */ #define _MD5_DIGEST_LENGTH 4
-struct md5_ctx +struct md5_state { uint32_t state[_MD5_DIGEST_LENGTH]; uint64_t count; /* Block count */ +};
+struct md5_ctx +{
- struct md5_state state; uint8_t block[MD5_BLOCK_SIZE]; /* Block buffer */ unsigned index; /* Into buffer */
};
When reworking these structs, I think we should generally have index before block, since index has a larger required alignment. Even if it doesn't matter in this particular case, with MD5_BLOCK_SIZE == 64.
I wonder if we can find some better naming. "state.state" isn't so pretty, and I think the conventional terminology would be to refer to the 4 32-bit words as the md5 "state", not including the block count. What we're trying to capture actually is somewhat hmac-specific.
It's the part that needs to be copied to the start at an md5_ctx to reset it to some block boundary, and the reason we need a named type (rather than offsetof(struct md5_ctx, block), is that code needs to allocate it. Perhaps
struct md5_init_state { uint32_t state[_MD5_DIGEST_LENGTH]; uint64_t count; /* Block count */ unsigned index; };
or struct md5_internal_ctx_no_buffer or so.
Then both plain md5 reset and md5-hmac could use a single memcpy. And we could use some internal variant of md5_digest to avoid the redundant memcpy done by md5_digest (in your patch set, the hmac code depends on md5_digest resetting the index field, while it overwrites the rest of the state).
I'm starting to think that it probably was a mistake to advertise and document the internal hmac_set_key, hmac_update and hmac_digest methods. Maybe we can deprecate them (without immediately breaking them); I find no usage on codesearch.debian.net. We'de get more flexibility if we could implement hmac_md5_* without going via struct nettle_hash nettle_md5.
I think it would make sense to start with reordering fields in the current context structs.
Regards, /Niels
Signed-off-by: Dmitry Eremin-Solenikov dbaryshkov@gmail.com --- hmac-md5.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/hmac-md5.c b/hmac-md5.c index a27e64f6f61b..01670af88f2d 100644 --- a/hmac-md5.c +++ b/hmac-md5.c @@ -41,7 +41,7 @@ void hmac_md5_set_key(struct hmac_md5_ctx *ctx, size_t key_length, const uint8_t *key) { - HMAC_SET_KEY(ctx, &nettle_md5, key_length, key); + HMAC2_SET_KEY(ctx, &nettle_md5, key_length, key); }
void @@ -55,5 +55,5 @@ void hmac_md5_digest(struct hmac_md5_ctx *ctx, size_t length, uint8_t *digest) { - HMAC_DIGEST(ctx, &nettle_md5, length, digest); + HMAC2_DIGEST(ctx, &nettle_md5, length, digest); }
nettle-bugs@lists.lysator.liu.se