]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/hmac.c
fileio: add read_virtual_file_at() flavour that takes dir_fd/path pair
[thirdparty/systemd.git] / src / basic / hmac.c
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
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 }