busybox/libbb/hash_hmac.c
Denys Vlasenko c11730490a libbb/yescrypt: remove redundant SHA256 HMAC implementation
function                                             old     new   delta
hmac_blocks                                            -      88     +88
static.PBKDF2_SHA256                                 176     213     +37
yescrypt_kdf32_body                                 1046    1052      +6
static.smix                                          759     762      +3
hmac_block                                            88      64     -24
HMAC_SHA256_Final                                     53       -     -53
HMAC_SHA256_Buf                                       58       -     -58
HMAC_SHA256_Init                                     159       -    -159
------------------------------------------------------------------------------
(add/remove: 1/3 grow/shrink: 3/1 up/down: 134/-294)         Total: -160 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2025-07-07 08:21:44 +02:00

107 lines
3.2 KiB
C

/*
* Copyright (C) 2025 Denys Vlasenko
*
* Licensed under GPLv2, see file LICENSE in this source tree.
*/
//kbuild:lib-$(CONFIG_TLS) += hash_hmac.o
//kbuild:lib-$(CONFIG_USE_BB_CRYPT_YES) += hash_hmac.o
#include "libbb.h"
// RFC 2104:
// HMAC(key, text) based on a hash H (say, sha256) is:
// ipad = [0x36 x INSIZE]
// opad = [0x5c x INSIZE]
// HMAC(key, text) = H((key XOR opad) + H((key XOR ipad) + text))
//
// H(key XOR opad) and H(key XOR ipad) can be precomputed
// if we often need HMAC hmac with the same key.
//
// text is often given in disjoint pieces.
void FAST_FUNC hmac_begin(hmac_ctx_t *ctx, const uint8_t *key, unsigned key_size, md5sha_begin_func *begin)
{
#if HMAC_ONLY_SHA256
#define begin sha256_begin
#endif
uint8_t key_xor_ipad[SHA2_INSIZE];
uint8_t key_xor_opad[SHA2_INSIZE];
unsigned i;
// "The authentication key can be of any length up to INSIZE, the
// block length of the hash function. Applications that use keys longer
// than INSIZE bytes will first hash the key using H and then use the
// resultant OUTSIZE byte string as the actual key to HMAC."
if (key_size > SHA2_INSIZE) {
uint8_t tempkey[SHA1_OUTSIZE < SHA256_OUTSIZE ? SHA256_OUTSIZE : SHA1_OUTSIZE];
/* use ctx->hashed_key_xor_ipad as scratch ctx */
begin(&ctx->hashed_key_xor_ipad);
md5sha_hash(&ctx->hashed_key_xor_ipad, key, key_size);
key_size = sha_end(&ctx->hashed_key_xor_ipad, tempkey);
key = tempkey;
}
for (i = 0; i < key_size; i++) {
key_xor_ipad[i] = key[i] ^ 0x36;
key_xor_opad[i] = key[i] ^ 0x5c;
}
for (; i < SHA2_INSIZE; i++) {
key_xor_ipad[i] = 0x36;
key_xor_opad[i] = 0x5c;
}
begin(&ctx->hashed_key_xor_ipad);
begin(&ctx->hashed_key_xor_opad);
md5sha_hash(&ctx->hashed_key_xor_ipad, key_xor_ipad, SHA2_INSIZE);
md5sha_hash(&ctx->hashed_key_xor_opad, key_xor_opad, SHA2_INSIZE);
}
#undef begin
unsigned FAST_FUNC hmac_end(hmac_ctx_t *ctx, uint8_t *out)
{
unsigned len = sha_end(&ctx->hashed_key_xor_ipad, out);
/* out = H((key XOR opad) + out) */
md5sha_hash(&ctx->hashed_key_xor_opad, out, len);
return sha_end(&ctx->hashed_key_xor_opad, out);
}
unsigned FAST_FUNC hmac_block(const uint8_t *key, unsigned key_size, md5sha_begin_func *begin, const void *in, unsigned sz, uint8_t *out)
{
hmac_ctx_t ctx;
hmac_begin(&ctx, key, key_size, begin);
hmac_hash(&ctx, in, sz);
return hmac_end(&ctx, out);
}
/* TLS helpers */
void FAST_FUNC hmac_hash_v(
hmac_ctx_t *ctx,
va_list va)
{
uint8_t *in;
/* ctx->hashed_key_xor_ipad contains unclosed "H((key XOR ipad) +" state */
/* ctx->hashed_key_xor_opad contains unclosed "H((key XOR opad) +" state */
/* calculate out = H((key XOR ipad) + text) */
while ((in = va_arg(va, uint8_t*)) != NULL) {
unsigned size = va_arg(va, unsigned);
md5sha_hash(&ctx->hashed_key_xor_ipad, in, size);
}
}
/* Using HMAC state, make a copy of it (IOW: without affecting this state!)
* hash in the list of (ptr,size) blocks, and finish the HMAC to out[] buffer.
* This function is useful for TLS PRF.
*/
unsigned FAST_FUNC hmac_peek_hash(hmac_ctx_t *ctx, uint8_t *out, ...)
{
hmac_ctx_t tmpctx = *ctx; /* struct copy */
va_list va;
va_start(va, out);
hmac_hash_v(&tmpctx, va);
va_end(va);
return hmac_end(&tmpctx, out);
}