Skip to content

Commit 65fc021

Browse files
committed
STM32 DHUK Support
1 parent 29f2ff4 commit 65fc021

7 files changed

Lines changed: 2004 additions & 158 deletions

File tree

wolfcrypt/src/dhuk.c

Lines changed: 342 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,342 @@
1+
/* dhuk.c
2+
*
3+
* Copyright (C) 2006-2026 wolfSSL Inc.
4+
*
5+
* This file is part of wolfSSL.
6+
*
7+
* wolfSSL is free software; you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation; either version 3 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* wolfSSL is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with this program; if not, write to the Free Software
19+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
20+
*/
21+
22+
#ifdef HAVE_CONFIG_H
23+
#include <config.h>
24+
#endif
25+
26+
#include <wolfssl/wolfcrypt/settings.h>
27+
#include <wolfssl/wolfcrypt/dhuk.h>
28+
29+
#ifdef WOLFSSL_DHUK
30+
31+
#ifndef WOLF_CRYPTO_CB
32+
#error "WOLFSSL_DHUK requires WOLF_CRYPTO_CB (crypto callback dispatch)"
33+
#endif
34+
35+
#include <wolfssl/wolfcrypt/cryptocb.h>
36+
#include <wolfssl/wolfcrypt/error-crypt.h>
37+
#include <wolfssl/wolfcrypt/wc_port.h>
38+
#include <wolfssl/wolfcrypt/aes.h>
39+
#ifdef HAVE_ECC
40+
#include <wolfssl/wolfcrypt/ecc.h>
41+
#endif
42+
43+
#ifdef NO_INLINE
44+
#include <wolfssl/wolfcrypt/misc.h>
45+
#else
46+
#define WOLFSSL_MISC_INCLUDED
47+
#include <wolfcrypt/src/misc.c>
48+
#endif
49+
50+
/* Constant-time tag compare (no early-exit on a MAC value). Returns 0 when
51+
* equal, non-zero otherwise. */
52+
static int dhuk_ct_cmp(const byte* a, const byte* b, word32 n)
53+
{
54+
byte diff = 0;
55+
word32 i;
56+
for (i = 0; i < n; i++) {
57+
diff |= (byte)(a[i] ^ b[i]);
58+
}
59+
return (int)diff;
60+
}
61+
62+
int wc_DhukInit(Wc_DhukCtx* ctx, const Wc_DhukBackend* be, void* beCtx)
63+
{
64+
int ret = 0;
65+
66+
if (ctx == NULL || be == NULL) {
67+
return BAD_FUNC_ARG;
68+
}
69+
if (be->derive_key_from_seed == NULL) {
70+
return BAD_FUNC_ARG; /* derive-from-seed is mandatory */
71+
}
72+
ctx->be = be;
73+
ctx->beCtx = beCtx;
74+
75+
if (be->init != NULL) {
76+
ret = be->init(beCtx);
77+
}
78+
return ret;
79+
}
80+
81+
int wc_DhukRegister(int devId, Wc_DhukCtx* ctx)
82+
{
83+
if (ctx == NULL || ctx->be == NULL) {
84+
return BAD_FUNC_ARG;
85+
}
86+
return wc_CryptoCb_RegisterDevice(devId, wc_DhukCryptoCb, ctx);
87+
}
88+
89+
void wc_DhukUnRegister(int devId)
90+
{
91+
wc_CryptoCb_UnRegisterDevice(devId);
92+
}
93+
94+
int wc_DhukKeyInit(Wc_DhukKey* k, const byte* seed, word32 seedSz)
95+
{
96+
if (k == NULL || seed == NULL) {
97+
return BAD_FUNC_ARG;
98+
}
99+
if (seedSz != WC_DHUK_SEED_SZ) {
100+
return BAD_FUNC_ARG;
101+
}
102+
XMEMSET(k, 0, sizeof(*k));
103+
XMEMCPY(k->seed, seed, WC_DHUK_SEED_SZ);
104+
k->seedSz = WC_DHUK_SEED_SZ;
105+
k->flags = WC_DHUK_FLAG_NONE;
106+
k->beCtx = NULL;
107+
return 0;
108+
}
109+
110+
void wc_DhukKeyFree(Wc_DhukKey* k)
111+
{
112+
if (k != NULL) {
113+
ForceZero(k->seed, sizeof(k->seed));
114+
k->seedSz = 0;
115+
}
116+
}
117+
118+
int wc_AesUseDhukKey(struct Aes* aes, int devId, Wc_DhukKey* k)
119+
{
120+
if (aes == NULL || k == NULL) {
121+
return BAD_FUNC_ARG;
122+
}
123+
if (k->seedSz != WC_DHUK_SEED_SZ) {
124+
return BAD_FUNC_ARG;
125+
}
126+
((Aes*)aes)->devId = devId;
127+
((Aes*)aes)->devCtx = (void*)k;
128+
/* The DHUK-derived working key is 256-bit; set keylen so generic AES
129+
* entry points (e.g. wc_AesGetKeySize) accept the object before the
130+
* crypto-callback dispatch takes over. No key material is stored. */
131+
((Aes*)aes)->keylen = 32;
132+
return 0;
133+
}
134+
135+
#ifdef HAVE_ECC
136+
int wc_ecc_use_dhuk_key(struct ecc_key* key, int devId, Wc_DhukKey* k)
137+
{
138+
if (key == NULL || k == NULL) {
139+
return BAD_FUNC_ARG;
140+
}
141+
if (k->seedSz != WC_DHUK_SEED_SZ) {
142+
return BAD_FUNC_ARG;
143+
}
144+
((ecc_key*)key)->devId = devId;
145+
((ecc_key*)key)->devCtx = (void*)k;
146+
return 0;
147+
}
148+
#endif /* HAVE_ECC */
149+
150+
#ifndef NO_AES
151+
/* Fetch + validate the DHUK key handle attached to an Aes; NULL if not ours. */
152+
static Wc_DhukKey* dhuk_aes_key(Aes* aes)
153+
{
154+
Wc_DhukKey* dk;
155+
if (aes == NULL) {
156+
return NULL;
157+
}
158+
dk = (Wc_DhukKey*)aes->devCtx;
159+
if (dk == NULL || dk->seedSz != WC_DHUK_SEED_SZ) {
160+
return NULL;
161+
}
162+
return dk;
163+
}
164+
#endif
165+
166+
/* Route a cipher (AES ECB/CBC, AES-GCM/GMAC) request to the backend. */
167+
static int dhuk_cipher(const Wc_DhukCtx* dctx, struct wc_CryptoInfo* info)
168+
{
169+
#ifndef NO_AES
170+
const Wc_DhukBackend* be = dctx->be;
171+
Wc_DhukKey* dk;
172+
int ret;
173+
174+
switch (info->cipher.type) {
175+
#if defined(HAVE_AES_ECB) || defined(WOLFSSL_AES_DIRECT) || \
176+
defined(WOLF_CRYPTO_CB_ONLY_AES)
177+
case WC_CIPHER_AES_ECB:
178+
dk = dhuk_aes_key(info->cipher.aesecb.aes);
179+
if (dk == NULL || be->do_aes == NULL) {
180+
return CRYPTOCB_UNAVAILABLE;
181+
}
182+
ret = be->derive_key_from_seed(dctx->beCtx, dk->seed, dk->seedSz);
183+
if (ret != 0) {
184+
return ret;
185+
}
186+
return be->do_aes(dctx->beCtx, WC_DHUK_MODE_ECB, info->cipher.enc,
187+
info->cipher.aesecb.in, info->cipher.aesecb.sz,
188+
info->cipher.aesecb.out, NULL, 0);
189+
#endif
190+
#if defined(HAVE_AES_CBC)
191+
case WC_CIPHER_AES_CBC:
192+
dk = dhuk_aes_key(info->cipher.aescbc.aes);
193+
if (dk == NULL || be->do_aes == NULL) {
194+
return CRYPTOCB_UNAVAILABLE;
195+
}
196+
ret = be->derive_key_from_seed(dctx->beCtx, dk->seed, dk->seedSz);
197+
if (ret != 0) {
198+
return ret;
199+
}
200+
ret = be->do_aes(dctx->beCtx, WC_DHUK_MODE_CBC, info->cipher.enc,
201+
info->cipher.aescbc.in, info->cipher.aescbc.sz,
202+
info->cipher.aescbc.out,
203+
(const byte*)info->cipher.aescbc.aes->reg,
204+
WC_AES_BLOCK_SIZE);
205+
if (ret == 0) {
206+
/* Update the chaining IV (aes->reg) for the next CBC call. */
207+
if (info->cipher.enc) {
208+
XMEMCPY(info->cipher.aescbc.aes->reg,
209+
info->cipher.aescbc.out + info->cipher.aescbc.sz
210+
- WC_AES_BLOCK_SIZE, WC_AES_BLOCK_SIZE);
211+
}
212+
else {
213+
XMEMCPY(info->cipher.aescbc.aes->reg,
214+
info->cipher.aescbc.in + info->cipher.aescbc.sz
215+
- WC_AES_BLOCK_SIZE, WC_AES_BLOCK_SIZE);
216+
}
217+
}
218+
return ret;
219+
#endif
220+
#ifdef HAVE_AESGCM
221+
case WC_CIPHER_AES_GCM:
222+
/* GMAC = AES-GCM with empty plaintext. Full GCM payload encryption is
223+
* a follow-on (needs a CTR + GHASH path). */
224+
if (info->cipher.enc) {
225+
dk = dhuk_aes_key(info->cipher.aesgcm_enc.aes);
226+
if (dk == NULL || be->do_gmac == NULL) {
227+
return CRYPTOCB_UNAVAILABLE;
228+
}
229+
if (info->cipher.aesgcm_enc.sz != 0) {
230+
return CRYPTOCB_UNAVAILABLE;
231+
}
232+
ret = be->derive_key_from_seed(dctx->beCtx, dk->seed, dk->seedSz);
233+
if (ret != 0) {
234+
return ret;
235+
}
236+
return be->do_gmac(dctx->beCtx,
237+
info->cipher.aesgcm_enc.iv,
238+
info->cipher.aesgcm_enc.ivSz,
239+
info->cipher.aesgcm_enc.authIn,
240+
info->cipher.aesgcm_enc.authInSz,
241+
info->cipher.aesgcm_enc.authTag,
242+
info->cipher.aesgcm_enc.authTagSz);
243+
}
244+
else {
245+
byte tag[WC_AES_BLOCK_SIZE];
246+
word32 tagSz = info->cipher.aesgcm_dec.authTagSz;
247+
dk = dhuk_aes_key(info->cipher.aesgcm_dec.aes);
248+
if (dk == NULL || be->do_gmac == NULL) {
249+
return CRYPTOCB_UNAVAILABLE;
250+
}
251+
if (info->cipher.aesgcm_dec.sz != 0) {
252+
return CRYPTOCB_UNAVAILABLE;
253+
}
254+
if (tagSz == 0 || tagSz > sizeof(tag)) {
255+
return BAD_FUNC_ARG;
256+
}
257+
ret = be->derive_key_from_seed(dctx->beCtx, dk->seed, dk->seedSz);
258+
if (ret != 0) {
259+
return ret;
260+
}
261+
XMEMSET(tag, 0, sizeof(tag));
262+
ret = be->do_gmac(dctx->beCtx,
263+
info->cipher.aesgcm_dec.iv,
264+
info->cipher.aesgcm_dec.ivSz,
265+
info->cipher.aesgcm_dec.authIn,
266+
info->cipher.aesgcm_dec.authInSz,
267+
tag, tagSz);
268+
if (ret != 0) {
269+
ForceZero(tag, sizeof(tag));
270+
return ret;
271+
}
272+
ret = dhuk_ct_cmp(tag, info->cipher.aesgcm_dec.authTag, tagSz);
273+
ForceZero(tag, sizeof(tag));
274+
return (ret == 0) ? 0 : AES_GCM_AUTH_E;
275+
}
276+
#endif
277+
default:
278+
return CRYPTOCB_UNAVAILABLE;
279+
}
280+
#else
281+
(void)dctx; (void)info;
282+
return CRYPTOCB_UNAVAILABLE;
283+
#endif /* !NO_AES */
284+
}
285+
286+
#if defined(HAVE_ECC) && defined(HAVE_ECC_SIGN)
287+
/* Route an ECDSA sign request to the backend. */
288+
static int dhuk_pk_sign(const Wc_DhukCtx* dctx, struct wc_CryptoInfo* info)
289+
{
290+
const Wc_DhukBackend* be = dctx->be;
291+
ecc_key* key = info->pk.eccsign.key;
292+
Wc_DhukKey* dk;
293+
int ret;
294+
295+
if (key == NULL) {
296+
return CRYPTOCB_UNAVAILABLE;
297+
}
298+
dk = (Wc_DhukKey*)key->devCtx;
299+
if (dk == NULL || dk->seedSz != WC_DHUK_SEED_SZ) {
300+
return CRYPTOCB_UNAVAILABLE;
301+
}
302+
if (be->sign == NULL) {
303+
return CRYPTOCB_UNAVAILABLE; /* backend has no signer */
304+
}
305+
ret = be->derive_key_from_seed(dctx->beCtx, dk->seed, dk->seedSz);
306+
if (ret != 0) {
307+
return ret;
308+
}
309+
return be->sign(dctx->beCtx, key,
310+
info->pk.eccsign.in, info->pk.eccsign.inlen,
311+
info->pk.eccsign.out, info->pk.eccsign.outlen,
312+
info->pk.eccsign.rng);
313+
}
314+
#endif /* HAVE_ECC && HAVE_ECC_SIGN */
315+
316+
int wc_DhukCryptoCb(int devId, struct wc_CryptoInfo* info, void* ctx)
317+
{
318+
Wc_DhukCtx* dctx = (Wc_DhukCtx*)ctx;
319+
320+
(void)devId;
321+
if (info == NULL || dctx == NULL || dctx->be == NULL) {
322+
return CRYPTOCB_UNAVAILABLE;
323+
}
324+
325+
switch (info->algo_type) {
326+
case WC_ALGO_TYPE_CIPHER:
327+
return dhuk_cipher(dctx, info);
328+
329+
#if defined(HAVE_ECC) && defined(HAVE_ECC_SIGN)
330+
case WC_ALGO_TYPE_PK:
331+
if (info->pk.type == WC_PK_TYPE_ECDSA_SIGN) {
332+
return dhuk_pk_sign(dctx, info);
333+
}
334+
return CRYPTOCB_UNAVAILABLE;
335+
#endif
336+
337+
default:
338+
return CRYPTOCB_UNAVAILABLE;
339+
}
340+
}
341+
342+
#endif /* WOLFSSL_DHUK */

0 commit comments

Comments
 (0)