ProtoCore v0.0.1
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
kdf.cpp
Go to the documentation of this file.
1// Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file kdf.cpp
6 * @brief SP800-108 counter-mode KDF with HMAC-SHA256 PRF (see kdf.h).
7 *
8 * The HMAC key is constant across counter iterations, so the ipad/opad key blocks are derived once and
9 * reused for every block; only the (counter || fixed) message changes. Streaming SHA-256 (pc_sha256_*)
10 * inherits hardware acceleration on ESP32 transparently.
11 */
12
13#include "crypto/kdf/kdf.h"
14#include "crypto/crypto_opt.h"
15#include "crypto/hash/sha256.h"
17#include <string.h>
19
20bool pc_kdf_ctr_hmac_sha256(const uint8_t *ki, size_t ki_len, const uint8_t *fixed, size_t fixed_len, uint8_t *out,
21 size_t out_len)
22{
23 if (!ki || !fixed || !out || out_len == 0)
24 {
25 return false;
26 }
27 // The HMAC key is constant across counter iterations, so derive its pads once (RFC 2104).
28 uint8_t k[64];
29 memset(k, 0, sizeof(k));
30 if (ki_len > 64)
31 {
32 pc_sha256(ki, ki_len, k); // a key longer than the block is hashed to 32 octets first
33 }
34 else
35 {
36 memcpy(k, ki, ki_len);
37 }
38 uint8_t ipad[64], opad[64];
39 for (int i = 0; i < 64; i++)
40 {
41 ipad[i] = (uint8_t)(k[i] ^ 0x36u);
42 opad[i] = (uint8_t)(k[i] ^ 0x5cu);
43 }
44
45 // K(i) = HMAC-SHA256(Ki, [i]_32be || fixed); concatenate blocks for i = 1, 2, ... then truncate.
46 size_t done = 0;
47 for (uint32_t counter = 1; done < out_len; counter++)
48 {
49 uint8_t ctr[4];
50 pc_wr32be(ctr, counter);
52 uint8_t inner[32];
54 pc_sha256_update(&c, ipad, 64);
55 pc_sha256_update(&c, ctr, 4);
56 pc_sha256_update(&c, fixed, fixed_len);
57 pc_sha256_final(&c, inner);
58 uint8_t block[32];
60 pc_sha256_update(&c, opad, 64);
61 pc_sha256_update(&c, inner, 32);
62 pc_sha256_final(&c, block);
63 size_t take = (out_len - done < 32) ? out_len - done : 32;
64 memcpy(out + done, block, take);
65 done += take;
66 }
67 return true;
68}
Per-translation-unit optimization override for hot, pure-integer crypto.
Fixed-width integer serializers into a raw uint8_t* buffer - one source of truth.
size_t pc_wr32be(uint8_t *p, uint32_t v)
Write v big-endian at p.
Definition endian.h:93
PC_CRYPTO_HOT bool pc_kdf_ctr_hmac_sha256(const uint8_t *ki, size_t ki_len, const uint8_t *fixed, size_t fixed_len, uint8_t *out, size_t out_len)
SP800-108 KDF in counter mode with HMAC-SHA256 as the PRF (NIST SP800-108 ยง5.1; r = 32-bit counter pl...
Definition kdf.cpp:20
SP800-108 counter-mode key derivation (HMAC-SHA256 PRF).
PC_CRYPTO_HOT void pc_sha256_init(pc_sha256_ctx *ctx)
Initialize a streaming SHA-256 context (ctx must not be NULL).
Definition sha256.cpp:29
void pc_sha256_final(pc_sha256_ctx *ctx, uint8_t digest[PC_SHA256_DIGEST_LEN])
Finalize the hash and write the 32-byte digest. The context is undefined afterwards; call init() agai...
Definition sha256.cpp:48
void pc_sha256_update(pc_sha256_ctx *ctx, const uint8_t *data, size_t len)
Feed len bytes of data into the running hash.
Definition sha256.cpp:39
void pc_sha256(const uint8_t *data, size_t len, uint8_t digest[PC_SHA256_DIGEST_LEN])
One-shot SHA-256: hash len bytes of data into digest (32 bytes).
Definition sha256.cpp:58
SHA-256 (FIPS 180-4) - streaming context and one-shot API.
Streaming SHA-256 context.
Definition sha256.h:40