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
23 changes: 21 additions & 2 deletions rtl8735b/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,17 @@ It is built inside the RealTek AmebaPro2 FreeRTOS SDK (which provides the startu
- HMAC-SHA256 under the HUK (`wc_HmacInit` with `devId = WC_HUK_DEVID`, then `wc_HmacSetKey`/`wc_HmacUpdate`/`wc_HmacFinal`): the MAC is deterministic for a given seed and differs for a wrong seed.
- HUK-bound ECDSA P-256 sign: a key is generated in software, its private scalar is wrapped under the HUK (ECB-encrypted with the HUK device), and signing then goes through the HUK device (unwrap + sign); the signature verifies against the software public key.
- HW ECDSA P-256 verify offload: the same signature is then verified through the HW engine (the public point is imported into a `WC_HUK_DEVID` key so `wc_ecc_verify_hash` dispatches to `hal_ecdsa`), and a tampered digest is shown to be rejected. No HUK context is needed to verify -- any P-256 public key.
- **Plaintext-key AES (second device):** with `WOLFSSL_RTL8735B_AES` also enabled (see `user_settings.h`), the example registers a second crypto-callback device, `wc_Rtl8735b_AesRegister(WC_RTL8735B_AES_DEVID)`, that runs a caller-supplied AES key directly on the HW engine with no HUK binding. It reproduces a published AES-GCM test vector (proving the key is used verbatim), then encrypts the same 32 key bytes through both devices to show the plaintext-key ciphertext differs from the HUK device-bound ciphertext -- the two devices coexist and are selected per `Aes` by `devId`.

## 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-ameba-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/rtl8735b.c` and `wolfssl/wolfcrypt/port/realtek/rtl8735b.h`). Enable with `WOLFSSL_RTL8735B_HUK` and `WOLF_CRYPTO_CB`.
- wolfSSL with the RealTek HUK port (`wolfcrypt/src/port/realtek/rtl8735b.c` and `wolfssl/wolfcrypt/port/realtek/rtl8735b.h`). Enable with `WOLFSSL_RTL8735B_HUK` and `WOLF_CRYPTO_CB`. This example's `user_settings.h` also defines `WOLFSSL_RTL8735B_AES` (the plaintext-key AES device), so the wolfSSL tree must be new enough to provide `wc_Rtl8735b_AesRegister` / `WC_RTL8735B_AES_DEVID`; remove that define to build against an older HUK-only port.

## Files

- `main.c` -- the example application (a FreeRTOS task that registers the HUK device and runs the AES-GCM/ECB/CBC/CTR checks plus unaligned-buffer GCM, in-place/multi-call CBC, non-12-byte-IV rejection, HMAC-SHA256, and HUK-bound ECDSA sign + HW verify checks).
- `main.c` -- the example application (a FreeRTOS task that registers the HUK device and runs the AES-GCM/ECB/CBC/CTR checks plus unaligned-buffer GCM, in-place/multi-call CBC, non-12-byte-IV rejection, HMAC-SHA256, and HUK-bound ECDSA sign + HW verify checks). With `WOLFSSL_RTL8735B_AES` it also registers the plaintext-key AES device and runs its GCM KAT + coexistence, ECB FIPS-197 KAT, unaligned-buffer, and non-12-byte-IV checks.
- `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.
- `test/` -- a separate `wolfcrypt_test` + `wolfcrypt_benchmark` example for this target with three backend modes (pure C, Thumb-2 / SP Cortex-M, and RealTek hardware offload); see `test/README.md`.
Expand Down Expand Up @@ -56,6 +57,7 @@ Remove the J27 jumper and reset to boot. The console (UART, 115200) prints:
=== wolfCrypt AmebaPro2 (RTL8735B) HUK example ===
[PASS] wolfCrypt_Init
[PASS] wc_Rtl8735b_HukRegister
[PASS] wc_Rtl8735b_AesRegister
== AES-GCM (full payload) under HUK-derived key ==
[PASS] AesInit(devId=WC_HUK_DEVID)
[PASS] AesGcmSetKey(seed,32)
Expand All @@ -76,6 +78,23 @@ Remove the J27 jumper and reset to boot. The console (UART, 115200) prints:
[PASS] verify with software public key
[PASS] HW ECDSA verify (good sig)
[PASS] HW ECDSA verify (tampered -> reject)
== AES-GCM with a plaintext key (devId=WC_RTL8735B_AES_DEVID) ==
[PASS] AesInit(devId=WC_RTL8735B_AES_DEVID)
[PASS] AesGcmSetKey(plaintext 128-bit key)
[PASS] AesGcmEncrypt
[PASS] ciphertext matches published vector
[PASS] tag matches published vector
[PASS] AesGcmDecrypt verifies
[PASS] plaintext round-trips
[PASS] tampered tag -> AES_GCM_AUTH_E
[PASS] plaintext-key encrypt (256-bit)
[PASS] HUK-seed encrypt (same 32 bytes)
[PASS] plaintext CT != HUK CT (distinct keys per devId)
== AES-ECB with a plaintext key (FIPS-197 KAT) ==
[PASS] ciphertext matches FIPS-197 vector
[PASS] AesEcb round-trip
== AES-GCM plaintext key, UNALIGNED buffers (port bounces) == ... round-trip PASS
== AES-GCM plaintext key, non-12-byte IV must hard-fail == ... 16-byte IV rejected PASS
=== done ===
```

Expand Down
278 changes: 278 additions & 0 deletions rtl8735b/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@
* (port bounce path), in-place multi-call CBC, and a non-12-byte GCM IV that
* must hard-fail (no silent software fallback).
*
* With WOLFSSL_RTL8735B_AES also enabled it registers a second crypto-callback
* device (WC_RTL8735B_AES_DEVID) that runs a caller-supplied plaintext AES key
* directly on the HW engine (no HUK binding), selected per Aes by devId, and
* exercises it with AES-GCM (published KAT + coexistence), an AES-ECB FIPS-197
* KAT, the unaligned-buffer bounce path, and non-12-byte-IV rejection.
*
* Build: configure with -DEXAMPLE=wolfcrypt_huk (see wolfcrypt_huk.cmake).
*/

Expand Down Expand Up @@ -564,9 +570,263 @@ static void huk_ecdsa_test(void)
ForceZero(seed, sizeof(seed));
}

