diff options
Diffstat (limited to '')
-rw-r--r-- | libbb/hash_hmac.c | 107 |
1 files changed, 107 insertions, 0 deletions
diff --git a/libbb/hash_hmac.c b/libbb/hash_hmac.c new file mode 100644 index 000000000..9e48e0f51 --- /dev/null +++ b/libbb/hash_hmac.c | |||
@@ -0,0 +1,107 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2025 Denys Vlasenko | ||
3 | * | ||
4 | * Licensed under GPLv2, see file LICENSE in this source tree. | ||
5 | */ | ||
6 | //kbuild:lib-$(CONFIG_TLS) += hash_hmac.o | ||
7 | //kbuild:lib-$(CONFIG_USE_BB_CRYPT_YES) += hash_hmac.o | ||
8 | |||
9 | #include "libbb.h" | ||
10 | |||
11 | // RFC 2104: | ||
12 | // HMAC(key, text) based on a hash H (say, sha256) is: | ||
13 | // ipad = [0x36 x INSIZE] | ||
14 | // opad = [0x5c x INSIZE] | ||
15 | // HMAC(key, text) = H((key XOR opad) + H((key XOR ipad) + text)) | ||
16 | // | ||
17 | // H(key XOR opad) and H(key XOR ipad) can be precomputed | ||
18 | // if we often need HMAC hmac with the same key. | ||
19 | // | ||
20 | // text is often given in disjoint pieces. | ||
21 | void FAST_FUNC hmac_begin(hmac_ctx_t *ctx, const uint8_t *key, unsigned key_size, md5sha_begin_func *begin) | ||
22 | { | ||
23 | #if HMAC_ONLY_SHA256 | ||
24 | #define begin sha256_begin | ||
25 | #endif | ||
26 | uint8_t key_xor_ipad[SHA2_INSIZE]; | ||
27 | uint8_t key_xor_opad[SHA2_INSIZE]; | ||
28 | unsigned i; | ||
29 | |||
30 | // "The authentication key can be of any length up to INSIZE, the | ||
31 | // block length of the hash function. Applications that use keys longer | ||
32 | // than INSIZE bytes will first hash the key using H and then use the | ||
33 | // resultant OUTSIZE byte string as the actual key to HMAC." | ||
34 | if (key_size > SHA2_INSIZE) { | ||
35 | uint8_t tempkey[SHA1_OUTSIZE < SHA256_OUTSIZE ? SHA256_OUTSIZE : SHA1_OUTSIZE]; | ||
36 | /* use ctx->hashed_key_xor_ipad as scratch ctx */ | ||
37 | begin(&ctx->hashed_key_xor_ipad); | ||
38 | md5sha_hash(&ctx->hashed_key_xor_ipad, key, key_size); | ||
39 | key_size = sha_end(&ctx->hashed_key_xor_ipad, tempkey); | ||
40 | key = tempkey; | ||
41 | } | ||
42 | |||
43 | for (i = 0; i < key_size; i++) { | ||
44 | key_xor_ipad[i] = key[i] ^ 0x36; | ||
45 | key_xor_opad[i] = key[i] ^ 0x5c; | ||
46 | } | ||
47 | for (; i < SHA2_INSIZE; i++) { | ||
48 | key_xor_ipad[i] = 0x36; | ||
49 | key_xor_opad[i] = 0x5c; | ||
50 | } | ||
51 | |||
52 | begin(&ctx->hashed_key_xor_ipad); | ||
53 | begin(&ctx->hashed_key_xor_opad); | ||
54 | md5sha_hash(&ctx->hashed_key_xor_ipad, key_xor_ipad, SHA2_INSIZE); | ||
55 | md5sha_hash(&ctx->hashed_key_xor_opad, key_xor_opad, SHA2_INSIZE); | ||
56 | } | ||
57 | #undef begin | ||
58 | |||
59 | unsigned FAST_FUNC hmac_end(hmac_ctx_t *ctx, uint8_t *out) | ||
60 | { | ||
61 | unsigned len = sha_end(&ctx->hashed_key_xor_ipad, out); | ||
62 | /* out = H((key XOR opad) + out) */ | ||
63 | md5sha_hash(&ctx->hashed_key_xor_opad, out, len); | ||
64 | return sha_end(&ctx->hashed_key_xor_opad, out); | ||
65 | } | ||
66 | |||
67 | unsigned FAST_FUNC hmac_block(const uint8_t *key, unsigned key_size, md5sha_begin_func *begin, const void *in, unsigned sz, uint8_t *out) | ||
68 | { | ||
69 | hmac_ctx_t ctx; | ||
70 | hmac_begin(&ctx, key, key_size, begin); | ||
71 | hmac_hash(&ctx, in, sz); | ||
72 | return hmac_end(&ctx, out); | ||
73 | } | ||
74 | |||
75 | /* TLS helpers */ | ||
76 | |||
77 | void FAST_FUNC hmac_hash_v( | ||
78 | hmac_ctx_t *ctx, | ||
79 | va_list va) | ||
80 | { | ||
81 | uint8_t *in; | ||
82 | |||
83 | /* ctx->hashed_key_xor_ipad contains unclosed "H((key XOR ipad) +" state */ | ||
84 | /* ctx->hashed_key_xor_opad contains unclosed "H((key XOR opad) +" state */ | ||
85 | |||
86 | /* calculate out = H((key XOR ipad) + text) */ | ||
87 | while ((in = va_arg(va, uint8_t*)) != NULL) { | ||
88 | unsigned size = va_arg(va, unsigned); | ||
89 | md5sha_hash(&ctx->hashed_key_xor_ipad, in, size); | ||
90 | } | ||
91 | } | ||
92 | |||
93 | /* Using HMAC state, make a copy of it (IOW: without affecting this state!) | ||
94 | * hash in the list of (ptr,size) blocks, and finish the HMAC to out[] buffer. | ||
95 | * This function is useful for TLS PRF. | ||
96 | */ | ||
97 | unsigned FAST_FUNC hmac_peek_hash(hmac_ctx_t *ctx, uint8_t *out, ...) | ||
98 | { | ||
99 | hmac_ctx_t tmpctx = *ctx; /* struct copy */ | ||
100 | va_list va; | ||
101 | |||
102 | va_start(va, out); | ||
103 | hmac_hash_v(&tmpctx, va); | ||
104 | va_end(va); | ||
105 | |||
106 | return hmac_end(&tmpctx, out); | ||
107 | } | ||