1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 
3 #include <assert.h>
4 #include <string.h>
5 
6 #include "hmac.h"
7 #include "sha256.h"
8 
9 #define HMAC_BLOCK_SIZE 64
10 #define INNER_PADDING_BYTE 0x36
11 #define OUTER_PADDING_BYTE 0x5c
12 
hmac_sha256(const void * key,size_t key_size,const void * input,size_t input_size,uint8_t res[static SHA256_DIGEST_SIZE])13 void hmac_sha256(const void *key,
14                  size_t key_size,
15                  const void *input,
16                  size_t input_size,
17                  uint8_t res[static SHA256_DIGEST_SIZE]) {
18 
19         uint8_t inner_padding[HMAC_BLOCK_SIZE] = { };
20         uint8_t outer_padding[HMAC_BLOCK_SIZE] = { };
21         uint8_t replacement_key[SHA256_DIGEST_SIZE];
22         struct sha256_ctx hash;
23 
24         assert(key);
25         assert(key_size > 0);
26         assert(res);
27 
28         /* Implement algorithm as described by FIPS 198. */
29 
30         /* The key needs to be block size length or less, hash it if it's longer. */
31         if (key_size > HMAC_BLOCK_SIZE) {
32                 sha256_init_ctx(&hash);
33                 sha256_process_bytes(key, key_size, &hash);
34                 sha256_finish_ctx(&hash, replacement_key);
35                 key = replacement_key;
36                 key_size = SHA256_DIGEST_SIZE;
37         }
38 
39         /* First, copy the key into the padding arrays. If it's shorter than
40          * the block size, the arrays are already initialized to 0. */
41         memcpy(inner_padding, key, key_size);
42         memcpy(outer_padding, key, key_size);
43 
44         /* Then, XOR the provided key and any padding leftovers with the fixed
45          * padding bytes as defined in FIPS 198. */
46         for (size_t i = 0; i < HMAC_BLOCK_SIZE; i++) {
47                 inner_padding[i] ^= INNER_PADDING_BYTE;
48                 outer_padding[i] ^= OUTER_PADDING_BYTE;
49         }
50 
51         /* First pass: hash the inner padding array and the input. */
52         sha256_init_ctx(&hash);
53         sha256_process_bytes(inner_padding, HMAC_BLOCK_SIZE, &hash);
54         sha256_process_bytes(input, input_size, &hash);
55         sha256_finish_ctx(&hash, res);
56 
57         /* Second pass: hash the outer padding array and the result of the first pass. */
58         sha256_init_ctx(&hash);
59         sha256_process_bytes(outer_padding, HMAC_BLOCK_SIZE, &hash);
60         sha256_process_bytes(res, SHA256_DIGEST_SIZE, &hash);
61         sha256_finish_ctx(&hash, res);
62 }
63