#ifdef WOLFSSL_RTL8735B_AES
/* AES-GCM with a plaintext key through the second device (WC_RTL8735B_AES_DEVID).
* Unlike the HUK device, the key bytes are the actual AES key, so the output
* matches a published GCM vector. Then the same 32 key bytes are run through
* both devices to show they coexist and are selected per Aes by devId: the
* plaintext-key ciphertext differs from the HUK device-bound ciphertext. */
static void plain_gcm_test(void)
{
Aes aes;
/* McGrew & Viega GCM test case 3: 128-bit key, 64-byte payload, no AAD. */
static const byte katKey[16] = {
0xfe,0xff,0xe9,0x92,0x86,0x65,0x73,0x1c,
0x6d,0x6a,0x8f,0x94,0x67,0x30,0x83,0x08
};
static const byte katIv[12] = {
0xca,0xfe,0xba,0xbe,0xfa,0xce,0xdb,0xad,0xde,0xca,0xf8,0x88
};
static const byte katPt[64] = {
0xd9,0x31,0x32,0x25,0xf8,0x84,0x06,0xe5,
0xa5,0x59,0x09,0xc5,0xaf,0xf5,0x26,0x9a,
0x86,0xa7,0xa9,0x53,0x15,0x34,0xf7,0xda,
0x2e,0x4c,0x30,0x3d,0x8a,0x31,0x8a,0x72,
0x1c,0x3c,0x0c,0x95,0x95,0x68,0x09,0x53,
0x2f,0xcf,0x0e,0x24,0x49,0xa6,0xb5,0x25,
0xb1,0x6a,0xed,0xf5,0xaa,0x0d,0xe6,0x57,
0xba,0x63,0x7b,0x39,0x1a,0xaf,0xd2,0x55
};
static const byte katCt[64] = {
0x42,0x83,0x1e,0xc2,0x21,0x77,0x74,0x24,
0x4b,0x72,0x21,0xb7,0x84,0xd0,0xd4,0x9c,
0xe3,0xaa,0x21,0x2f,0x2c,0x02,0xa4,0xe0,
0x35,0xc1,0x7e,0x23,0x29,0xac,0xa1,0x2e,
0x21,0xd5,0x14,0xb2,0x54,0x66,0x93,0x1c,
0x7d,0x8f,0x6a,0x5a,0xac,0x84,0xaa,0x05,
0x1b,0xa3,0x0b,0x39,0x6a,0x0a,0xac,0x97,
0x3d,0x58,0xe0,0x91,0x47,0x3f,0x59,0x85
};
static const byte katTag[16] = {
0x4d,0x5c,0x2a,0xf3,0x27,0xcd,0x64,0xa6,
0x2c,0xf3,0x5a,0xbd,0x2b,0xa6,0xfa,0xb4
};
/* HAL crypto engine requires 32-byte-aligned key/iv/buffers. */
byte key[32] __attribute__((aligned(32)));
byte iv[12] __attribute__((aligned(32)));
byte pt[64] __attribute__((aligned(32)));
byte ct[64] __attribute__((aligned(32)));
byte ctHuk[64] __attribute__((aligned(32)));
byte dec[64] __attribute__((aligned(32)));
byte tag[16] __attribute__((aligned(32)));
byte tagHuk[16] __attribute__((aligned(32)));
int ret;

dbg_printf("\r\n== AES-GCM with a plaintext key "
"(devId=WC_RTL8735B_AES_DEVID) ==\r\n");

/* Known-answer test: the plaintext key must reproduce the published vector.
* Stage the vector key into the 32-byte-aligned buffer the HAL DMA wants. */
memcpy(key, katKey, sizeof(katKey));
memcpy(iv, katIv, sizeof(iv));
memcpy(pt, katPt, sizeof(pt));
ret = wc_AesInit(&aes, NULL, WC_RTL8735B_AES_DEVID);
CHECK("AesInit(devId=WC_RTL8735B_AES_DEVID)", ret == 0);
if (ret != 0) {
return;
}
ret = wc_AesGcmSetKey(&aes, key, sizeof(katKey));
CHECK("AesGcmSetKey(plaintext 128-bit key)", ret == 0);
if (ret == 0) {
ret = wc_AesGcmEncrypt(&aes, ct, pt, sizeof(pt), iv, sizeof(iv),
tag, sizeof(tag), NULL, 0);
CHECK("AesGcmEncrypt", ret == 0);
}
CHECK("ciphertext matches published vector",
ret == 0 && memcmp(ct, katCt, sizeof(katCt)) == 0);
CHECK("tag matches published vector",
ret == 0 && memcmp(tag, katTag, sizeof(katTag)) == 0);
if (ret == 0) {
ret = wc_AesGcmDecrypt(&aes, dec, ct, sizeof(ct), iv, sizeof(iv),
tag, sizeof(tag), NULL, 0);
CHECK("AesGcmDecrypt verifies", ret == 0);
CHECK("plaintext round-trips", memcmp(dec, pt, sizeof(pt)) == 0);

/* Negative: a tampered tag must be rejected by the HW decrypt-verify. */
tag[0] ^= 0xFFu;
ret = wc_AesGcmDecrypt(&aes, dec, ct, sizeof(ct), iv, sizeof(iv),
tag, sizeof(tag), NULL, 0);
CHECK("tampered tag -> AES_GCM_AUTH_E", ret == AES_GCM_AUTH_E);
}
wc_AesFree(&aes);

/* Coexistence: same 32 key bytes -> plaintext device vs HUK device produce
* different ciphertext (one uses the key verbatim, the other as a seed). */
memset(key, 0x5A, sizeof(key));
ret = wc_AesInit(&aes, NULL, WC_RTL8735B_AES_DEVID);
CHECK("AesInit(plaintext devId)", ret == 0);
if (ret == 0) {
ret = wc_AesGcmSetKey(&aes, key, sizeof(key));
CHECK("AesGcmSetKey(plaintext 256-bit key)", ret == 0);
}
if (ret == 0) {
ret = wc_AesGcmEncrypt(&aes, ct, pt, sizeof(pt), iv, sizeof(iv),
tag, sizeof(tag), NULL, 0);
}
wc_AesFree(&aes);
CHECK("plaintext-key encrypt (256-bit)", ret == 0);
if (ret == 0) {
ret = wc_AesInit(&aes, NULL, WC_HUK_DEVID);
CHECK("AesInit(HUK devId)", ret == 0);
if (ret == 0) {
ret = wc_AesGcmSetKey(&aes, key, sizeof(key));
CHECK("AesGcmSetKey(HUK seed, same 32 bytes)", ret == 0);
}
if (ret == 0) {
ret = wc_AesGcmEncrypt(&aes, ctHuk, pt, sizeof(pt), iv, sizeof(iv),
tagHuk, sizeof(tagHuk), NULL, 0);
}
wc_AesFree(&aes);
CHECK("HUK-seed encrypt (same 32 bytes)", ret == 0);
CHECK("plaintext CT != HUK CT (distinct keys per devId)",
ret == 0 && memcmp(ct, ctHuk, sizeof(ct)) != 0);
}
ForceZero(key, sizeof(key)); /* scrub key material before return */
}

