Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions AmebaPro2/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# wolfCrypt on RealTek AmebaPro2 (RTL8735B) -- Hardware Unique Key (HUK)

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.

It is built inside the RealTek AmebaPro2 FreeRTOS SDK (which provides the startup, HAL, and the `elf2bin`/`uartfwburn` image+flash tooling).

## What it shows

- Registering the HUK crypto-callback device: `wc_AmebaPro2_HukRegister(WC_HUK_DEVID)`.
- 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`).
- 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`).
- 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.

## Prerequisites

- RealTek AmebaPro2 FreeRTOS SDK: https://github.com/Ameba-AIoT/ameba-rtos-pro2
- RealTek ASDK 10.3.0 toolchain (GCC 10.3.0): https://github.com/Ameba-AIoT/ameba-toolchain (tag `V10.3.0-amebe-rtos-pro2`). The stock system `arm-none-eabi-gcc` does not build the SDK (newlib/lwip header clashes); use the ASDK toolchain.
- 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`.

## Files

- `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).
- `user_settings.h` -- a lean wolfCrypt configuration for this example.
- `wolfcrypt_huk.cmake` -- wiring that adds wolfCrypt + the RealTek HUK port to the SDK app build.

## Build

1. Copy this directory into the SDK as an example component:
`cp -r AmebaPro2 <SDK>/component/example/wolfcrypt_huk`
2. Install the example `main()` as the project app:
`cp <SDK>/component/example/wolfcrypt_huk/main.c <SDK>/project/realtek_amebapro2_v0_example/src/main.c`
3. Configure and build with the ASDK toolchain on PATH, pointing `WOLFSSL_ROOT` at your wolfSSL tree:
```
export PATH=<asdk>/asdk-10.3.0/linux/newlib/bin:$PATH
cd <SDK>/project/realtek_amebapro2_v0_example/GCC-RELEASE
mkdir -p build && cd build
cmake .. -G"Unix Makefiles" -DCMAKE_TOOLCHAIN_FILE=../toolchain.cmake \
-DBUILD_FPGA=OFF -DBUILD_PXP=OFF \
-DEXAMPLE=wolfcrypt_huk -DWOLFSSL_ROOT=<path-to-wolfssl>
make flash -j8
```
The output image is `build/flash_ntz.bin`.

