diff options
Diffstat (limited to 'src/basic/hmac.c')
-rw-r--r-- | src/basic/hmac.c | 60 |
1 files changed, 60 insertions, 0 deletions
diff --git a/src/basic/hmac.c b/src/basic/hmac.c new file mode 100644 index 0000000..a5f66d5 --- /dev/null +++ b/src/basic/hmac.c @@ -0,0 +1,60 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include <assert.h> +#include <string.h> + +#include "hmac.h" +#include "sha256.h" + +#define HMAC_BLOCK_SIZE 64 +#define INNER_PADDING_BYTE 0x36 +#define OUTER_PADDING_BYTE 0x5c + +void hmac_sha256(const void *key, + size_t key_size, + const void *input, + size_t input_size, + uint8_t res[static SHA256_DIGEST_SIZE]) { + + uint8_t inner_padding[HMAC_BLOCK_SIZE] = { }; + uint8_t outer_padding[HMAC_BLOCK_SIZE] = { }; + uint8_t replacement_key[SHA256_DIGEST_SIZE]; + struct sha256_ctx hash; + + assert(key); + assert(key_size > 0); + assert(res); + + /* Implement algorithm as described by FIPS 198. */ + + /* The key needs to be block size length or less, hash it if it's longer. */ + if (key_size > HMAC_BLOCK_SIZE) { + sha256_direct(key, key_size, replacement_key); + key = replacement_key; + key_size = SHA256_DIGEST_SIZE; + } + + /* First, copy the key into the padding arrays. If it's shorter than + * the block size, the arrays are already initialized to 0. */ + memcpy(inner_padding, key, key_size); + memcpy(outer_padding, key, key_size); + + /* Then, XOR the provided key and any padding leftovers with the fixed + * padding bytes as defined in FIPS 198. */ + for (size_t i = 0; i < HMAC_BLOCK_SIZE; i++) { + inner_padding[i] ^= INNER_PADDING_BYTE; + outer_padding[i] ^= OUTER_PADDING_BYTE; + } + + /* First pass: hash the inner padding array and the input. */ + sha256_init_ctx(&hash); + sha256_process_bytes(inner_padding, HMAC_BLOCK_SIZE, &hash); + sha256_process_bytes(input, input_size, &hash); + sha256_finish_ctx(&hash, res); + + /* Second pass: hash the outer padding array and the result of the first pass. */ + sha256_init_ctx(&hash); + sha256_process_bytes(outer_padding, HMAC_BLOCK_SIZE, &hash); + sha256_process_bytes(res, SHA256_DIGEST_SIZE, &hash); + sha256_finish_ctx(&hash, res); +} |