/* AES-ECB with a plaintext key: FIPS-197 appendix C.1 known-answer vector. The
* plaintext device runs the key verbatim, so the HW output must match the
* published ciphertext exactly (the HUK device cannot -- its key is derived). */
static void plain_ecb_test(void)
{
Aes aes;
static const byte katKey[16] = {
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f
};
static const byte katPt[16] = {
0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,
0x88,0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff
};
static const byte katCt[16] = {
0x69,0xc4,0xe0,0xd8,0x6a,0x7b,0x04,0x30,
0xd8,0xcd,0xb7,0x80,0x70,0xb4,0xc5,0x5a
};
byte key[16] __attribute__((aligned(32)));
byte pt[16] __attribute__((aligned(32)));
byte ct[16] __attribute__((aligned(32)));
byte dec[16] __attribute__((aligned(32)));
int ret;

memcpy(key, katKey, sizeof(key));
memcpy(pt, katPt, sizeof(pt));

dbg_printf("\r\n== AES-ECB with a plaintext key (FIPS-197 KAT) ==\r\n");
ret = wc_AesInit(&aes, NULL, WC_RTL8735B_AES_DEVID);
CHECK("AesInit(devId=WC_RTL8735B_AES_DEVID)", ret == 0);
if (ret != 0) {
return;
}
ret = wc_AesSetKey(&aes, key, sizeof(key), NULL, AES_ENCRYPTION);
CHECK("AesSetKey(ECB enc)", ret == 0);
if (ret == 0) {
ret = wc_AesEcbEncrypt(&aes, ct, pt, sizeof(pt));
CHECK("AesEcbEncrypt", ret == 0);
}
CHECK("ciphertext matches FIPS-197 vector",
ret == 0 && memcmp(ct, katCt, sizeof(katCt)) == 0);
ret = wc_AesSetKey(&aes, key, sizeof(key), NULL, AES_DECRYPTION);
CHECK("AesSetKey(ECB dec)", ret == 0);
if (ret == 0) {
ret = wc_AesEcbDecrypt(&aes, dec, ct, sizeof(ct));
}
CHECK("AesEcb round-trip", ret == 0 && memcmp(dec, pt, sizeof(pt)) == 0);
wc_AesFree(&aes);
ForceZero(key, sizeof(key)); /* scrub key material before return */
}

