Skip to content

Commit 669c4de

Browse files
committed
Add RealTek AmebaPro2 (RTL8735B) HUK wolfCrypt example
1 parent 8eb7fa1 commit 669c4de

4 files changed

Lines changed: 449 additions & 0 deletions

File tree

AmebaPro2/README.md

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# wolfCrypt on RealTek AmebaPro2 (RTL8735B) -- Hardware Unique Key (HUK)
2+
3+
This example demonstrates wolfCrypt AES-GCM, AES-ECB, AES-CBC and AES-CTR bound to the RealTek RTL8735B silicon **Hardware Unique Key (HUK)** through the wolfCrypt crypto-callback (CryptoCb) framework. A 256-bit "seed" is run through the AmebaPro2 HAL secure HKDF key-ladder against the HUK to derive a per-purpose working key inside a secure key-storage slot; that working key never enters software. The application just sets the seed as the AES key and uses the normal wolfCrypt AES APIs -- the RealTek HUK crypto-callback device does the rest.
4+
5+
It is built inside the RealTek AmebaPro2 FreeRTOS SDK (which provides the startup, HAL, and the `elf2bin`/`uartfwburn` image+flash tooling).
6+
7+
## What it shows
8+
9+
- Registering the HUK crypto-callback device: `wc_AmebaPro2_HukRegister(WC_HUK_DEVID)`.
10+
- AES-GCM (full payload), AES-ECB, AES-CBC and AES-CTR run under the HUK-derived key (init an `Aes` with `devId = WC_HUK_DEVID`, then use the usual `wc_AesGcmSetKey`/`wc_AesGcmEncrypt`, `wc_AesSetKey`/`wc_AesEcb*`/`wc_AesCbc*`, `wc_AesSetKeyDirect`/`wc_AesCtrEncrypt`).
11+
- The key is device-bound and deterministic: the same seed yields the same key (so GMAC verifies and AES round-trips), and a different seed yields a different key (GCM decrypt returns `AES_GCM_AUTH_E`).
12+
- The port tolerates unaligned caller buffers (it bounces them to satisfy the HAL's 32-byte alignment); the example includes an explicitly-unaligned GCM check.
13+
14+
## Prerequisites
15+
16+
- RealTek AmebaPro2 FreeRTOS SDK: https://github.com/Ameba-AIoT/ameba-rtos-pro2
17+
- RealTek ASDK 10.3.0 toolchain (GCC 10.3.0): https://github.com/Ameba-AIoT/ameba-toolchain (tag `V10.3.0-ameba-rtos-pro2`). The stock system `arm-none-eabi-gcc` does not build the SDK (newlib/lwip header clashes); use the ASDK toolchain.
18+
- wolfSSL with the RealTek HUK port (`wolfcrypt/src/port/realtek/amebapro2.c` and `wolfssl/wolfcrypt/port/realtek/amebapro2.h`). Enable with `WOLFSSL_REALTEK_HUK` (which implies `WOLFSSL_DHUK`) and `WOLF_CRYPTO_CB`.
19+
20+
## Files
21+
22+
- `main.c` -- the example application (a FreeRTOS task that registers the HUK device and runs the AES-GCM/ECB/CBC/CTR checks plus an unaligned-buffer GCM check).
23+
- `user_settings.h` -- a lean wolfCrypt configuration for this example.
24+
- `wolfcrypt_huk.cmake` -- wiring that adds wolfCrypt + the RealTek HUK port to the SDK app build.
25+
26+
## Build
27+
28+
1. Copy this directory into the SDK as an example component:
29+
`cp -r AmebaPro2 <SDK>/component/example/wolfcrypt_huk`
30+
2. Install the example `main()` as the project app:
31+
`cp <SDK>/component/example/wolfcrypt_huk/main.c <SDK>/project/realtek_amebapro2_v0_example/src/main.c`
32+
3. Configure and build with the ASDK toolchain on PATH, pointing `WOLFSSL_ROOT` at your wolfSSL tree:
33+
```
34+
export PATH=<asdk>/asdk-10.3.0/linux/newlib/bin:$PATH
35+
cd <SDK>/project/realtek_amebapro2_v0_example/GCC-RELEASE
36+
mkdir -p build && cd build
37+
cmake .. -G"Unix Makefiles" -DCMAKE_TOOLCHAIN_FILE=../toolchain.cmake \
38+
-DBUILD_FPGA=OFF -DBUILD_PXP=OFF \
39+
-DEXAMPLE=wolfcrypt_huk -DWOLFSSL_ROOT=<path-to-wolfssl>
40+
make flash -j8
41+
```
42+
The output image is `build/flash_ntz.bin`.
43+
44+
## Flash and run
45+
46+
Put the board in download mode (J27 jumper + reset), then flash over UART with the SDK `uartfwburn` tool (from the SDK `tools/Pro2_PG_tool*` directory, which also holds `boot_recover.bin`, `flash_loader_nor.bin`, `flash_control_info.bin`):
47+
```
48+
./uartfwburn.linux -p <COM_PORT> -f <build>/flash_ntz.bin -b 3000000 -U
49+
```
50+
Remove the J27 jumper and reset to boot. The console (UART, 115200) prints:
51+
```
52+
=== wolfCrypt AmebaPro2 (RTL8735B) HUK example ===
53+
[PASS] wolfCrypt_Init
54+
[PASS] wc_AmebaPro2_HukRegister
55+
== AES-GCM (full payload) under HUK-derived key ==
56+
[PASS] AesInit(devId=WC_HUK_DEVID)
57+
[PASS] AesGcmSetKey(seed,32)
58+
[PASS] AesGcmEncrypt
59+
[PASS] deterministic tag
60+
[PASS] AesGcmDecrypt verifies
61+
[PASS] plaintext round-trips
62+
[PASS] wrong seed -> AES_GCM_AUTH_E
63+
== AES-ECB under HUK-derived key == ... round-trip PASS
64+
== AES-CBC under HUK-derived key == ... round-trip PASS
65+
== AES-CTR under HUK-derived key == ... round-trip PASS
66+
== AES-GCM with UNALIGNED buffers (port bounces) == ... round-trip PASS
67+
=== done ===
68+
```
69+
70+
## Notes
71+
72+
- The AmebaPro2 HAL crypto engine DMAs its key/IV/AAD/tag buffers on 32-byte boundaries; the port stages and bounces buffers as needed, so callers need not align (the example aligns its buffers anyway, and adds an explicitly-unaligned GCM case to exercise the bounce path).
73+
- The seed is HKDF input, not the AES key itself -- it diversifies the HUK into a working key. Keep the seed stable for a given purpose to get a stable derived key.
74+
- HUK-bound ECDSA signing is a planned follow-on; this example covers the AES surface.
75+
- Port internals (the HKDF key-ladder, slot configuration macros such as `WC_HUK_DEVID`, `WC_AMEBAPRO2_*`) are documented in `wolfssl/wolfcrypt/port/realtek/amebapro2.h` and `wolfcrypt/src/port/realtek/README.md` in the wolfSSL tree.

AmebaPro2/main.c

Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
/* wolfCrypt AmebaPro2 (RTL8735B) HUK example -- built inside the RealTek
2+
* FreeRTOS SDK. Registers the wolfCrypt HUK crypto-callback device and runs
3+
* AES-GCM (full payload) / AES-ECB / AES-CBC under a key derived from the
4+
* silicon Hardware Unique Key; the working key never enters software. The
5+
* 256-bit "seed" passed as the AES key is HKDF input diversifying the HUK.
6+
*
7+
* Build: configure with -DEXAMPLE=wolfcrypt_huk (see wolfcrypt_huk.cmake).
8+
*/
9+
10+
#include "platform_stdlib.h"
11+
#include "FreeRTOS.h"
12+
#include "task.h"
13+
#include "device_lock.h"
14+
#include "hal_trng.h"
15+
16+
#include <wolfssl/wolfcrypt/settings.h>
17+
#include <wolfssl/wolfcrypt/wc_port.h>
18+
#include <wolfssl/wolfcrypt/aes.h>
19+
#include <wolfssl/wolfcrypt/error-crypt.h>
20+
#include <wolfssl/wolfcrypt/port/realtek/amebapro2.h>
21+
22+
#define STACKSIZE 8192
23+
24+
#define CHECK(label, cond) \
25+
dbg_printf("[%s] %s\r\n", (cond) ? "PASS" : "FAIL", (label))
26+
27+
/* wolfCrypt RNG seed hook (user_settings: CUSTOM_RAND_GENERATE_SEED). Fills
28+
* from the AmebaPro2 hardware TRNG. */
29+
int amebapro2_rand_seed(unsigned char* output, unsigned int sz)
30+
{
31+
static hal_trng_sec_adapter_t trng;
32+
static int inited = 0;
33+
unsigned int i;
34+
35+
if (!inited) {
36+
if (hal_trng_init(&trng) != 0) {
37+
return -1;
38+
}
39+
inited = 1;
40+
}
41+
for (i = 0; i < sz; ) {
42+
u32 r = hal_trng_get_rand(&trng);
43+
unsigned int n = (sz - i) < 4u ? (sz - i) : 4u;
44+
memcpy(output + i, &r, n);
45+
i += n;
46+
}
47+
return 0;
48+
}
49+
50+
static void huk_gcm_test(void)
51+
{
52+
Aes aes;
53+
/* HAL crypto engine requires 32-byte-aligned key/iv/aad/tag buffers. */
54+
byte seed[32] __attribute__((aligned(32)));
55+
byte iv[12] __attribute__((aligned(32)));
56+
byte aad[16] __attribute__((aligned(32)));
57+
byte pt[32] __attribute__((aligned(32)));
58+
byte ct[32] __attribute__((aligned(32)));
59+
byte dec[32] __attribute__((aligned(32)));
60+
byte tag[16] __attribute__((aligned(32)));
61+
byte tag2[16] __attribute__((aligned(32)));
62+
int ret;
63+
64+
memset(seed, 0xA5, sizeof(seed)); memset(iv, 0x11, sizeof(iv));
65+
memset(aad, 0x22, sizeof(aad)); memset(pt, 0x33, sizeof(pt));
66+
67+
dbg_printf("\r\n== AES-GCM (full payload) under HUK-derived key ==\r\n");
68+
ret = wc_AesInit(&aes, NULL, WC_HUK_DEVID);
69+
CHECK("AesInit(devId=WC_HUK_DEVID)", ret == 0);
70+
ret = wc_AesGcmSetKey(&aes, seed, sizeof(seed));
71+
CHECK("AesGcmSetKey(seed,32)", ret == 0);
72+
73+
ret = wc_AesGcmEncrypt(&aes, ct, pt, sizeof(pt), iv, sizeof(iv),
74+
tag, sizeof(tag), aad, sizeof(aad));
75+
CHECK("AesGcmEncrypt", ret == 0);
76+
77+
memset(tag2, 0, sizeof(tag2));
78+
ret = wc_AesGcmEncrypt(&aes, ct, pt, sizeof(pt), iv, sizeof(iv),
79+
tag2, sizeof(tag2), aad, sizeof(aad));
80+
CHECK("deterministic tag", ret == 0 && memcmp(tag, tag2, 16) == 0);
81+
82+
ret = wc_AesGcmDecrypt(&aes, dec, ct, sizeof(ct), iv, sizeof(iv),
83+
tag, sizeof(tag), aad, sizeof(aad));
84+
CHECK("AesGcmDecrypt verifies", ret == 0);
85+
CHECK("plaintext round-trips", memcmp(dec, pt, sizeof(pt)) == 0);
86+
87+
seed[0] ^= 0xFF;
88+
ret = wc_AesGcmSetKey(&aes, seed, sizeof(seed));
89+
CHECK("AesGcmSetKey(wrong seed)", ret == 0);
90+
ret = wc_AesGcmDecrypt(&aes, dec, ct, sizeof(ct), iv, sizeof(iv),
91+
tag, sizeof(tag), aad, sizeof(aad));
92+
CHECK("wrong seed -> AES_GCM_AUTH_E", ret == AES_GCM_AUTH_E);
93+
wc_AesFree(&aes);
94+
}
95+
96+
static void huk_ecb_cbc_test(void)
97+
{
98+
Aes aes;
99+
byte seed[32] __attribute__((aligned(32)));
100+
byte iv[16] __attribute__((aligned(32)));
101+
byte pt[32] __attribute__((aligned(32)));
102+
byte ct[32] __attribute__((aligned(32)));
103+
byte dec[32] __attribute__((aligned(32)));
104+
int ret;
105+
106+
memset(seed, 0x5A, sizeof(seed)); memset(iv, 0x44, sizeof(iv));
107+
memset(pt, 0x77, sizeof(pt));
108+
109+
dbg_printf("\r\n== AES-ECB under HUK-derived key ==\r\n");
110+
ret = wc_AesInit(&aes, NULL, WC_HUK_DEVID);
111+
CHECK("AesInit(devId=WC_HUK_DEVID)", ret == 0);
112+
if (ret != 0) {
113+
return;
114+
}
115+
ret = wc_AesSetKey(&aes, seed, sizeof(seed), NULL, AES_ENCRYPTION);
116+
CHECK("AesSetKey(ECB enc)", ret == 0);
117+
ret = wc_AesEcbEncrypt(&aes, ct, pt, sizeof(pt));
118+
CHECK("AesEcbEncrypt", ret == 0);
119+
wc_AesSetKey(&aes, seed, sizeof(seed), NULL, AES_DECRYPTION);
120+
ret = wc_AesEcbDecrypt(&aes, dec, ct, sizeof(ct));
121+
CHECK("AesEcb round-trip", ret == 0 && memcmp(dec, pt, sizeof(pt)) == 0);
122+
wc_AesFree(&aes);
123+
124+
dbg_printf("\r\n== AES-CBC under HUK-derived key ==\r\n");
125+
ret = wc_AesInit(&aes, NULL, WC_HUK_DEVID);
126+
CHECK("AesInit(devId=WC_HUK_DEVID)", ret == 0);
127+
if (ret != 0) {
128+
return;
129+
}
130+
ret = wc_AesSetKey(&aes, seed, sizeof(seed), iv, AES_ENCRYPTION);
131+
CHECK("AesSetKey(CBC enc)", ret == 0);
132+
ret = wc_AesCbcEncrypt(&aes, ct, pt, sizeof(pt));
133+
CHECK("AesCbcEncrypt", ret == 0);
134+
wc_AesSetKey(&aes, seed, sizeof(seed), iv, AES_DECRYPTION);
135+
ret = wc_AesCbcDecrypt(&aes, dec, ct, sizeof(ct));
136+
CHECK("AesCbc round-trip", ret == 0 && memcmp(dec, pt, sizeof(pt)) == 0);
137+
wc_AesFree(&aes);
138+
}
139+
140+
static void huk_ctr_test(void)
141+
{
142+
Aes aes;
143+
byte seed[32] __attribute__((aligned(32)));
144+
byte iv[16] __attribute__((aligned(32)));
145+
byte pt[20] __attribute__((aligned(32))); /* non-block-multiple: partial */
146+
byte ct[20] __attribute__((aligned(32)));
147+
byte dec[20] __attribute__((aligned(32)));
148+
int ret;
149+
150+
memset(seed, 0x5A, sizeof(seed)); memset(iv, 0x66, sizeof(iv));
151+
memset(pt, 0x99, sizeof(pt));
152+
153+
dbg_printf("\r\n== AES-CTR under HUK-derived key ==\r\n");
154+
ret = wc_AesInit(&aes, NULL, WC_HUK_DEVID);
155+
CHECK("AesInit(devId=WC_HUK_DEVID)", ret == 0);
156+
if (ret != 0) {
157+
return;
158+
}
159+
ret = wc_AesSetKeyDirect(&aes, seed, sizeof(seed), iv, AES_ENCRYPTION);
160+
CHECK("AesSetKeyDirect(CTR)", ret == 0);
161+
ret = wc_AesCtrEncrypt(&aes, ct, pt, sizeof(pt));
162+
CHECK("AesCtrEncrypt", ret == 0);
163+
CHECK("CTR ciphertext != plaintext", memcmp(ct, pt, sizeof(pt)) != 0);
164+
wc_AesFree(&aes);
165+
166+
/* CTR is its own inverse with the same key+IV */
167+
ret = wc_AesInit(&aes, NULL, WC_HUK_DEVID);
168+
CHECK("AesInit(devId=WC_HUK_DEVID)", ret == 0);
169+
if (ret != 0) {
170+
return;
171+
}
172+
ret = wc_AesSetKeyDirect(&aes, seed, sizeof(seed), iv, AES_ENCRYPTION);
173+
CHECK("AesSetKeyDirect(CTR round-trip)", ret == 0);
174+
ret = wc_AesCtrEncrypt(&aes, dec, ct, sizeof(ct));
175+
CHECK("AesCtr round-trip", ret == 0 && memcmp(dec, pt, sizeof(pt)) == 0);
176+
wc_AesFree(&aes);
177+
}
178+
179+
static void huk_gcm_unaligned_test(void)
180+
{
181+
Aes aes;
182+
/* 32-byte-aligned backing; the +1 views below are deliberately unaligned so
183+
* the port's bounce-to-aligned path is exercised. */
184+
byte buf[7][48] __attribute__((aligned(32)));
185+
byte* seed = buf[0] + 1;
186+
byte* iv = buf[1] + 1;
187+
byte* aad = buf[2] + 1;
188+
byte* pt = buf[3] + 1;
189+
byte* ct = buf[4] + 1;
190+
byte* dec = buf[5] + 1;
191+
byte* tag = buf[6] + 1;
192+
int ret;
193+
194+
memset(seed, 0xA5, 32); memset(iv, 0x11, 12);
195+
memset(aad, 0x22, 16); memset(pt, 0x33, 32);
196+
197+
dbg_printf("\r\n== AES-GCM with UNALIGNED buffers (port bounces) ==\r\n");
198+
ret = wc_AesInit(&aes, NULL, WC_HUK_DEVID);
199+
CHECK("AesInit(devId=WC_HUK_DEVID)", ret == 0);
200+
if (ret != 0) {
201+
return;
202+
}
203+
ret = wc_AesGcmSetKey(&aes, seed, 32);
204+
CHECK("AesGcmSetKey (unaligned seed)", ret == 0);
205+
ret = wc_AesGcmEncrypt(&aes, ct, pt, 32, iv, 12, tag, 16, aad, 16);
206+
CHECK("AesGcmEncrypt (unaligned)", ret == 0);
207+
ret = wc_AesGcmDecrypt(&aes, dec, ct, 32, iv, 12, tag, 16, aad, 16);
208+
CHECK("AesGcmDecrypt (unaligned) verifies", ret == 0);
209+
CHECK("unaligned round-trip", memcmp(dec, pt, 32) == 0);
210+
wc_AesFree(&aes);
211+
}
212+
213+
static void wolf_huk_thread(void* param)
214+
{
215+
int ret;
216+
(void)param;
217+
218+
dbg_printf("\r\n=== wolfCrypt AmebaPro2 (RTL8735B) HUK example ===\r\n");
219+
220+
device_mutex_lock(RT_DEV_LOCK_CRYPTO);
221+
222+
ret = wolfCrypt_Init();
223+
CHECK("wolfCrypt_Init", ret == 0);
224+
ret = wc_AmebaPro2_HukRegister(WC_HUK_DEVID);
225+
CHECK("wc_AmebaPro2_HukRegister", ret == 0);
226+
227+
if (ret == 0) {
228+
huk_gcm_test();
229+
huk_ecb_cbc_test();
230+
huk_ctr_test();
231+
huk_gcm_unaligned_test();
232+
wc_AmebaPro2_HukUnRegister(WC_HUK_DEVID);
233+
}
234+
wolfCrypt_Cleanup();
235+
236+
device_mutex_unlock(RT_DEV_LOCK_CRYPTO);
237+
dbg_printf("\r\n=== done ===\r\n");
238+
vTaskDelete(NULL);
239+
}
240+
241+
int main(void)
242+
{
243+
if (xTaskCreate(wolf_huk_thread, "wolf_huk", STACKSIZE, NULL,
244+
tskIDLE_PRIORITY + 1, NULL) != pdPASS) {
245+
dbg_printf("xTaskCreate failed\r\n");
246+
}
247+
vTaskStartScheduler();
248+
while (1) {
249+
}
250+
}

0 commit comments

Comments
 (0)