From 6978574556c07410bed2f04fefce94018951d9f2 Mon Sep 17 00:00:00 2001 From: Paul Duncan Date: Mon, 4 Sep 2023 23:27:29 -0400 Subject: sha3.[hc]: add hmac_sha3_{224,256,384,512}(), hmac_sha3_{224,256,384,512}_{init,absorb,final}(), test_hmac_sha3_{224,256,384,512}(), test_hmac_sha3_{224,256,384,512}_ctx() --- sha3.c | 970 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- sha3.h | 188 ++++++++++++- 2 files changed, 1153 insertions(+), 5 deletions(-) diff --git a/sha3.c b/sha3.c index 4a7f512..b03e0f3 100644 --- a/sha3.c +++ b/sha3.c @@ -219,13 +219,13 @@ static inline void sha3_init(sha3_t * const hash) { } // Absorb input data into iterative SHA-3 hash context. -static inline bool sha3_absorb(sha3_t * const hash, const size_t rate, const uint8_t * const src, const size_t len) { +static inline bool sha3_absorb(sha3_t * const hash, const size_t rate, const uint8_t *src, size_t len) { if (hash->finalized) { // hash already finalized, return false return false; } - // absorb bytes (FIXME: should absorb larger chunks) + // absorb bytes (FIXME: absorb larger chunks) for (size_t i = 0; i < len; i++) { hash->a.u8[hash->num_bytes++] ^= src[i]; if (hash->num_bytes == rate) { @@ -330,6 +330,242 @@ void sha3_512_final(sha3_t * const hash, uint8_t dst[SHA3_512_CAPACITY]) { sha3_final(hash, SHA3_512_RATE, dst, SHA3_512_CAPACITY); } +void hmac_sha3_224_init(hmac_sha3_t *hmac, const uint8_t *k, const size_t k_len) { + // clear finalized flag + hmac->finalized = false; + + // init key buffer + uint8_t k_buf[SHA3_224_RATE] = { 0 }; + if (k_len <= sizeof(k_buf)) { + memcpy(k_buf, k, k_len); + } else { + sha3_224(k, k_len, k_buf); + } + + // apply opad + for (size_t i = 0; i < SHA3_224_RATE; i++) { + k_buf[i] ^= 0x5c; + } + + // init outer hash, absorb outer key + sha3_224_init(&(hmac->outer)); + sha3_224_absorb(&(hmac->outer), k_buf, sizeof(k_buf)); + + // remove opad, apply ipad + for (size_t i = 0; i < SHA3_224_RATE; i++) { + k_buf[i] ^= (0x5c ^ 0x36); + } + + // init outer hash, absorb inner key + sha3_224_init(&(hmac->inner)); + sha3_224_absorb(&(hmac->inner), k_buf, sizeof(k_buf)); +} + +_Bool hmac_sha3_224_absorb(hmac_sha3_t *hmac, const uint8_t *src, const size_t len) { + return sha3_224_absorb(&(hmac->inner), src, len); +} + +void hmac_sha3_224_final(hmac_sha3_t *hmac, uint8_t dst[28]) { + // finalize inner hash into buffer + uint8_t buf[28] = { 0 }; + sha3_224_final(&(hmac->inner), buf); + + // absorb into outer hash + sha3_224_absorb(&(hmac->outer), buf, sizeof(buf)); + + // finalize outer hash into destination + sha3_224_final(&(hmac->outer), dst); +} + +void hmac_sha3_224(const uint8_t * const k, const size_t k_len, const uint8_t * const m, const size_t m_len, uint8_t dst[28]) { + // init + hmac_sha3_t hmac; + hmac_sha3_224_init(&hmac, k, k_len); + + // absorb + hmac_sha3_224_absorb(&hmac, m, m_len); + + // finalize + hmac_sha3_224_final(&hmac, dst); +} + +void hmac_sha3_256_init(hmac_sha3_t *hmac, const uint8_t *k, const size_t k_len) { + // clear finalized flag + hmac->finalized = false; + + // init key buffer + uint8_t k_buf[SHA3_256_RATE] = { 0 }; + if (k_len <= sizeof(k_buf)) { + memcpy(k_buf, k, k_len); + } else { + sha3_256(k, k_len, k_buf); + } + + // apply opad + for (size_t i = 0; i < SHA3_256_RATE; i++) { + k_buf[i] ^= 0x5c; + } + + // init outer hash, absorb outer key + sha3_256_init(&(hmac->outer)); + sha3_256_absorb(&(hmac->outer), k_buf, sizeof(k_buf)); + + // remove opad, apply ipad + for (size_t i = 0; i < SHA3_256_RATE; i++) { + k_buf[i] ^= (0x5c ^ 0x36); + } + + // init outer hash, absorb inner key + sha3_256_init(&(hmac->inner)); + sha3_256_absorb(&(hmac->inner), k_buf, sizeof(k_buf)); +} + +_Bool hmac_sha3_256_absorb(hmac_sha3_t *hmac, const uint8_t *src, const size_t len) { + return sha3_256_absorb(&(hmac->inner), src, len); +} + +void hmac_sha3_256_final(hmac_sha3_t *hmac, uint8_t dst[32]) { + // finalize inner hash into buffer + uint8_t buf[32] = { 0 }; + sha3_256_final(&(hmac->inner), buf); + + // absorb into outer hash + sha3_256_absorb(&(hmac->outer), buf, sizeof(buf)); + + // finalize outer hash into destination + sha3_256_final(&(hmac->outer), dst); +} + +void hmac_sha3_256(const uint8_t * const k, const size_t k_len, const uint8_t * const m, const size_t m_len, uint8_t dst[32]) { + // init + hmac_sha3_t hmac; + hmac_sha3_256_init(&hmac, k, k_len); + + // absorb + hmac_sha3_256_absorb(&hmac, m, m_len); + + // finalize + hmac_sha3_256_final(&hmac, dst); +} + +void hmac_sha3_384_init(hmac_sha3_t *hmac, const uint8_t *k, const size_t k_len) { + // clear finalized flag + hmac->finalized = false; + + // init key buffer + uint8_t k_buf[SHA3_384_RATE] = { 0 }; + if (k_len <= sizeof(k_buf)) { + memcpy(k_buf, k, k_len); + } else { + sha3_384(k, k_len, k_buf); + } + + // apply opad + for (size_t i = 0; i < SHA3_384_RATE; i++) { + k_buf[i] ^= 0x5c; + } + + // init outer hash, absorb outer key + sha3_384_init(&(hmac->outer)); + sha3_384_absorb(&(hmac->outer), k_buf, sizeof(k_buf)); + + // remove opad, apply ipad + for (size_t i = 0; i < SHA3_384_RATE; i++) { + k_buf[i] ^= (0x5c ^ 0x36); + } + + // init outer hash, absorb inner key + sha3_384_init(&(hmac->inner)); + sha3_384_absorb(&(hmac->inner), k_buf, sizeof(k_buf)); +} + +_Bool hmac_sha3_384_absorb(hmac_sha3_t *hmac, const uint8_t *src, const size_t len) { + return sha3_384_absorb(&(hmac->inner), src, len); +} + +void hmac_sha3_384_final(hmac_sha3_t *hmac, uint8_t dst[48]) { + // finalize inner hash into buffer + uint8_t buf[48] = { 0 }; + sha3_384_final(&(hmac->inner), buf); + + // absorb into outer hash + sha3_384_absorb(&(hmac->outer), buf, sizeof(buf)); + + // finalize outer hash into destination + sha3_384_final(&(hmac->outer), dst); +} + +void hmac_sha3_384(const uint8_t * const k, const size_t k_len, const uint8_t * const m, const size_t m_len, uint8_t dst[48]) { + // init + hmac_sha3_t hmac; + hmac_sha3_384_init(&hmac, k, k_len); + + // absorb + hmac_sha3_384_absorb(&hmac, m, m_len); + + // finalize + hmac_sha3_384_final(&hmac, dst); +} + +void hmac_sha3_512_init(hmac_sha3_t *hmac, const uint8_t *k, const size_t k_len) { + // clear finalized flag + hmac->finalized = false; + + // init key buffer + uint8_t k_buf[SHA3_512_RATE] = { 0 }; + if (k_len <= sizeof(k_buf)) { + memcpy(k_buf, k, k_len); + } else { + sha3_512(k, k_len, k_buf); + } + + // apply opad + for (size_t i = 0; i < SHA3_512_RATE; i++) { + k_buf[i] ^= 0x5c; + } + + // init outer hash, absorb outer key + sha3_512_init(&(hmac->outer)); + sha3_512_absorb(&(hmac->outer), k_buf, sizeof(k_buf)); + + // remove opad, apply ipad + for (size_t i = 0; i < SHA3_512_RATE; i++) { + k_buf[i] ^= (0x5c ^ 0x36); + } + + // init outer hash, absorb inner key + sha3_512_init(&(hmac->inner)); + sha3_512_absorb(&(hmac->inner), k_buf, sizeof(k_buf)); +} + +_Bool hmac_sha3_512_absorb(hmac_sha3_t *hmac, const uint8_t *src, const size_t len) { + return sha3_512_absorb(&(hmac->inner), src, len); +} + +void hmac_sha3_512_final(hmac_sha3_t *hmac, uint8_t dst[64]) { + // finalize inner hash into buffer + uint8_t buf[64] = { 0 }; + sha3_512_final(&(hmac->inner), buf); + + // absorb into outer hash + sha3_512_absorb(&(hmac->outer), buf, sizeof(buf)); + + // finalize outer hash into destination + sha3_512_final(&(hmac->outer), dst); +} + +void hmac_sha3_512(const uint8_t * const k, const size_t k_len, const uint8_t * const m, const size_t m_len, uint8_t dst[64]) { + // init + hmac_sha3_t hmac; + hmac_sha3_512_init(&hmac, k, k_len); + + // absorb + hmac_sha3_512_absorb(&hmac, m, m_len); + + // finalize + hmac_sha3_512_final(&hmac, dst); +} + static inline void shake(const uint8_t *m, size_t m_len, uint8_t * const dst, const size_t dst_len) { // in the sha3 xof functions, the capacity is always 2 times the // destination length, and the rate is the total state size minus the @@ -4885,6 +5121,728 @@ static void test_parallelhash256_xof(void) { } } +static void test_hmac_sha3_224(void) { + static const struct { + const char *name; // test name + const uint8_t key[256]; // key + const size_t key_len; // key length, in bytes + const uint8_t msg[256]; // input data + const size_t msg_len; // message length, in bytes + const uint8_t exp[28]; // expected hash + } tests[] = {{ + // src: https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/HMAC_SHA3-224.pdf + .name = "HMAC-SHA3-224 Sample #1", + .key = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, + }, + .key_len = 28, + .msg = "Sample message for keylen