/* AES-GCM with a plaintext key over deliberately-unaligned caller buffers, so
* the port's bounce-to-aligned path is exercised for the second device too. */
static void plain_gcm_unaligned_test(void)
{
Aes aes;
/* 32-byte-aligned backing; the +1 views below are deliberately unaligned. */
byte buf[6][48] __attribute__((aligned(32)));
byte* key = buf[0] + 1;
byte* iv = buf[1] + 1;
byte* pt = buf[2] + 1;
byte* ct = buf[3] + 1;
byte* dec = buf[4] + 1;
byte* tag = buf[5] + 1;
int ret;

memset(key, 0x5A, 16); memset(iv, 0x11, 12);
memset(pt, 0x33, 32);

dbg_printf("\r\n== AES-GCM plaintext key, UNALIGNED buffers "
"(port bounces) ==\r\n");
ret = wc_AesInit(&aes, NULL, WC_RTL8735B_AES_DEVID);
CHECK("AesInit(devId=WC_RTL8735B_AES_DEVID)", ret == 0);
if (ret != 0) {
return;
}
ret = wc_AesGcmSetKey(&aes, key, 16);
CHECK("AesGcmSetKey (unaligned key)", ret == 0);
if (ret != 0) {
wc_AesFree(&aes);
return;
}
ret = wc_AesGcmEncrypt(&aes, ct, pt, 32, iv, 12, tag, 16, NULL, 0);
CHECK("AesGcmEncrypt (unaligned)", ret == 0);
ret = wc_AesGcmDecrypt(&aes, dec, ct, 32, iv, 12, tag, 16, NULL, 0);
CHECK("AesGcmDecrypt (unaligned) verifies", ret == 0);
CHECK("unaligned round-trip", memcmp(dec, pt, 32) == 0);
wc_AesFree(&aes);
ForceZero(key, 16); /* scrub key material before return */
}