## Flash and run

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`):
```
./uartfwburn.linux -p <COM_PORT> -f <build>/flash_ntz.bin -b 3000000 -U
```
Remove the J27 jumper and reset to boot. The console (UART, 115200) prints:
```
=== wolfCrypt AmebaPro2 (RTL8735B) HUK example ===
[PASS] wolfCrypt_Init
[PASS] wc_AmebaPro2_HukRegister
== AES-GCM (full payload) under HUK-derived key ==
[PASS] AesInit(devId=WC_HUK_DEVID)
[PASS] AesGcmSetKey(seed,32)
[PASS] AesGcmEncrypt
[PASS] deterministic tag
[PASS] AesGcmDecrypt verifies
[PASS] plaintext round-trips
[PASS] wrong seed -> AES_GCM_AUTH_E
== AES-ECB under HUK-derived key == ... round-trip PASS
== AES-CBC under HUK-derived key == ... round-trip PASS
== AES-CTR under HUK-derived key == ... round-trip PASS
== AES-GCM with UNALIGNED buffers (port bounces) == ... round-trip PASS
=== done ===
```

## Notes

- 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).
- 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.
- HUK-bound ECDSA signing is a planned follow-on; this example covers the AES surface.
- 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.
228 changes: 228 additions & 0 deletions AmebaPro2/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
/* wolfCrypt AmebaPro2 (RTL8735B) HUK example -- built inside the RealTek
* FreeRTOS SDK. Registers the wolfCrypt HUK crypto-callback device and runs
* AES-GCM (full payload) / AES-ECB / AES-CBC under a key derived from the
* silicon Hardware Unique Key; the working key never enters software. The
* 256-bit "seed" passed as the AES key is HKDF input diversifying the HUK.
*
* Build: configure with -DEXAMPLE=wolfcrypt_huk (see wolfcrypt_huk.cmake).
*/

#include "platform_stdlib.h"
#include "FreeRTOS.h"
#include "task.h"
#include "device_lock.h"
#include "hal_trng.h"

#include <wolfssl/wolfcrypt/settings.h>
#include <wolfssl/wolfcrypt/wc_port.h>
#include <wolfssl/wolfcrypt/aes.h>
#include <wolfssl/wolfcrypt/error-crypt.h>
#include <wolfssl/wolfcrypt/port/realtek/amebapro2.h>

#define STACKSIZE 8192

#define CHECK(label, cond) \
dbg_printf("[%s] %s\r\n", (cond) ? "PASS" : "FAIL", (label))

/* wolfCrypt RNG seed hook (user_settings: CUSTOM_RAND_GENERATE_SEED). Fills
* from the AmebaPro2 hardware TRNG. */
int amebapro2_rand_seed(unsigned char* output, unsigned int sz)
{
static hal_trng_sec_adapter_t trng;
static int inited = 0;
unsigned int i;

if (!inited) {
if (hal_trng_init(&trng) != 0) {
return -1;
}
inited = 1;
}
for (i = 0; i < sz; ) {
u32 r = hal_trng_get_rand(&trng);
unsigned int n = (sz - i) < 4u ? (sz - i) : 4u;
memcpy(output + i, &r, n);
i += n;
}
return 0;
}

static void huk_gcm_test(void)
{
Aes aes;
/* HAL crypto engine requires 32-byte-aligned key/iv/aad/tag buffers. */
byte seed[32] __attribute__((aligned(32)));
byte iv[12] __attribute__((aligned(32)));
byte aad[16] __attribute__((aligned(32)));
byte pt[32] __attribute__((aligned(32)));
byte ct[32] __attribute__((aligned(32)));
byte dec[32] __attribute__((aligned(32)));
byte tag[16] __attribute__((aligned(32)));
byte tag2[16] __attribute__((aligned(32)));
int ret;

memset(seed, 0xA5, sizeof(seed)); memset(iv, 0x11, sizeof(iv));
memset(aad, 0x22, sizeof(aad)); memset(pt, 0x33, sizeof(pt));

dbg_printf("\r\n== AES-GCM (full payload) under HUK-derived key ==\r\n");
ret = wc_AesInit(&aes, NULL, WC_HUK_DEVID);
CHECK("AesInit(devId=WC_HUK_DEVID)", ret == 0);
ret = wc_AesGcmSetKey(&aes, seed, sizeof(seed));
CHECK("AesGcmSetKey(seed,32)", ret == 0);

ret = wc_AesGcmEncrypt(&aes, ct, pt, sizeof(pt), iv, sizeof(iv),
tag, sizeof(tag), aad, sizeof(aad));
CHECK("AesGcmEncrypt", ret == 0);

memset(tag2, 0, sizeof(tag2));
ret = wc_AesGcmEncrypt(&aes, ct, pt, sizeof(pt), iv, sizeof(iv),
tag2, sizeof(tag2), aad, sizeof(aad));
CHECK("deterministic tag", ret == 0 && memcmp(tag, tag2, 16) == 0);

ret = wc_AesGcmDecrypt(&aes, dec, ct, sizeof(ct), iv, sizeof(iv),
tag, sizeof(tag), aad, sizeof(aad));
CHECK("AesGcmDecrypt verifies", ret == 0);
CHECK("plaintext round-trips", memcmp(dec, pt, sizeof(pt)) == 0);

seed[0] ^= 0xFF;
wc_AesGcmSetKey(&aes, seed, sizeof(seed));
ret = wc_AesGcmDecrypt(&aes, dec, ct, sizeof(ct), iv, sizeof(iv),
tag, sizeof(tag), aad, sizeof(aad));
CHECK("wrong seed -> AES_GCM_AUTH_E", ret == AES_GCM_AUTH_E);
Comment on lines +87 to +91
wc_AesFree(&aes);
}

static void huk_ecb_cbc_test(void)
{
Aes aes;
byte seed[32] __attribute__((aligned(32)));
byte iv[16] __attribute__((aligned(32)));
byte pt[32] __attribute__((aligned(32)));
byte ct[32] __attribute__((aligned(32)));
byte dec[32] __attribute__((aligned(32)));
int ret;

memset(seed, 0x5A, sizeof(seed)); memset(iv, 0x44, sizeof(iv));
memset(pt, 0x77, sizeof(pt));

dbg_printf("\r\n== AES-ECB under HUK-derived key ==\r\n");
wc_AesInit(&aes, NULL, WC_HUK_DEVID);
ret = wc_AesSetKey(&aes, seed, sizeof(seed), NULL, AES_ENCRYPTION);
CHECK("AesSetKey(ECB enc)", ret == 0);
Comment on lines +108 to +111
ret = wc_AesEcbEncrypt(&aes, ct, pt, sizeof(pt));
CHECK("AesEcbEncrypt", ret == 0);
wc_AesSetKey(&aes, seed, sizeof(seed), NULL, AES_DECRYPTION);
ret = wc_AesEcbDecrypt(&aes, dec, ct, sizeof(ct));
CHECK("AesEcb round-trip", ret == 0 && memcmp(dec, pt, sizeof(pt)) == 0);
wc_AesFree(&aes);

dbg_printf("\r\n== AES-CBC under HUK-derived key ==\r\n");
wc_AesInit(&aes, NULL, WC_HUK_DEVID);
ret = wc_AesSetKey(&aes, seed, sizeof(seed), iv, AES_ENCRYPTION);
CHECK("AesSetKey(CBC enc)", ret == 0);
Comment on lines +119 to +122
ret = wc_AesCbcEncrypt(&aes, ct, pt, sizeof(pt));
CHECK("AesCbcEncrypt", ret == 0);
wc_AesSetKey(&aes, seed, sizeof(seed), iv, AES_DECRYPTION);
ret = wc_AesCbcDecrypt(&aes, dec, ct, sizeof(ct));
CHECK("AesCbc round-trip", ret == 0 && memcmp(dec, pt, sizeof(pt)) == 0);
wc_AesFree(&aes);
}

static void huk_ctr_test(void)
{
Aes aes;
byte seed[32] __attribute__((aligned(32)));
byte iv[16] __attribute__((aligned(32)));
byte pt[20] __attribute__((aligned(32))); /* non-block-multiple: partial */
byte ct[20] __attribute__((aligned(32)));
byte dec[20] __attribute__((aligned(32)));
int ret;

memset(seed, 0x5A, sizeof(seed)); memset(iv, 0x66, sizeof(iv));
memset(pt, 0x99, sizeof(pt));

dbg_printf("\r\n== AES-CTR under HUK-derived key ==\r\n");
wc_AesInit(&aes, NULL, WC_HUK_DEVID);
ret = wc_AesSetKeyDirect(&aes, seed, sizeof(seed), iv, AES_ENCRYPTION);
CHECK("AesSetKeyDirect(CTR)", ret == 0);
Comment on lines +144 to +147
ret = wc_AesCtrEncrypt(&aes, ct, pt, sizeof(pt));
CHECK("AesCtrEncrypt", ret == 0);
CHECK("CTR ciphertext != plaintext", memcmp(ct, pt, sizeof(pt)) != 0);
wc_AesFree(&aes);

/* CTR is its own inverse with the same key+IV */
wc_AesInit(&aes, NULL, WC_HUK_DEVID);
wc_AesSetKeyDirect(&aes, seed, sizeof(seed), iv, AES_ENCRYPTION);
ret = wc_AesCtrEncrypt(&aes, dec, ct, sizeof(ct));
Comment on lines +153 to +156
CHECK("AesCtr round-trip", ret == 0 && memcmp(dec, pt, sizeof(pt)) == 0);
wc_AesFree(&aes);
}

static void huk_gcm_unaligned_test(void)
{
Aes aes;
/* 32-byte-aligned backing; the +1 views below are deliberately unaligned so
* the port's bounce-to-aligned path is exercised. */
byte buf[7][48] __attribute__((aligned(32)));
byte* seed = buf[0] + 1;
byte* iv = buf[1] + 1;
byte* aad = buf[2] + 1;
byte* pt = buf[3] + 1;
byte* ct = buf[4] + 1;
byte* dec = buf[5] + 1;
byte* tag = buf[6] + 1;
int ret;

memset(seed, 0xA5, 32); memset(iv, 0x11, 12);
memset(aad, 0x22, 16); memset(pt, 0x33, 32);

dbg_printf("\r\n== AES-GCM with UNALIGNED buffers (port bounces) ==\r\n");
wc_AesInit(&aes, NULL, WC_HUK_DEVID);
ret = wc_AesGcmSetKey(&aes, seed, 32);
CHECK("AesGcmSetKey (unaligned seed)", ret == 0);
Comment on lines +179 to +182
ret = wc_AesGcmEncrypt(&aes, ct, pt, 32, iv, 12, tag, 16, aad, 16);
CHECK("AesGcmEncrypt (unaligned)", ret == 0);
ret = wc_AesGcmDecrypt(&aes, dec, ct, 32, iv, 12, tag, 16, aad, 16);
CHECK("AesGcmDecrypt (unaligned) verifies", ret == 0);
CHECK("unaligned round-trip", memcmp(dec, pt, 32) == 0);
wc_AesFree(&aes);
}

static void wolf_huk_thread(void* param)
{
int ret;
(void)param;

dbg_printf("\r\n=== wolfCrypt AmebaPro2 (RTL8735B) HUK example ===\r\n");

device_mutex_lock(RT_DEV_LOCK_CRYPTO);

ret = wolfCrypt_Init();
CHECK("wolfCrypt_Init", ret == 0);
ret = wc_AmebaPro2_HukRegister(WC_HUK_DEVID);
CHECK("wc_AmebaPro2_HukRegister", ret == 0);

if (ret == 0) {
huk_gcm_test();
huk_ecb_cbc_test();
huk_ctr_test();
huk_gcm_unaligned_test();
wc_AmebaPro2_HukUnRegister(WC_HUK_DEVID);
}
wolfCrypt_Cleanup();

device_mutex_unlock(RT_DEV_LOCK_CRYPTO);
dbg_printf("\r\n=== done ===\r\n");
vTaskDelete(NULL);
}

int main(void)
{
if (xTaskCreate(wolf_huk_thread, "wolf_huk", STACKSIZE, NULL,
tskIDLE_PRIORITY + 1, NULL) != pdPASS) {
dbg_printf("xTaskCreate failed\r\n");
}
vTaskStartScheduler();
while (1) {
}
}
73 changes: 73 additions & 0 deletions AmebaPro2/user_settings.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/* user_settings.h -- wolfCrypt config for the AmebaPro2 (RTL8735B) HUK example
* built inside the RealTek FreeRTOS SDK. AES-focused (GCM/ECB/CBC) HUK
* crypto-callback demo; ECC/ECDSA omitted to keep the build minimal. */

#ifndef AMEBAPRO2_HUK_USER_SETTINGS_H
#define AMEBAPRO2_HUK_USER_SETTINGS_H

#ifdef __cplusplus
extern "C" {
#endif

/* ---- HUK crypto-callback device (our RealTek port) ---- */
#define WOLFSSL_REALTEK_HUK
#define WOLF_CRYPTO_CB

/* ---- platform / RTOS ---- */
#define WOLFSSL_GENERAL_ALIGNMENT 4
#define SIZEOF_LONG_LONG 8
#define SINGLE_THREADED /* HW crypto serialized by the SDK device_lock */
#define NO_FILESYSTEM
#define NO_WRITEV
#define NO_MAIN_DRIVER
#define WOLFCRYPT_ONLY /* no TLS layer */
#define BENCH_EMBEDDED
#define WOLFSSL_SMALL_STACK
#define WOLFSSL_IGNORE_FILE_WARN
#define NO_ERROR_STRINGS

/* ---- AES modes exercised by the HUK device ---- */
#define HAVE_AESGCM
#define WOLFSSL_AES_DIRECT
#define HAVE_AES_ECB
#define HAVE_AES_CBC
#define WOLFSSL_AES_COUNTER
#define WOLFSSL_AES_256
#define WOLFSSL_AES_128
#define GCM_TABLE_4BIT

/* ---- hashing + DRBG (seeded from the SDK TRNG, see main.c) ---- */
#undef NO_SHA256
#define WOLFSSL_SHA256
#define HAVE_HASHDRBG
#define WC_NO_HARDEN /* timing-hardening not needed for the demo */

/* ---- trims ---- */
#define NO_ECC /* ECDSA is a separate (Stage 3) follow-on */
#define NO_RSA
#define NO_DSA
#define NO_DH
#define NO_DES3
#define NO_RC4
#define NO_MD4
#define NO_MD5
#define NO_SHA
#define NO_PWDBASED
#define NO_PKCS12
#define NO_PKCS8
#define NO_ASN
#define NO_CERTS
#define NO_OLD_TLS

/* ---- custom RNG seed hook (provided in main.c via the SDK TRNG) ---- */
#define CUSTOM_RAND_GENERATE_SEED amebapro2_rand_seed
#ifndef __ASSEMBLER__
#include <stddef.h>
int amebapro2_rand_seed(unsigned char* output, unsigned int sz);
#endif

#ifdef __cplusplus
}
#endif

#endif /* AMEBAPRO2_HUK_USER_SETTINGS_H */
Loading