Skip to content

Commit 4d7213a

Browse files
committed
Add support for HKDF
1 parent 8d579d6 commit 4d7213a

17 files changed

+911
-55
lines changed

benchmark/bench_modules/wh_bench_mod_all.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,12 @@ int wh_Bench_Mod_HmacSha3256(whClientContext* client, whBenchOpContext* ctx,
143143
int wh_Bench_Mod_HmacSha3256Dma(whClientContext* client, whBenchOpContext* ctx,
144144
int id, void* params);
145145

146+
/* HKDF benchmark module prototypes (wh_bench_mod_hkdf.c) */
147+
#if defined(HAVE_HKDF)
148+
int wh_Bench_Mod_HkdfSha256(whClientContext* client, whBenchOpContext* ctx,
149+
int id, void* params);
150+
#endif /* HAVE_HKDF */
151+
146152
/*
147153
* ECC benchmark module prototypes (wh_bench_mod_ecc.c)
148154
*/
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/*
2+
* Copyright (C) 2025 wolfSSL Inc.
3+
*
4+
* This file is part of wolfHSM.
5+
*
6+
* wolfHSM is free software; you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation; either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* wolfHSM is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with wolfHSM. If not, see <http://www.gnu.org/licenses/>.
18+
*/
19+
20+
#include "wh_bench_mod.h"
21+
#include "wolfhsm/wh_error.h"
22+
23+
#include "wolfssl/wolfcrypt/hmac.h"
24+
#include "wolfssl/wolfcrypt/kdf.h"
25+
#include "wolfssl/wolfcrypt/sha256.h"
26+
27+
#if defined(WOLFHSM_CFG_BENCH_ENABLE)
28+
29+
#if defined(HAVE_HKDF)
30+
31+
32+
/* Output keying material size */
33+
#define WH_BENCH_HKDF_OKM_SIZE 42
34+
35+
static int _benchHkdf(whClientContext* client, whBenchOpContext* ctx, int id,
36+
int devId)
37+
{
38+
/* Simple fixed inputs for HKDF to measure performance. The data mirrors
39+
* sizes from RFC 5869 test case 1 but we only care about timing here. */
40+
static const uint8_t hkdf_ikm[] = {
41+
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
42+
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b};
43+
static const uint8_t hkdf_salt[] = {0x00, 0x01, 0x02, 0x03, 0x04,
44+
0x05, 0x06, 0x07, 0x08, 0x09,
45+
0x0a, 0x0b, 0x0c};
46+
static const uint8_t hkdf_info[] = {0xf0, 0xf1, 0xf2, 0xf3, 0xf4,
47+
0xf5, 0xf6, 0xf7, 0xf8, 0xf9};
48+
49+
50+
int ret = 0;
51+
uint8_t okm[WH_BENCH_HKDF_OKM_SIZE];
52+
int i;
53+
54+
(void)client;
55+
56+
for (i = 0; i < WOLFHSM_CFG_BENCH_KG_ITERS && ret == 0; i++) {
57+
int benchStartRet;
58+
int benchStopRet;
59+
60+
benchStartRet = wh_Bench_StartOp(ctx, id);
61+
ret = wc_HKDF_ex(WC_SHA256, hkdf_ikm, (word32)sizeof(hkdf_ikm),
62+
hkdf_salt, (word32)sizeof(hkdf_salt), hkdf_info,
63+
(word32)sizeof(hkdf_info), okm, (word32)sizeof(okm),
64+
NULL, /* heap */
65+
devId);
66+
benchStopRet = wh_Bench_StopOp(ctx, id);
67+
68+
if (benchStartRet != 0) {
69+
WH_BENCH_PRINTF("Failed to wh_Bench_StartOp %d\n", benchStartRet);
70+
ret = benchStartRet;
71+
break;
72+
}
73+
if (ret != 0) {
74+
WH_BENCH_PRINTF("Failed to wc_HKDF_ex %d\n", ret);
75+
break;
76+
}
77+
if (benchStopRet != 0) {
78+
WH_BENCH_PRINTF("Failed to wh_Bench_StopOp %d\n", benchStopRet);
79+
ret = benchStopRet;
80+
break;
81+
}
82+
}
83+
84+
return ret;
85+
}
86+
87+
int wh_Bench_Mod_HkdfSha256(whClientContext* client, whBenchOpContext* ctx,
88+
int id, void* params)
89+
{
90+
(void)params;
91+
return _benchHkdf(client, ctx, id, WH_DEV_ID);
92+
}
93+
94+
#endif /* defined(HAVE_HKDF) */
95+
96+
#endif /* WOLFHSM_CFG_BENCH_ENABLE */

benchmark/wh_bench.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,11 @@ typedef enum BenchModuleIdx {
155155
#endif /* WOLFSSL_SHA3 */
156156
#endif /* !(NO_HMAC) */
157157

158+
/* HKDF */
159+
#if defined(HAVE_HKDF)
160+
BENCH_MODULE_IDX_HKDF_SHA2_256,
161+
#endif /* HAVE_HKDF */
162+
158163
/* ECC */
159164
#if defined(HAVE_ECC)
160165
BENCH_MODULE_IDX_ECC_P256_SIGN,
@@ -314,6 +319,11 @@ static BenchModule g_benchModules[] = {
314319
#endif /* WOLFSSL_SHA3 */
315320
#endif /* !(NO_HMAC) */
316321

322+
/* HKDF */
323+
#if defined(HAVE_HKDF)
324+
[BENCH_MODULE_IDX_HKDF_SHA2_256] = {"HKDF-SHA2-256", wh_Bench_Mod_HkdfSha256, BENCH_THROUGHPUT_OPS, 0, NULL},
325+
#endif /* HAVE_HKDF */
326+
317327
/* ECC */
318328
#if defined(HAVE_ECC)
319329
[BENCH_MODULE_IDX_ECC_P256_SIGN] = {"ECC-P256-SIGN", wh_Bench_Mod_EccP256Sign, BENCH_THROUGHPUT_OPS, 0, NULL},

benchmark/wh_bench_ops.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
#include <stdint.h>
2727

2828
/* Maximum number of operations that can be registered */
29-
#define MAX_BENCH_OPS 83
29+
#define MAX_BENCH_OPS 84
3030
/* Maximum length of operation name */
3131
#define MAX_OP_NAME 64
3232

examples/demo/client/wh_demo_client_all.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,18 @@ int wh_DemoClient_All(whClientContext* clientContext)
114114
}
115115
#endif /* !NO_AES && HAVE_AESGCM */
116116

117+
#ifdef HAVE_HKDF
118+
rc = wh_DemoClient_CryptoHkdfExport(clientContext);
119+
if (rc != 0) {
120+
return rc;
121+
}
122+
123+
rc = wh_DemoClient_CryptoHkdfCache(clientContext);
124+
if (rc != 0) {
125+
return rc;
126+
}
127+
#endif /* HAVE_HKDF */
128+
117129
#if defined(WOLFSSL_CMAC)
118130
rc = wh_DemoClient_CryptoCmac(clientContext);
119131
if (rc != 0) {

examples/demo/client/wh_demo_client_crypto.c

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1357,3 +1357,96 @@ int wh_DemoClient_CryptoCmacOneshotImport(whClientContext* clientContext)
13571357
return ret;
13581358
}
13591359
#endif /* WOLFSSL_CMAC && !NO_AES */
1360+
1361+
#if defined(HAVE_HKDF)
1362+
/*
1363+
* Demonstrates deriving key material using HKDF and exporting it directly to
1364+
* the client with the wolfCrypt API. This example provides the HKDF operation
1365+
* with input keying material (IKM), optional salt, and info. The derived output
1366+
* key material (OKM) is produced on the HSM and returned to the client buffer.
1367+
*
1368+
* After deriving the OKM, you can use it as a symmetric key (for example as an
1369+
* AES key) or application-specific secret.
1370+
*/
1371+
int wh_DemoClient_CryptoHkdfExport(whClientContext* clientContext)
1372+
{
1373+
int ret = 0;
1374+
int devId = WH_DEV_ID;
1375+
/* Example inputs for HKDF. The data mirrors sizes from RFC 5869 test case 1
1376+
*/
1377+
const byte ikm[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1378+
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F};
1379+
const byte salt[] = {0xA0, 0xA1, 0xA2, 0xA3};
1380+
const byte info[] = {0xB0, 0xB1, 0xB2, 0xB3, 0xB4};
1381+
byte okm[32]; /* 32 bytes for WC_SHA256-based HKDF */
1382+
1383+
(void)clientContext; /* Unused in the export form */
1384+
1385+
/* Derive 32 bytes using HKDF with SHA-256. The OKM is exported directly
1386+
* back to the client buffer 'okm'. */
1387+
ret = wc_HKDF_ex(WC_SHA256, ikm, sizeof(ikm), salt, sizeof(salt), info,
1388+
sizeof(info), okm, (word32)sizeof(okm), NULL, devId);
1389+
if (ret != 0) {
1390+
printf("Failed to wc_HKDF_ex %d\n", ret);
1391+
}
1392+
1393+
/* At this point 'okm' holds the derived key material.
1394+
* Now you can use the key for your application. */
1395+
1396+
return ret;
1397+
}
1398+
1399+
/*
1400+
* Demonstrates deriving key material using HKDF and storing it in the HSM
1401+
* key cache. The client does not receive the key material; instead, it gets a
1402+
* keyId that can be used with compatible operations (for example, attaching
1403+
* the keyId to an AES context).
1404+
*
1405+
* After the key is cached, you can reference it by keyId for relevant
1406+
* operations. This example optionally evicts the cached key at the end.
1407+
*/
1408+
int wh_DemoClient_CryptoHkdfCache(whClientContext* clientContext)
1409+
{
1410+
int ret = 0;
1411+
int needEvict = 0;
1412+
whKeyId keyId = WH_KEYID_ERASED;
1413+
/* Example inputs for HKDF. */
1414+
const byte ikm[] = {0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
1415+
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F};
1416+
const byte salt[] = {0xC0, 0xC1, 0xC2, 0xC3};
1417+
const byte info[] = {0xD0, 0xD1, 0xD2};
1418+
const uint32_t outSz = 32; /* arbitrary output size */
1419+
/* Metadata flags/label for the cached key. Adjust to your requirements. */
1420+
whNvmFlags flags = WH_NVM_FLAGS_NONE;
1421+
char label[] = "hkdf-derived key";
1422+
1423+
/* Request the HSM to derive HKDF output and store it in the key cache.
1424+
* On success, 'keyId' is assigned by the HSM (unless pre-set) and can be
1425+
* used to reference the cached key material. */
1426+
ret = wh_Client_HkdfMakeCacheKey(
1427+
clientContext, WC_SHA256, ikm, (uint32_t)sizeof(ikm), salt,
1428+
(uint32_t)sizeof(salt), info, (uint32_t)sizeof(info), &keyId, flags,
1429+
(const uint8_t*)label, (uint32_t)strlen(label), outSz);
1430+
if (ret != WH_ERROR_OK) {
1431+
printf("Failed to wh_Client_HkdfMakeCacheKey %d\n", ret);
1432+
goto exit;
1433+
}
1434+
1435+
needEvict = 1;
1436+
1437+
/* Now you can use the cached key, referring to it by ID for relevant
1438+
* operations. */
1439+
1440+
exit:
1441+
if (needEvict) {
1442+
int evictRet = wh_Client_KeyEvict(clientContext, keyId);
1443+
if (evictRet != 0) {
1444+
printf("Failed to wh_Client_KeyEvict %d\n", evictRet);
1445+
if (ret == 0) {
1446+
ret = evictRet;
1447+
}
1448+
}
1449+
}
1450+
return ret;
1451+
}
1452+
#endif /* HAVE_HKDF */

examples/demo/client/wh_demo_client_crypto.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,9 @@ int wh_DemoClient_CryptoCmac(whClientContext* clientContext);
2222
int wh_DemoClient_CryptoCmacImport(whClientContext* clientContext);
2323
int wh_DemoClient_CryptoCmacOneshotImport(whClientContext* clientContext);
2424

25+
#ifdef HAVE_HKDF
26+
int wh_DemoClient_CryptoHkdfExport(whClientContext* clientContext);
27+
int wh_DemoClient_CryptoHkdfCache(whClientContext* clientContext);
28+
#endif /* HAVE_HKDF */
29+
2530
#endif /* !DEMO_CLIENT_CRYPTO_H_ */

0 commit comments

Comments
 (0)