/* A non-12-byte GCM IV must hard-fail on the plaintext device too, NOT silently
* fall back to software GCM (regression for the IV hard-error contract). */
static void plain_gcm_badiv_test(void)
{
Aes aes;
byte key[16] __attribute__((aligned(32)));
byte iv[16] __attribute__((aligned(32))); /* 16 bytes, not the supported 12 */
byte pt[16] __attribute__((aligned(32)));
byte ct[16] __attribute__((aligned(32)));
byte tag[16] __attribute__((aligned(32)));
int ret;

memset(key, 0x5A, sizeof(key)); memset(iv, 0x11, sizeof(iv));
memset(pt, 0x33, sizeof(pt));

dbg_printf("\r\n== AES-GCM plaintext key, non-12-byte IV must hard-fail "
"==\r\n");
ret = wc_AesInit(&aes, NULL, WC_RTL8735B_AES_DEVID);
CHECK("AesInit(devId=WC_RTL8735B_AES_DEVID)", ret == 0);
if (ret != 0) {
return;
}
ret = wc_AesGcmSetKey(&aes, key, sizeof(key));
CHECK("AesGcmSetKey(key,16)", ret == 0);
if (ret != 0) {
wc_AesFree(&aes);
return;
}
ret = wc_AesGcmEncrypt(&aes, ct, pt, sizeof(pt), iv, sizeof(iv),
tag, sizeof(tag), NULL, 0);
CHECK("16-byte IV rejected (no silent SW fallback)", ret != 0);
wc_AesFree(&aes);
ForceZero(key, sizeof(key)); /* scrub key material before return */
}
#endif /* WOLFSSL_RTL8735B_AES */

static void wolf_huk_thread(void* param)
{
int ret;
#ifdef WOLFSSL_RTL8735B_AES
int aesRet = 0;
#endif
(void)param;

dbg_printf("\r\n=== wolfCrypt AmebaPro2 (RTL8735B) HUK example ===\r\n");
Expand All @@ -580,6 +840,15 @@ static void wolf_huk_thread(void* param)
ret = wc_Rtl8735b_HukRegister(WC_HUK_DEVID);
CHECK("wc_Rtl8735b_HukRegister", ret == 0);
}
#ifdef WOLFSSL_RTL8735B_AES
/* The plaintext-key AES device is an optional add-on; track its registration
* in its own result so a failure only skips its demo -- it must never
* suppress the HUK suite or leak the HUK device registration. */
if (ret == 0) {
aesRet = wc_Rtl8735b_AesRegister(WC_RTL8735B_AES_DEVID);
CHECK("wc_Rtl8735b_AesRegister", aesRet == 0);
}
#endif
if (ret == 0) {
huk_gcm_test();
huk_ecb_cbc_test();
Expand All @@ -589,6 +858,15 @@ static void wolf_huk_thread(void* param)
huk_gcm_badiv_test();
huk_hmac_test();
huk_ecdsa_test();
#ifdef WOLFSSL_RTL8735B_AES
if (aesRet == 0) {
plain_gcm_test();
plain_ecb_test();
plain_gcm_unaligned_test();
plain_gcm_badiv_test();
wc_Rtl8735b_AesUnRegister(WC_RTL8735B_AES_DEVID);
}
#endif
wc_Rtl8735b_HukUnRegister(WC_HUK_DEVID);
}
wolfCrypt_Cleanup();
Expand Down
5 changes: 4 additions & 1 deletion rtl8735b/user_settings.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
/* user_settings.h -- wolfCrypt config for the AmebaPro2 (RTL8735B) HUK example
* built inside the RealTek FreeRTOS SDK. HUK crypto-callback demo: AES
* (GCM/ECB/CBC/CTR), HMAC-SHA256, and ECDSA P-256. */
* (GCM/ECB/CBC/CTR), HMAC-SHA256, and ECDSA P-256. Also enables the plaintext-
* key AES device (WOLFSSL_RTL8735B_AES) -- a second crypto-callback device that
* runs a caller-supplied AES key directly on the HW engine (no HUK binding). */

#ifndef RTL8735B_HUK_USER_SETTINGS_H
#define RTL8735B_HUK_USER_SETTINGS_H
Expand All @@ -11,6 +13,7 @@ extern "C" {

/* ---- HUK crypto-callback device (our RealTek port) ---- */
#define WOLFSSL_RTL8735B_HUK
#define WOLFSSL_RTL8735B_AES /* plaintext-key AES device (2nd devId) */
#define WOLF_CRYPTO_CB
#define WOLF_CRYPTO_CB_COPY /* HUK HMAC buffer copy/free ops */
#define WOLF_CRYPTO_CB_FREE
Expand Down
Loading