diff --git a/AmebaPro2/README.md b/AmebaPro2/README.md new file mode 100644 index 000000000..6ff8fca32 --- /dev/null +++ b/AmebaPro2/README.md @@ -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 /component/example/wolfcrypt_huk` +2. Install the example `main()` as the project app: + `cp /component/example/wolfcrypt_huk/main.c /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-10.3.0/linux/newlib/bin:$PATH + cd /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= + 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 -f /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. diff --git a/AmebaPro2/main.c b/AmebaPro2/main.c new file mode 100644 index 000000000..a42a95462 --- /dev/null +++ b/AmebaPro2/main.c @@ -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 +#include +#include +#include +#include + +#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); + 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); + 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); + 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); + 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)); + 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); + 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) { + } +} diff --git a/AmebaPro2/user_settings.h b/AmebaPro2/user_settings.h new file mode 100644 index 000000000..d3c3110c1 --- /dev/null +++ b/AmebaPro2/user_settings.h @@ -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 + int amebapro2_rand_seed(unsigned char* output, unsigned int sz); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* AMEBAPRO2_HUK_USER_SETTINGS_H */ diff --git a/AmebaPro2/wolfcrypt_huk.cmake b/AmebaPro2/wolfcrypt_huk.cmake new file mode 100644 index 000000000..0f04461ce --- /dev/null +++ b/AmebaPro2/wolfcrypt_huk.cmake @@ -0,0 +1,51 @@ +# wolfCrypt AmebaPro2 (RTL8735B) HUK example -- RealTek FreeRTOS SDK wiring. +# +# Install this directory at /component/example/wolfcrypt_huk/ and select it +# at configure time: +# cmake .. -DEXAMPLE=wolfcrypt_huk -DWOLFSSL_ROOT=/path/to/wolfssl ... +# (also copy main.c to /project/realtek_amebapro2_v0_example/src/main.c) +# +# Adds the wolfCrypt sources + the RealTek HUK crypto-callback port + this +# example's include path and -DWOLFSSL_USER_SETTINGS to the SDK app build. + +# Locate the wolfSSL tree: -DWOLFSSL_ROOT=..., or $WOLFSSL_ROOT, else a guess. +if(NOT DEFINED WOLFSSL_ROOT OR WOLFSSL_ROOT STREQUAL "") + if(DEFINED ENV{WOLFSSL_ROOT}) + set(WOLFSSL_ROOT $ENV{WOLFSSL_ROOT}) + else() + set(WOLFSSL_ROOT ${CMAKE_CURRENT_LIST_DIR}/../../../../wolfssl) + endif() +endif() +if(NOT EXISTS ${WOLFSSL_ROOT}/wolfcrypt/src/aes.c) + message(FATAL_ERROR + "WOLFSSL_ROOT='${WOLFSSL_ROOT}' is not a wolfSSL tree. " + "Pass -DWOLFSSL_ROOT=/path/to/wolfssl.") +endif() +message(STATUS "wolfCrypt HUK example: WOLFSSL_ROOT=${WOLFSSL_ROOT}") + +### header search paths ### +list(APPEND app_example_inc_path + ${WOLFSSL_ROOT} + ${CMAKE_CURRENT_LIST_DIR} # user_settings.h +) + +### compile definitions (become -D...) ### +list(APPEND app_example_flags + WOLFSSL_USER_SETTINGS +) + +### source files ### +list(APPEND app_example_sources + ${WOLFSSL_ROOT}/wolfcrypt/src/aes.c + ${WOLFSSL_ROOT}/wolfcrypt/src/sha256.c + ${WOLFSSL_ROOT}/wolfcrypt/src/hash.c + ${WOLFSSL_ROOT}/wolfcrypt/src/hmac.c + ${WOLFSSL_ROOT}/wolfcrypt/src/random.c + ${WOLFSSL_ROOT}/wolfcrypt/src/memory.c + ${WOLFSSL_ROOT}/wolfcrypt/src/wc_port.c + ${WOLFSSL_ROOT}/wolfcrypt/src/cryptocb.c + ${WOLFSSL_ROOT}/wolfcrypt/src/error.c + ${WOLFSSL_ROOT}/wolfcrypt/src/logging.c + ${WOLFSSL_ROOT}/wolfcrypt/src/wc_encrypt.c + ${WOLFSSL_ROOT}/wolfcrypt/src/port/realtek/amebapro2.c +)