diff --git a/boards/stm32wb55xx_nucleo/Makefile.inc b/boards/stm32wb55xx_nucleo/Makefile.inc index f98b6e6..6a1be19 100644 --- a/boards/stm32wb55xx_nucleo/Makefile.inc +++ b/boards/stm32wb55xx_nucleo/Makefile.inc @@ -1,7 +1,7 @@ _BOARD_DIR := $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST)))) PLATFORM = stm32wb -TESTS ?= clock gpio flash timer rng +TESTS ?= clock gpio flash timer rng crypto GCC = $(GCC_PATH)arm-none-eabi-gcc LD = $(GCC_PATH)arm-none-eabi-ld @@ -26,5 +26,6 @@ BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/timer.c) BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/supply.c) BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/flash.c) BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/rng.c) +BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/crypto.c) BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/stm32wb_*.c) BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/systick.c) diff --git a/boards/stm32wb55xx_nucleo/board.c b/boards/stm32wb55xx_nucleo/board.c index d268566..8c55745 100644 --- a/boards/stm32wb55xx_nucleo/board.c +++ b/boards/stm32wb55xx_nucleo/board.c @@ -123,6 +123,28 @@ whal_Rng g_whalRng = { }, }; +/* Crypto */ +static const whal_Crypto_OpFunc cryptoOps[BOARD_CRYPTO_OP_COUNT] = { + [BOARD_CRYPTO_AES_ECB] = whal_Stm32wbAes_AesEcb, + [BOARD_CRYPTO_AES_CBC] = whal_Stm32wbAes_AesCbc, + [BOARD_CRYPTO_AES_CTR] = whal_Stm32wbAes_AesCtr, + [BOARD_CRYPTO_AES_GCM] = whal_Stm32wbAes_AesGcm, + [BOARD_CRYPTO_AES_GMAC] = whal_Stm32wbAes_AesGmac, + [BOARD_CRYPTO_AES_CCM] = whal_Stm32wbAes_AesCcm, +}; + +whal_Crypto g_whalCrypto = { + WHAL_STM32WB55_AES1_DEVICE, + + .ops = cryptoOps, + .opsCount = BOARD_CRYPTO_OP_COUNT, + + .cfg = &(whal_Stm32wbAes_Cfg) { + .clkCtrl = &g_whalClock, + .clk = &(whal_Stm32wbRcc_Clk) {WHAL_STM32WB55_AES1_CLOCK}, + }, +}; + /* SysTick timing */ volatile size_t g_tick = 0; volatile uint8_t g_waiting = 0; @@ -191,6 +213,11 @@ whal_Error Board_Init(void) return err; } + err = whal_Crypto_Init(&g_whalCrypto); + if (err) { + return err; + } + err = whal_Timer_Init(&g_whalTimer); if (err) { return err; @@ -218,6 +245,11 @@ whal_Error Board_Deinit(void) return err; } + err = whal_Crypto_Deinit(&g_whalCrypto); + if (err) { + return err; + } + err = whal_Rng_Deinit(&g_whalRng); if (err) { return err; diff --git a/boards/stm32wb55xx_nucleo/board.h b/boards/stm32wb55xx_nucleo/board.h index 047bc79..dc6d8af 100644 --- a/boards/stm32wb55xx_nucleo/board.h +++ b/boards/stm32wb55xx_nucleo/board.h @@ -11,6 +11,7 @@ extern whal_Timer g_whalTimer; extern whal_Uart g_whalUart; extern whal_Flash g_whalFlash; extern whal_Rng g_whalRng; +extern whal_Crypto g_whalCrypto; extern volatile size_t g_tick; @@ -18,6 +19,16 @@ extern volatile size_t g_tick; #define BOARD_FLASH_TEST_ADDR 0x08080000 #define BOARD_FLASH_SECTOR_SZ 0x1000 +enum { + BOARD_CRYPTO_AES_ECB, + BOARD_CRYPTO_AES_CBC, + BOARD_CRYPTO_AES_CTR, + BOARD_CRYPTO_AES_GCM, + BOARD_CRYPTO_AES_GMAC, + BOARD_CRYPTO_AES_CCM, + BOARD_CRYPTO_OP_COUNT, +}; + whal_Error Board_Init(void); whal_Error Board_Deinit(void); void Board_WaitMs(size_t ms); diff --git a/docs/adding_a_test.md b/docs/adding_a_test.md index e5a17fb..90f95aa 100644 --- a/docs/adding_a_test.md +++ b/docs/adding_a_test.md @@ -14,6 +14,8 @@ Tests use the macros defined in `tests/test.h`: - `WHAL_ASSERT_NEQ(a, b)` — assert not equal - `WHAL_ASSERT_MEM_EQ(a, b, len)` — assert memory regions are equal, reports the byte offset of the first mismatch +- `WHAL_SKIP()` — skip the current test (marks it as SKIP instead of + PASS/FAIL and returns early) Test functions take no arguments and return void. On assertion failure the function returns early and the test is marked as failed. diff --git a/docs/writing_a_driver.md b/docs/writing_a_driver.md index 938a732..7d0d5f6 100644 --- a/docs/writing_a_driver.md +++ b/docs/writing_a_driver.md @@ -447,6 +447,75 @@ consumption and avoid unnecessary entropy source wear. --- +## Crypto + +Header: `wolfHAL/crypto/crypto.h` + +The crypto driver provides access to hardware cryptographic accelerators. Unlike +other device types, the crypto driver uses an **ops table** dispatch model +instead of a fixed vtable — each supported algorithm is a function pointer in a +board-defined ops table, indexed by a board-defined enum. This allows different +platforms to expose different subsets of algorithms without changing the generic +interface. + +### Device Struct + +The crypto device struct extends the standard model with an ops table: + +```c +struct whal_Crypto { + const whal_Regmap regmap; + const whal_CryptoDriver *driver; + const whal_Crypto_OpFunc *ops; + size_t opsCount; + const void *cfg; +}; +``` + +The `driver` vtable handles Init/Deinit. The `ops` table maps algorithm indices +to operation functions. The board defines the enum values and populates the ops +table. + +### Init / Deinit + +Init should enable the peripheral clock. Deinit should disable the AES +peripheral and its clock. + +### Operations + +Each operation function has the signature: + +```c +whal_Error myOp(whal_Crypto *cryptoDev, void *opArgs); +``` + +The `opArgs` parameter is a pointer to an algorithm-specific argument struct +(e.g., `whal_Crypto_AesEcbArgs`, `whal_Crypto_AesGcmArgs`). The operation +function casts it to the correct type. See `wolfHAL/crypto/crypto.h` for the +full set of argument structs. + +### Board Integration + +The board defines an enum of supported operations and a corresponding ops table: + +```c +enum { + BOARD_CRYPTO_AES_ECB, + BOARD_CRYPTO_AES_CBC, + BOARD_CRYPTO_OP_COUNT, +}; + +static const whal_Crypto_OpFunc cryptoOps[BOARD_CRYPTO_OP_COUNT] = { + [BOARD_CRYPTO_AES_ECB] = whal_Stm32wbAes_AesEcb, + [BOARD_CRYPTO_AES_CBC] = whal_Stm32wbAes_AesCbc, +}; +``` + +Callers use `whal_Crypto_Op(&g_whalCrypto, BOARD_CRYPTO_AES_ECB, &args)` to +invoke an operation. + +--- + ## Supply Header: `wolfHAL/supply/supply.h` diff --git a/src/crypto/crypto.c b/src/crypto/crypto.c new file mode 100644 index 0000000..81925b0 --- /dev/null +++ b/src/crypto/crypto.c @@ -0,0 +1,33 @@ +#include +#include + +whal_Error whal_Crypto_Init(whal_Crypto *cryptoDev) +{ + if (!cryptoDev || !cryptoDev->driver || !cryptoDev->driver->Init) { + return WHAL_EINVAL; + } + + return cryptoDev->driver->Init(cryptoDev); +} + +whal_Error whal_Crypto_Deinit(whal_Crypto *cryptoDev) +{ + if (!cryptoDev || !cryptoDev->driver || !cryptoDev->driver->Deinit) { + return WHAL_EINVAL; + } + + return cryptoDev->driver->Deinit(cryptoDev); +} + +whal_Error whal_Crypto_Op(whal_Crypto *cryptoDev, size_t op, void *opArgs) +{ + if (!cryptoDev || !cryptoDev->ops || !opArgs) { + return WHAL_EINVAL; + } + + if (op >= cryptoDev->opsCount || !cryptoDev->ops[op]) { + return WHAL_EINVAL; + } + + return cryptoDev->ops[op](cryptoDev, opArgs); +} diff --git a/src/crypto/stm32wb_aes.c b/src/crypto/stm32wb_aes.c new file mode 100644 index 0000000..ea8a5cc --- /dev/null +++ b/src/crypto/stm32wb_aes.c @@ -0,0 +1,910 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * STM32WB AES1 Register Definitions + * + * The AES1 peripheral provides hardware acceleration for 128/256-bit + * AES in ECB, CBC, CTR, GCM, GMAC, and CCM modes. Data is fed through DINR and + * read from DOUTR, 32 bits at a time. + */ + +/* Control Register */ +#define AES_CR_REG 0x00 +#define AES_CR_EN_Pos 0 /* AES enable */ +#define AES_CR_EN_Msk (1UL << AES_CR_EN_Pos) + +#define AES_CR_DATATYPE_Pos 1 /* Data type selection */ +#define AES_CR_DATATYPE_Msk (3UL << AES_CR_DATATYPE_Pos) + +#define AES_CR_MODE_Pos 3 /* Operating mode */ +#define AES_CR_MODE_Msk (3UL << AES_CR_MODE_Pos) + +#define AES_CR_CHMOD_Pos 5 /* Chaining mode [1:0] */ +#define AES_CR_CHMOD_Msk (3UL << AES_CR_CHMOD_Pos) + +#define AES_CR_CHMOD2_Pos 16 /* Chaining mode [2] */ +#define AES_CR_CHMOD2_Msk (1UL << AES_CR_CHMOD2_Pos) + +#define AES_CR_CCFC_Pos 7 /* Computation complete flag clear */ +#define AES_CR_CCFC_Msk (1UL << AES_CR_CCFC_Pos) + +#define AES_CR_KEYSIZE_Pos 18 /* Key size (0=128, 1=256) */ +#define AES_CR_KEYSIZE_Msk (1UL << AES_CR_KEYSIZE_Pos) + +#define AES_CR_GCMPH_Pos 13 /* GCM phase */ +#define AES_CR_GCMPH_Msk (3UL << AES_CR_GCMPH_Pos) + +/* Status Register */ +#define AES_SR_REG 0x04 +#define AES_SR_CCF_Pos 0 /* Computation complete */ +#define AES_SR_CCF_Msk (1UL << AES_SR_CCF_Pos) + +#define AES_SR_RDERR_Pos 1 /* Read error */ +#define AES_SR_RDERR_Msk (1UL << AES_SR_RDERR_Pos) + +#define AES_SR_WRERR_Pos 2 /* Write error */ +#define AES_SR_WRERR_Msk (1UL << AES_SR_WRERR_Pos) + +/* Data Registers */ +#define AES_DINR_REG 0x08 +#define AES_DOUTR_REG 0x0C + +/* Key Registers */ +#define AES_KEYR0_REG 0x10 +#define AES_KEYR1_REG 0x14 +#define AES_KEYR2_REG 0x18 +#define AES_KEYR3_REG 0x1C +#define AES_KEYR4_REG 0x30 +#define AES_KEYR5_REG 0x34 +#define AES_KEYR6_REG 0x38 +#define AES_KEYR7_REG 0x3C + +/* Initialization Vector Registers */ +#define AES_IVR0_REG 0x20 +#define AES_IVR1_REG 0x24 +#define AES_IVR2_REG 0x28 +#define AES_IVR3_REG 0x2C + +/* Chaining modes */ +#define AES_CHMOD_ECB 0x0 +#define AES_CHMOD_CBC 0x1 +#define AES_CHMOD_CTR 0x2 +#define AES_CHMOD_GCM 0x3 +#define AES_CHMOD_CCM 0x4 /* CHMOD[2:0] = 100 */ + +/* Operating modes */ +#define AES_MODE_ENCRYPT 0x0 +#define AES_MODE_KEYDERIV 0x1 +#define AES_MODE_DECRYPT 0x2 +#define AES_MODE_KEYDERIV_DECRYPT 0x3 + +/* Data types (swap modes) */ +#define AES_DATATYPE_NONE 0x0 /* No swapping */ +#define AES_DATATYPE_HALFWORD 0x1 /* 16-bit half-word swap */ +#define AES_DATATYPE_BYTE 0x2 /* 8-bit byte swap */ +#define AES_DATATYPE_BIT 0x3 /* 1-bit bit swap */ + + +/* GCM phases */ +#define AES_GCMPH_INIT 0x0 +#define AES_GCMPH_HEADER 0x1 +#define AES_GCMPH_PAYLOAD 0x2 +#define AES_GCMPH_FINAL 0x3 + +static void WriteKey(size_t base, const uint8_t *key, size_t keySz) +{ + const uint8_t *k = key; + if (keySz == 32) { + whal_Reg_Write(base, AES_KEYR7_REG, whal_LoadBe32(k)); + whal_Reg_Write(base, AES_KEYR6_REG, whal_LoadBe32(k + 4)); + whal_Reg_Write(base, AES_KEYR5_REG, whal_LoadBe32(k + 8)); + whal_Reg_Write(base, AES_KEYR4_REG, whal_LoadBe32(k + 12)); + k += 16; + } + whal_Reg_Write(base, AES_KEYR3_REG, whal_LoadBe32(k)); + whal_Reg_Write(base, AES_KEYR2_REG, whal_LoadBe32(k + 4)); + whal_Reg_Write(base, AES_KEYR1_REG, whal_LoadBe32(k + 8)); + whal_Reg_Write(base, AES_KEYR0_REG, whal_LoadBe32(k + 12)); +} + +static void WriteIv(size_t base, const uint8_t *iv) +{ + whal_Reg_Write(base, AES_IVR3_REG, whal_LoadBe32(iv)); + whal_Reg_Write(base, AES_IVR2_REG, whal_LoadBe32(iv + 4)); + whal_Reg_Write(base, AES_IVR1_REG, whal_LoadBe32(iv + 8)); + whal_Reg_Write(base, AES_IVR0_REG, whal_LoadBe32(iv + 12)); +} + +static void WriteBlock(size_t base, const uint8_t *in) +{ + whal_Reg_Write(base, AES_DINR_REG, whal_LoadBe32(in)); + whal_Reg_Write(base, AES_DINR_REG, whal_LoadBe32(in + 4)); + whal_Reg_Write(base, AES_DINR_REG, whal_LoadBe32(in + 8)); + whal_Reg_Write(base, AES_DINR_REG, whal_LoadBe32(in + 12)); +} + +static void ReadBlock(size_t base, uint8_t *out) +{ + whal_StoreBe32(out, whal_Reg_Read(base, AES_DOUTR_REG)); + whal_StoreBe32(out + 4, whal_Reg_Read(base, AES_DOUTR_REG)); + whal_StoreBe32(out + 8, whal_Reg_Read(base, AES_DOUTR_REG)); + whal_StoreBe32(out + 12, whal_Reg_Read(base, AES_DOUTR_REG)); +} + + +whal_Error whal_Stm32wbAes_Init(whal_Crypto *cryptoDev) +{ + whal_Error err; + const whal_Stm32wbAes_Cfg *cfg; + + if (!cryptoDev || !cryptoDev->cfg) { + return WHAL_EINVAL; + } + + cfg = (const whal_Stm32wbAes_Cfg *)cryptoDev->cfg; + + err = whal_Clock_Enable(cfg->clkCtrl, cfg->clk); + if (err != WHAL_SUCCESS) { + return err; + } + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32wbAes_Deinit(whal_Crypto *cryptoDev) +{ + whal_Error err; + const whal_Stm32wbAes_Cfg *cfg; + + if (!cryptoDev || !cryptoDev->cfg) { + return WHAL_EINVAL; + } + + cfg = (const whal_Stm32wbAes_Cfg *)cryptoDev->cfg; + + /* Disable AES peripheral */ + whal_Reg_Update(cryptoDev->regmap.base, AES_CR_REG, AES_CR_EN_Msk, + whal_SetBits(AES_CR_EN_Msk, AES_CR_EN_Pos, 0)); + + err = whal_Clock_Disable(cfg->clkCtrl, cfg->clk); + if (err != WHAL_SUCCESS) { + return err; + } + + return WHAL_SUCCESS; +} + + +whal_Error whal_Stm32wbAes_AesEcb(whal_Crypto *cryptoDev, void *opArgs) +{ + whal_Crypto_AesEcbArgs *args; + size_t base; + size_t mode; + size_t keySizeBit; + size_t i; + + if (!cryptoDev || !opArgs) + return WHAL_EINVAL; + + args = (whal_Crypto_AesEcbArgs *)opArgs; + + if (!args->key || !args->in || !args->out) + return WHAL_EINVAL; + + if (args->keySz != 16 && args->keySz != 32) + return WHAL_EINVAL; + + if (args->sz == 0 || (args->sz & 0xF) != 0) + return WHAL_EINVAL; + + base = cryptoDev->regmap.base; + keySizeBit = (args->keySz == 32) ? 1 : 0; + + mode = (args->dir == WHAL_CRYPTO_ENCRYPT) + ? AES_MODE_ENCRYPT : AES_MODE_KEYDERIV_DECRYPT; + + /* Disable AES */ + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, 0); + + /* Configure: MODE, CHMOD=ECB, DATATYPE=none, KEYSIZE */ + whal_Reg_Update(base, AES_CR_REG, + AES_CR_MODE_Msk | AES_CR_CHMOD_Msk | AES_CR_CHMOD2_Msk | + AES_CR_DATATYPE_Msk | AES_CR_KEYSIZE_Msk, + whal_SetBits(AES_CR_MODE_Msk, AES_CR_MODE_Pos, mode) | + whal_SetBits(AES_CR_CHMOD_Msk, AES_CR_CHMOD_Pos, + AES_CHMOD_ECB) | + whal_SetBits(AES_CR_DATATYPE_Msk, AES_CR_DATATYPE_Pos, + AES_DATATYPE_NONE) | + whal_SetBits(AES_CR_KEYSIZE_Msk, AES_CR_KEYSIZE_Pos, + keySizeBit)); + + WriteKey(base, args->key, args->keySz); + + /* Enable AES */ + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, AES_CR_EN_Msk); + + /* Process each 16-byte block */ + for (i = 0; i < args->sz; i += 16) { + const uint8_t *in = args->in + i; + uint8_t *out = args->out + i; + + WriteBlock(base, in); + while (!(whal_Reg_Read(base, AES_SR_REG) & AES_SR_CCF_Msk)); + ReadBlock(base, out); + whal_Reg_Update(base, AES_CR_REG, AES_CR_CCFC_Msk, AES_CR_CCFC_Msk); + } + + /* Disable AES */ + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, 0); + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32wbAes_AesCbc(whal_Crypto *cryptoDev, void *opArgs) +{ + whal_Crypto_AesCbcArgs *args; + size_t base; + size_t mode; + size_t keySizeBit; + size_t i; + + if (!cryptoDev || !opArgs) + return WHAL_EINVAL; + + args = (whal_Crypto_AesCbcArgs *)opArgs; + + if (!args->key || !args->iv || !args->in || !args->out) + return WHAL_EINVAL; + + if (args->keySz != 16 && args->keySz != 32) + return WHAL_EINVAL; + + if (args->sz == 0 || (args->sz & 0xF) != 0) + return WHAL_EINVAL; + + base = cryptoDev->regmap.base; + keySizeBit = (args->keySz == 32) ? 1 : 0; + + mode = (args->dir == WHAL_CRYPTO_ENCRYPT) + ? AES_MODE_ENCRYPT : AES_MODE_KEYDERIV_DECRYPT; + + /* Disable AES */ + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, 0); + + /* Configure: MODE, CHMOD=CBC, DATATYPE=none, KEYSIZE */ + whal_Reg_Update(base, AES_CR_REG, + AES_CR_MODE_Msk | AES_CR_CHMOD_Msk | AES_CR_CHMOD2_Msk | + AES_CR_DATATYPE_Msk | AES_CR_KEYSIZE_Msk, + whal_SetBits(AES_CR_MODE_Msk, AES_CR_MODE_Pos, mode) | + whal_SetBits(AES_CR_CHMOD_Msk, AES_CR_CHMOD_Pos, + AES_CHMOD_CBC) | + whal_SetBits(AES_CR_DATATYPE_Msk, AES_CR_DATATYPE_Pos, + AES_DATATYPE_NONE) | + whal_SetBits(AES_CR_KEYSIZE_Msk, AES_CR_KEYSIZE_Pos, + keySizeBit)); + + WriteKey(base, args->key, args->keySz); + WriteIv(base, args->iv); + + /* Enable AES */ + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, AES_CR_EN_Msk); + + /* Process each 16-byte block */ + for (i = 0; i < args->sz; i += 16) { + const uint8_t *in = args->in + i; + uint8_t *out = args->out + i; + + WriteBlock(base, in); + while (!(whal_Reg_Read(base, AES_SR_REG) & AES_SR_CCF_Msk)); + ReadBlock(base, out); + whal_Reg_Update(base, AES_CR_REG, AES_CR_CCFC_Msk, AES_CR_CCFC_Msk); + } + + /* Disable AES */ + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, 0); + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32wbAes_AesCtr(whal_Crypto *cryptoDev, void *opArgs) +{ + whal_Crypto_AesCtrArgs *args; + size_t base; + size_t keySizeBit; + size_t i; + + if (!cryptoDev || !opArgs) + return WHAL_EINVAL; + + args = (whal_Crypto_AesCtrArgs *)opArgs; + + if (!args->key || !args->iv || !args->in || !args->out) + return WHAL_EINVAL; + + if (args->keySz != 16 && args->keySz != 32) + return WHAL_EINVAL; + + if (args->sz == 0 || (args->sz & 0xF) != 0) + return WHAL_EINVAL; + + base = cryptoDev->regmap.base; + keySizeBit = (args->keySz == 32) ? 1 : 0; + + /* Disable AES */ + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, 0); + + /* Configure: MODE=encrypt (always for CTR), CHMOD=CTR, DATATYPE=none, KEYSIZE */ + whal_Reg_Update(base, AES_CR_REG, + AES_CR_MODE_Msk | AES_CR_CHMOD_Msk | AES_CR_CHMOD2_Msk | + AES_CR_DATATYPE_Msk | AES_CR_KEYSIZE_Msk, + whal_SetBits(AES_CR_MODE_Msk, AES_CR_MODE_Pos, + AES_MODE_ENCRYPT) | + whal_SetBits(AES_CR_CHMOD_Msk, AES_CR_CHMOD_Pos, + AES_CHMOD_CTR) | + whal_SetBits(AES_CR_DATATYPE_Msk, AES_CR_DATATYPE_Pos, + AES_DATATYPE_NONE) | + whal_SetBits(AES_CR_KEYSIZE_Msk, AES_CR_KEYSIZE_Pos, + keySizeBit)); + + WriteKey(base, args->key, args->keySz); + WriteIv(base, args->iv); + + /* Enable AES */ + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, AES_CR_EN_Msk); + + /* Process each 16-byte block */ + for (i = 0; i < args->sz; i += 16) { + const uint8_t *in = args->in + i; + uint8_t *out = args->out + i; + + WriteBlock(base, in); + while (!(whal_Reg_Read(base, AES_SR_REG) & AES_SR_CCF_Msk)); + ReadBlock(base, out); + whal_Reg_Update(base, AES_CR_REG, AES_CR_CCFC_Msk, AES_CR_CCFC_Msk); + } + + /* Disable AES */ + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, 0); + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32wbAes_AesGcm(whal_Crypto *cryptoDev, void *opArgs) +{ + whal_Crypto_AesGcmArgs *args; + size_t base; + size_t mode; + size_t keySizeBit; + size_t i; + uint8_t tagBuf[16]; + + if (!cryptoDev || !opArgs) + return WHAL_EINVAL; + + args = (whal_Crypto_AesGcmArgs *)opArgs; + + if (!args->key || !args->iv || !args->tag) + return WHAL_EINVAL; + + if (args->keySz != 16 && args->keySz != 32) + return WHAL_EINVAL; + + if (args->ivSz != 12) + return WHAL_EINVAL; + + if (args->sz > 0 && (!args->in || !args->out)) + return WHAL_EINVAL; + + if (args->aadSz > 0 && !args->aad) + return WHAL_EINVAL; + + if (args->tagSz == 0 || args->tagSz > 16) + return WHAL_EINVAL; + + base = cryptoDev->regmap.base; + keySizeBit = (args->keySz == 32) ? 1 : 0; + + mode = (args->dir == WHAL_CRYPTO_ENCRYPT) + ? AES_MODE_ENCRYPT : AES_MODE_DECRYPT; + + /* Disable AES */ + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, 0); + + /* --- Init phase: compute H from key --- */ + whal_Reg_Update(base, AES_CR_REG, + AES_CR_MODE_Msk | AES_CR_CHMOD_Msk | AES_CR_CHMOD2_Msk | + AES_CR_DATATYPE_Msk | AES_CR_KEYSIZE_Msk | + AES_CR_GCMPH_Msk, + whal_SetBits(AES_CR_MODE_Msk, AES_CR_MODE_Pos, + AES_MODE_ENCRYPT) | + whal_SetBits(AES_CR_CHMOD_Msk, AES_CR_CHMOD_Pos, + AES_CHMOD_GCM) | + whal_SetBits(AES_CR_DATATYPE_Msk, AES_CR_DATATYPE_Pos, + AES_DATATYPE_NONE) | + whal_SetBits(AES_CR_KEYSIZE_Msk, AES_CR_KEYSIZE_Pos, + keySizeBit) | + whal_SetBits(AES_CR_GCMPH_Msk, AES_CR_GCMPH_Pos, + AES_GCMPH_INIT)); + + WriteKey(base, args->key, args->keySz); + + /* Write IV: 12 bytes nonce into IVR3-IVR1, counter=0x00000002 into IVR0 */ + whal_Reg_Write(base, AES_IVR3_REG, whal_LoadBe32(args->iv)); + whal_Reg_Write(base, AES_IVR2_REG, whal_LoadBe32(args->iv + 4)); + whal_Reg_Write(base, AES_IVR1_REG, whal_LoadBe32(args->iv + 8)); + whal_Reg_Write(base, AES_IVR0_REG, 0x00000002); + + /* Enable AES — init phase runs, EN auto-clears when done */ + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, AES_CR_EN_Msk); + + while (!(whal_Reg_Read(base, AES_SR_REG) & AES_SR_CCF_Msk)); + whal_Reg_Update(base, AES_CR_REG, AES_CR_CCFC_Msk, AES_CR_CCFC_Msk); + + /* --- Header phase: process AAD --- */ + if (args->aadSz > 0) { + whal_Reg_Update(base, AES_CR_REG, + AES_CR_MODE_Msk | AES_CR_GCMPH_Msk, + whal_SetBits(AES_CR_MODE_Msk, AES_CR_MODE_Pos, + AES_MODE_ENCRYPT) | + whal_SetBits(AES_CR_GCMPH_Msk, AES_CR_GCMPH_Pos, + AES_GCMPH_HEADER)); + + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, AES_CR_EN_Msk); + + for (i = 0; i < args->aadSz; i += 16) { + const uint8_t *aad = args->aad + i; + size_t remain = args->aadSz - i; + uint8_t block[16] = {0}; + size_t j; + + if (remain >= 16) { + WriteBlock(base, aad); + } else { + for (j = 0; j < remain; j++) + block[j] = aad[j]; + WriteBlock(base, block); + } + + while (!(whal_Reg_Read(base, AES_SR_REG) & AES_SR_CCF_Msk)); + whal_Reg_Update(base, AES_CR_REG, AES_CR_CCFC_Msk, + AES_CR_CCFC_Msk); + } + } + + /* --- Payload phase --- */ + if (args->sz > 0) { + whal_Reg_Update(base, AES_CR_REG, + AES_CR_MODE_Msk | AES_CR_GCMPH_Msk, + whal_SetBits(AES_CR_MODE_Msk, AES_CR_MODE_Pos, mode) | + whal_SetBits(AES_CR_GCMPH_Msk, AES_CR_GCMPH_Pos, + AES_GCMPH_PAYLOAD)); + + if (args->aadSz == 0) + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, AES_CR_EN_Msk); + + for (i = 0; i < args->sz; i += 16) { + const uint8_t *in = args->in + i; + uint8_t *out = args->out + i; + size_t remain = args->sz - i; + uint8_t block[16] = {0}; + size_t j; + + if (remain >= 16) { + WriteBlock(base, in); + } else { + for (j = 0; j < remain; j++) + block[j] = in[j]; + WriteBlock(base, block); + } + + while (!(whal_Reg_Read(base, AES_SR_REG) & AES_SR_CCF_Msk)); + + if (remain >= 16) { + ReadBlock(base, out); + } else { + ReadBlock(base, block); + for (j = 0; j < remain; j++) + out[j] = block[j]; + } + + whal_Reg_Update(base, AES_CR_REG, AES_CR_CCFC_Msk, + AES_CR_CCFC_Msk); + } + } + + /* --- Final phase: compute tag --- */ + whal_Reg_Update(base, AES_CR_REG, + AES_CR_MODE_Msk | AES_CR_GCMPH_Msk, + whal_SetBits(AES_CR_MODE_Msk, AES_CR_MODE_Pos, + AES_MODE_ENCRYPT) | + whal_SetBits(AES_CR_GCMPH_Msk, AES_CR_GCMPH_Pos, + AES_GCMPH_FINAL)); + + if (args->aadSz == 0 && args->sz == 0) + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, AES_CR_EN_Msk); + + /* Write bit-length block: aadSz*8 (64-bit) || sz*8 (64-bit) */ + whal_Reg_Write(base, AES_DINR_REG, 0); + whal_Reg_Write(base, AES_DINR_REG, (uint32_t)(args->aadSz * 8)); + whal_Reg_Write(base, AES_DINR_REG, 0); + whal_Reg_Write(base, AES_DINR_REG, (uint32_t)(args->sz * 8)); + + while (!(whal_Reg_Read(base, AES_SR_REG) & AES_SR_CCF_Msk)); + + /* Read tag from DOUTR */ + ReadBlock(base, tagBuf); + + for (i = 0; i < args->tagSz; i++) + args->tag[i] = tagBuf[i]; + + whal_Reg_Update(base, AES_CR_REG, AES_CR_CCFC_Msk, AES_CR_CCFC_Msk); + + /* Disable AES */ + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, 0); + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32wbAes_AesGmac(whal_Crypto *cryptoDev, void *opArgs) +{ + whal_Crypto_AesGmacArgs *args; + size_t base; + size_t keySizeBit; + size_t i; + uint8_t tagBuf[16]; + + if (!cryptoDev || !opArgs) + return WHAL_EINVAL; + + args = (whal_Crypto_AesGmacArgs *)opArgs; + + if (!args->key || !args->iv || !args->tag) + return WHAL_EINVAL; + + if (args->keySz != 16 && args->keySz != 32) + return WHAL_EINVAL; + + if (args->ivSz != 12) + return WHAL_EINVAL; + + if (args->aadSz > 0 && !args->aad) + return WHAL_EINVAL; + + if (args->tagSz == 0 || args->tagSz > 16) + return WHAL_EINVAL; + + base = cryptoDev->regmap.base; + keySizeBit = (args->keySz == 32) ? 1 : 0; + + /* Disable AES */ + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, 0); + + /* --- Init phase --- */ + whal_Reg_Update(base, AES_CR_REG, + AES_CR_MODE_Msk | AES_CR_CHMOD_Msk | AES_CR_CHMOD2_Msk | + AES_CR_DATATYPE_Msk | AES_CR_KEYSIZE_Msk | + AES_CR_GCMPH_Msk, + whal_SetBits(AES_CR_MODE_Msk, AES_CR_MODE_Pos, + AES_MODE_ENCRYPT) | + whal_SetBits(AES_CR_CHMOD_Msk, AES_CR_CHMOD_Pos, + AES_CHMOD_GCM) | + whal_SetBits(AES_CR_DATATYPE_Msk, AES_CR_DATATYPE_Pos, + AES_DATATYPE_NONE) | + whal_SetBits(AES_CR_KEYSIZE_Msk, AES_CR_KEYSIZE_Pos, + keySizeBit) | + whal_SetBits(AES_CR_GCMPH_Msk, AES_CR_GCMPH_Pos, + AES_GCMPH_INIT)); + + WriteKey(base, args->key, args->keySz); + + /* Write IV: 12 bytes nonce, counter=0x00000002 */ + whal_Reg_Write(base, AES_IVR3_REG, whal_LoadBe32(args->iv)); + whal_Reg_Write(base, AES_IVR2_REG, whal_LoadBe32(args->iv + 4)); + whal_Reg_Write(base, AES_IVR1_REG, whal_LoadBe32(args->iv + 8)); + whal_Reg_Write(base, AES_IVR0_REG, 0x00000002); + + /* Enable — init phase runs, EN auto-clears */ + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, AES_CR_EN_Msk); + + while (!(whal_Reg_Read(base, AES_SR_REG) & AES_SR_CCF_Msk)); + whal_Reg_Update(base, AES_CR_REG, AES_CR_CCFC_Msk, AES_CR_CCFC_Msk); + + /* --- Header phase: process AAD --- */ + if (args->aadSz > 0) { + whal_Reg_Update(base, AES_CR_REG, + AES_CR_MODE_Msk | AES_CR_GCMPH_Msk, + whal_SetBits(AES_CR_MODE_Msk, AES_CR_MODE_Pos, + AES_MODE_ENCRYPT) | + whal_SetBits(AES_CR_GCMPH_Msk, AES_CR_GCMPH_Pos, + AES_GCMPH_HEADER)); + + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, AES_CR_EN_Msk); + + for (i = 0; i < args->aadSz; i += 16) { + const uint8_t *aad = args->aad + i; + size_t remain = args->aadSz - i; + uint8_t block[16] = {0}; + size_t j; + + if (remain >= 16) { + WriteBlock(base, aad); + } else { + for (j = 0; j < remain; j++) + block[j] = aad[j]; + WriteBlock(base, block); + } + + while (!(whal_Reg_Read(base, AES_SR_REG) & AES_SR_CCF_Msk)); + whal_Reg_Update(base, AES_CR_REG, AES_CR_CCFC_Msk, + AES_CR_CCFC_Msk); + } + } + + /* --- Final phase: compute tag (skip payload for GMAC) --- */ + whal_Reg_Update(base, AES_CR_REG, + AES_CR_MODE_Msk | AES_CR_GCMPH_Msk, + whal_SetBits(AES_CR_MODE_Msk, AES_CR_MODE_Pos, + AES_MODE_ENCRYPT) | + whal_SetBits(AES_CR_GCMPH_Msk, AES_CR_GCMPH_Pos, + AES_GCMPH_FINAL)); + + if (args->aadSz == 0) + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, AES_CR_EN_Msk); + + /* Write bit-length block: aadSz*8 (64-bit) || 0 (64-bit) */ + whal_Reg_Write(base, AES_DINR_REG, 0); + whal_Reg_Write(base, AES_DINR_REG, (uint32_t)(args->aadSz * 8)); + whal_Reg_Write(base, AES_DINR_REG, 0); + whal_Reg_Write(base, AES_DINR_REG, 0); + + while (!(whal_Reg_Read(base, AES_SR_REG) & AES_SR_CCF_Msk)); + + /* Read tag from DOUTR */ + ReadBlock(base, tagBuf); + + for (i = 0; i < args->tagSz; i++) + args->tag[i] = tagBuf[i]; + + whal_Reg_Update(base, AES_CR_REG, AES_CR_CCFC_Msk, AES_CR_CCFC_Msk); + + /* Disable AES */ + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, 0); + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32wbAes_AesCcm(whal_Crypto *cryptoDev, void *opArgs) +{ + whal_Crypto_AesCcmArgs *args; + size_t base; + size_t mode; + size_t keySizeBit; + size_t i; + uint8_t b0[16]; + uint8_t block[16]; + uint8_t tagBuf[16]; + + if (!cryptoDev || !opArgs) + return WHAL_EINVAL; + + args = (whal_Crypto_AesCcmArgs *)opArgs; + + if (!args->key || !args->nonce || !args->tag) + return WHAL_EINVAL; + + if (args->keySz != 16 && args->keySz != 32) + return WHAL_EINVAL; + + if (args->nonceSz < 7 || args->nonceSz > 13) + return WHAL_EINVAL; + + if (args->sz > 0 && (!args->in || !args->out)) + return WHAL_EINVAL; + + if (args->aadSz > 0 && !args->aad) + return WHAL_EINVAL; + + if (args->tagSz < 4 || args->tagSz > 16 || (args->tagSz & 1) != 0) + return WHAL_EINVAL; + + base = cryptoDev->regmap.base; + keySizeBit = (args->keySz == 32) ? 1 : 0; + + mode = (args->dir == WHAL_CRYPTO_ENCRYPT) + ? AES_MODE_ENCRYPT : AES_MODE_DECRYPT; + + /* + * Build B0 block per RFC 3610: + * Flags = 8*(Adata?1:0) + 8*((t-2)/2) + (q-1) + * where q = 15 - nonceSz, t = tagSz + */ + { + size_t q = 15 - args->nonceSz; + size_t t = args->tagSz; + uint8_t flags = (uint8_t)(((args->aadSz > 0) ? 0x40 : 0) | + (((t - 2) / 2) << 3) | + (q - 1)); + b0[0] = flags; + for (i = 0; i < args->nonceSz; i++) + b0[1 + i] = args->nonce[i]; + + /* Encode message length in q bytes, big-endian */ + { + size_t msgLen = args->sz; + size_t j; + for (j = 0; j < q; j++) { + b0[15 - j] = (uint8_t)(msgLen & 0xFF); + msgLen >>= 8; + } + } + } + + /* Disable AES */ + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, 0); + + /* --- Init phase: load B0 into IVRx --- */ + /* CCM: CHMOD[2:0] = 100, so CHMOD[1:0]=00 and CHMOD[2]=1 */ + whal_Reg_Update(base, AES_CR_REG, + AES_CR_MODE_Msk | AES_CR_CHMOD_Msk | AES_CR_CHMOD2_Msk | + AES_CR_DATATYPE_Msk | AES_CR_KEYSIZE_Msk | + AES_CR_GCMPH_Msk, + whal_SetBits(AES_CR_MODE_Msk, AES_CR_MODE_Pos, + AES_MODE_ENCRYPT) | + whal_SetBits(AES_CR_CHMOD_Msk, AES_CR_CHMOD_Pos, 0) | + AES_CR_CHMOD2_Msk | + whal_SetBits(AES_CR_DATATYPE_Msk, AES_CR_DATATYPE_Pos, + AES_DATATYPE_NONE) | + whal_SetBits(AES_CR_KEYSIZE_Msk, AES_CR_KEYSIZE_Pos, + keySizeBit) | + whal_SetBits(AES_CR_GCMPH_Msk, AES_CR_GCMPH_Pos, + AES_GCMPH_INIT)); + + WriteKey(base, args->key, args->keySz); + WriteIv(base, b0); + + /* Enable — init phase runs, EN auto-clears */ + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, AES_CR_EN_Msk); + + while (!(whal_Reg_Read(base, AES_SR_REG) & AES_SR_CCF_Msk)); + whal_Reg_Update(base, AES_CR_REG, AES_CR_CCFC_Msk, AES_CR_CCFC_Msk); + + /* --- Header phase: process AAD with length prefix --- */ + if (args->aadSz > 0) { + whal_Reg_Update(base, AES_CR_REG, + AES_CR_MODE_Msk | AES_CR_GCMPH_Msk, + whal_SetBits(AES_CR_MODE_Msk, AES_CR_MODE_Pos, + AES_MODE_ENCRYPT) | + whal_SetBits(AES_CR_GCMPH_Msk, AES_CR_GCMPH_Pos, + AES_GCMPH_HEADER)); + + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, AES_CR_EN_Msk); + + /* + * B1 block: 2-byte length prefix followed by AAD data. + * For aadSz < 65280, prefix is just 2 bytes. + * Remaining AAD continues in subsequent blocks. + */ + { + uint8_t hdrBuf[16] = {0}; + size_t hdrOff = 0; + size_t aadOff = 0; + size_t j; + + /* 2-byte length prefix */ + hdrBuf[0] = (uint8_t)(args->aadSz >> 8); + hdrBuf[1] = (uint8_t)(args->aadSz); + hdrOff = 2; + + /* Fill rest of first block with AAD */ + while (hdrOff < 16 && aadOff < args->aadSz) { + hdrBuf[hdrOff++] = args->aad[aadOff++]; + } + + /* Write first block */ + WriteBlock(base, hdrBuf); + while (!(whal_Reg_Read(base, AES_SR_REG) & AES_SR_CCF_Msk)); + whal_Reg_Update(base, AES_CR_REG, AES_CR_CCFC_Msk, + AES_CR_CCFC_Msk); + + /* Process remaining AAD in 16-byte blocks */ + while (aadOff < args->aadSz) { + for (j = 0; j < 16; j++) + block[j] = 0; + + for (j = 0; j < 16 && aadOff < args->aadSz; j++) + block[j] = args->aad[aadOff++]; + + WriteBlock(base, block); + while (!(whal_Reg_Read(base, AES_SR_REG) & AES_SR_CCF_Msk)); + whal_Reg_Update(base, AES_CR_REG, AES_CR_CCFC_Msk, + AES_CR_CCFC_Msk); + } + } + } + + /* --- Payload phase --- */ + if (args->sz > 0) { + whal_Reg_Update(base, AES_CR_REG, + AES_CR_MODE_Msk | AES_CR_GCMPH_Msk, + whal_SetBits(AES_CR_MODE_Msk, AES_CR_MODE_Pos, mode) | + whal_SetBits(AES_CR_GCMPH_Msk, AES_CR_GCMPH_Pos, + AES_GCMPH_PAYLOAD)); + + if (args->aadSz == 0) + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, AES_CR_EN_Msk); + + for (i = 0; i < args->sz; i += 16) { + const uint8_t *in = args->in + i; + uint8_t *out = args->out + i; + size_t remain = args->sz - i; + size_t j; + + if (remain >= 16) { + WriteBlock(base, in); + } else { + for (j = 0; j < 16; j++) + block[j] = 0; + for (j = 0; j < remain; j++) + block[j] = in[j]; + WriteBlock(base, block); + } + + while (!(whal_Reg_Read(base, AES_SR_REG) & AES_SR_CCF_Msk)); + + if (remain >= 16) { + ReadBlock(base, out); + } else { + ReadBlock(base, block); + for (j = 0; j < remain; j++) + out[j] = block[j]; + } + + whal_Reg_Update(base, AES_CR_REG, AES_CR_CCFC_Msk, + AES_CR_CCFC_Msk); + } + } + + /* --- Final phase: compute/verify tag --- */ + whal_Reg_Update(base, AES_CR_REG, + AES_CR_MODE_Msk | AES_CR_GCMPH_Msk, + whal_SetBits(AES_CR_MODE_Msk, AES_CR_MODE_Pos, + AES_MODE_ENCRYPT) | + whal_SetBits(AES_CR_GCMPH_Msk, AES_CR_GCMPH_Pos, + AES_GCMPH_FINAL)); + + if (args->aadSz == 0 && args->sz == 0) + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, AES_CR_EN_Msk); + + /* Write zeros to DINR for final phase */ + whal_Reg_Write(base, AES_DINR_REG, 0); + whal_Reg_Write(base, AES_DINR_REG, 0); + whal_Reg_Write(base, AES_DINR_REG, 0); + whal_Reg_Write(base, AES_DINR_REG, 0); + + while (!(whal_Reg_Read(base, AES_SR_REG) & AES_SR_CCF_Msk)); + + /* Read tag from DOUTR */ + ReadBlock(base, tagBuf); + + for (i = 0; i < args->tagSz; i++) + args->tag[i] = tagBuf[i]; + + whal_Reg_Update(base, AES_CR_REG, AES_CR_CCFC_Msk, AES_CR_CCFC_Msk); + + /* Disable AES */ + whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, 0); + + return WHAL_SUCCESS; +} + +const whal_CryptoDriver whal_Stm32wbAes_Driver = { + .Init = whal_Stm32wbAes_Init, + .Deinit = whal_Stm32wbAes_Deinit, +}; diff --git a/tests/README.md b/tests/README.md index 807ca74..da63bf0 100644 --- a/tests/README.md +++ b/tests/README.md @@ -48,8 +48,8 @@ Board support (device instances, linker scripts, etc.) lives in the top-level ## Core Tests -Host-side unit tests (bitops, dispatch) live in `core/` and build with the -native compiler: +Host-side unit tests (bitops, dispatch, endian) live in `core/` and build with +the native compiler: ``` cd core && make && make run diff --git a/tests/core/Makefile b/tests/core/Makefile index 25e1865..2e32fee 100644 --- a/tests/core/Makefile +++ b/tests/core/Makefile @@ -3,7 +3,7 @@ WHAL_DIR = $(CURDIR)/../.. INCLUDE = -I$(WHAL_DIR) CFLAGS = -Wall -Werror $(INCLUDE) -g3 -TEST_SRC = main.c test_bitops.c test_dispatch.c +TEST_SRC = main.c test_bitops.c test_dispatch.c test_endian.c WHAL_SRC = $(WHAL_DIR)/src/clock/clock.c \ $(WHAL_DIR)/src/gpio/gpio.c \ diff --git a/tests/core/main.c b/tests/core/main.c index bd2aa8f..71ac87c 100644 --- a/tests/core/main.c +++ b/tests/core/main.c @@ -3,7 +3,9 @@ int g_whalTestPassed; int g_whalTestFailed; +int g_whalTestSkipped; int g_whalTestCurFailed; +int g_whalTestCurSkipped; void whal_Test_Puts(const char *s) { @@ -12,14 +14,17 @@ void whal_Test_Puts(const char *s) void whal_Test_Bitops(void); void whal_Test_Dispatch(void); +void whal_Test_Endian(void); int main(void) { g_whalTestPassed = 0; g_whalTestFailed = 0; + g_whalTestSkipped = 0; whal_Test_Bitops(); whal_Test_Dispatch(); + whal_Test_Endian(); WHAL_TEST_SUMMARY(); diff --git a/tests/core/test_endian.c b/tests/core/test_endian.c new file mode 100644 index 0000000..44d5706 --- /dev/null +++ b/tests/core/test_endian.c @@ -0,0 +1,84 @@ +#include +#include "../test.h" + +static void Test_Endian_LoadBe32(void) +{ + const uint8_t buf[] = { 0xDE, 0xAD, 0xBE, 0xEF }; + WHAL_ASSERT_EQ(whal_LoadBe32(buf), 0xDEADBEEFul); +} + +static void Test_Endian_LoadBe32_Zero(void) +{ + const uint8_t buf[] = { 0x00, 0x00, 0x00, 0x00 }; + WHAL_ASSERT_EQ(whal_LoadBe32(buf), 0x00000000ul); +} + +static void Test_Endian_LoadBe32_AllOnes(void) +{ + const uint8_t buf[] = { 0xFF, 0xFF, 0xFF, 0xFF }; + WHAL_ASSERT_EQ(whal_LoadBe32(buf), 0xFFFFFFFFul); +} + +static void Test_Endian_LoadBe32_MsbOnly(void) +{ + const uint8_t buf[] = { 0x80, 0x00, 0x00, 0x00 }; + WHAL_ASSERT_EQ(whal_LoadBe32(buf), 0x80000000ul); +} + +static void Test_Endian_LoadBe32_LsbOnly(void) +{ + const uint8_t buf[] = { 0x00, 0x00, 0x00, 0x01 }; + WHAL_ASSERT_EQ(whal_LoadBe32(buf), 0x00000001ul); +} + +static void Test_Endian_StoreBe32(void) +{ + uint8_t buf[4] = {0}; + whal_StoreBe32(buf, 0xDEADBEEF); + WHAL_ASSERT_EQ(buf[0], 0xDE); + WHAL_ASSERT_EQ(buf[1], 0xAD); + WHAL_ASSERT_EQ(buf[2], 0xBE); + WHAL_ASSERT_EQ(buf[3], 0xEF); +} + +static void Test_Endian_StoreBe32_Zero(void) +{ + uint8_t buf[4] = { 0xFF, 0xFF, 0xFF, 0xFF }; + whal_StoreBe32(buf, 0x00000000); + WHAL_ASSERT_EQ(buf[0], 0x00); + WHAL_ASSERT_EQ(buf[1], 0x00); + WHAL_ASSERT_EQ(buf[2], 0x00); + WHAL_ASSERT_EQ(buf[3], 0x00); +} + +static void Test_Endian_StoreBe32_MsbOnly(void) +{ + uint8_t buf[4] = {0}; + whal_StoreBe32(buf, 0x80000000); + WHAL_ASSERT_EQ(buf[0], 0x80); + WHAL_ASSERT_EQ(buf[1], 0x00); + WHAL_ASSERT_EQ(buf[2], 0x00); + WHAL_ASSERT_EQ(buf[3], 0x00); +} + +static void Test_Endian_Roundtrip(void) +{ + uint8_t buf[4] = {0}; + whal_StoreBe32(buf, 0xCAFEBABE); + WHAL_ASSERT_EQ(whal_LoadBe32(buf), 0xCAFEBABEul); +} + +void whal_Test_Endian(void) +{ + WHAL_TEST_SUITE_START("endian"); + WHAL_TEST(Test_Endian_LoadBe32); + WHAL_TEST(Test_Endian_LoadBe32_Zero); + WHAL_TEST(Test_Endian_LoadBe32_AllOnes); + WHAL_TEST(Test_Endian_LoadBe32_MsbOnly); + WHAL_TEST(Test_Endian_LoadBe32_LsbOnly); + WHAL_TEST(Test_Endian_StoreBe32); + WHAL_TEST(Test_Endian_StoreBe32_Zero); + WHAL_TEST(Test_Endian_StoreBe32_MsbOnly); + WHAL_TEST(Test_Endian_Roundtrip); + WHAL_TEST_SUITE_END(); +} diff --git a/tests/crypto/test_crypto.c b/tests/crypto/test_crypto.c new file mode 100644 index 0000000..03a2162 --- /dev/null +++ b/tests/crypto/test_crypto.c @@ -0,0 +1,483 @@ +#include +#include +#include "board.h" +#include "test.h" + +static const uint8_t key[32] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, +}; + +static const uint8_t iv[16] = { + 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, + 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, +}; + +static const uint8_t nonce[12] = { + 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, + 0xB8, 0xB9, 0xBA, 0xBB, +}; + +static const uint8_t aad[16] = { + 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, + 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, +}; + +static const uint8_t plaintext[32] = { + 0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE, 0xBA, 0xBE, + 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, +}; + +/* NIST SP 800-38A test vectors (AES-256, single block) */ +static const uint8_t nistKey[32] = { + 0x60, 0x3D, 0xEB, 0x10, 0x15, 0xCA, 0x71, 0xBE, + 0x2B, 0x73, 0xAE, 0xF0, 0x85, 0x7D, 0x77, 0x81, + 0x1F, 0x35, 0x2C, 0x07, 0x3B, 0x61, 0x08, 0xD7, + 0x2D, 0x98, 0x10, 0xA3, 0x09, 0x14, 0xDF, 0xF4, +}; + +static const uint8_t nistPt[16] = { + 0x6B, 0xC1, 0xBE, 0xE2, 0x2E, 0x40, 0x9F, 0x96, + 0xE9, 0x3D, 0x7E, 0x11, 0x73, 0x93, 0x17, 0x2A, +}; + +/* NIST SP 800-38A F.1.5 AES-256-ECB expected ciphertext */ +static const uint8_t nistEcbCt[16] = { + 0xF3, 0xEE, 0xD1, 0xBD, 0xB5, 0xD2, 0xA0, 0x3C, + 0x06, 0x4B, 0x5A, 0x7E, 0x3D, 0xB1, 0x81, 0xF8, +}; + +/* NIST SP 800-38A F.2.5 AES-256-CBC expected ciphertext */ +static const uint8_t nistCbcIv[16] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, +}; + +static const uint8_t nistCbcCt[16] = { + 0xF5, 0x8C, 0x4C, 0x04, 0xD6, 0xE5, 0xF1, 0xBA, + 0x77, 0x9E, 0xAB, 0xFB, 0x5F, 0x7B, 0xFB, 0xD6, +}; + +/* NIST SP 800-38A F.5.5 AES-256-CTR expected ciphertext */ +static const uint8_t nistCtrIv[16] = { + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, + 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, +}; + +static const uint8_t nistCtrCt[16] = { + 0x60, 0x1E, 0xC3, 0x13, 0x77, 0x57, 0x89, 0xA5, + 0xB7, 0xA7, 0xF5, 0x04, 0xBB, 0xF3, 0xD2, 0x28, +}; + +/* GCM spec Test Case 15: AES-256-GCM, 64-byte payload, no AAD */ +static const uint8_t gcmKey[32] = { + 0xFE, 0xFF, 0xE9, 0x92, 0x86, 0x65, 0x73, 0x1C, + 0x6D, 0x6A, 0x8F, 0x94, 0x67, 0x30, 0x83, 0x08, + 0xFE, 0xFF, 0xE9, 0x92, 0x86, 0x65, 0x73, 0x1C, + 0x6D, 0x6A, 0x8F, 0x94, 0x67, 0x30, 0x83, 0x08, +}; + +static const uint8_t gcmIv[12] = { + 0xCA, 0xFE, 0xBA, 0xBE, 0xFA, 0xCE, 0xDB, 0xAD, + 0xDE, 0xCA, 0xF8, 0x88, +}; + +static const uint8_t gcmPt[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 uint8_t gcmCt[64] = { + 0x52, 0x2D, 0xC1, 0xF0, 0x99, 0x56, 0x7D, 0x07, + 0xF4, 0x7F, 0x37, 0xA3, 0x2A, 0x84, 0x42, 0x7D, + 0x64, 0x3A, 0x8C, 0xDC, 0xBF, 0xE5, 0xC0, 0xC9, + 0x75, 0x98, 0xA2, 0xBD, 0x25, 0x55, 0xD1, 0xAA, + 0x8C, 0xB0, 0x8E, 0x48, 0x59, 0x0D, 0xBB, 0x3D, + 0xA7, 0xB0, 0x8B, 0x10, 0x56, 0x82, 0x88, 0x38, + 0xC5, 0xF6, 0x1E, 0x63, 0x93, 0xBA, 0x7A, 0x0A, + 0xBC, 0xC9, 0xF6, 0x62, 0x89, 0x80, 0x15, 0xAD, +}; + +static const uint8_t gcmTag[16] = { + 0xB0, 0x94, 0xDA, 0xC5, 0xD9, 0x34, 0x71, 0xBD, + 0xEC, 0x1A, 0x50, 0x22, 0x70, 0xE3, 0xCC, 0x6C, +}; + +/* NIST CAVP gcmEncryptExtIV256.rsp: Keylen=256, IVlen=96, PTlen=0, AADlen=128, Taglen=128, Count=0 */ +static const uint8_t gmacKey[32] = { + 0x78, 0xDC, 0x4E, 0x0A, 0xAF, 0x52, 0xD9, 0x35, + 0xC3, 0xC0, 0x1E, 0xEA, 0x57, 0x42, 0x8F, 0x00, + 0xCA, 0x1F, 0xD4, 0x75, 0xF5, 0xDA, 0x86, 0xA4, + 0x9C, 0x8D, 0xD7, 0x3D, 0x68, 0xC8, 0xE2, 0x23, +}; + +static const uint8_t gmacIv[12] = { + 0xD7, 0x9C, 0xF2, 0x2D, 0x50, 0x4C, 0xC7, 0x93, + 0xC3, 0xFB, 0x6C, 0x8A, +}; + +static const uint8_t gmacAad[16] = { + 0xB9, 0x6B, 0xAA, 0x8C, 0x1C, 0x75, 0xA6, 0x71, + 0xBF, 0xB2, 0xD0, 0x8D, 0x06, 0xBE, 0x5F, 0x36, +}; + +static const uint8_t gmacTag[16] = { + 0x3E, 0x5D, 0x48, 0x6A, 0xA2, 0xE3, 0x0B, 0x22, + 0xE0, 0x40, 0xB8, 0x57, 0x23, 0xA0, 0x6E, 0x76, +}; + +/* NIST CAVP DVPT256.rsp: Alen=32, Plen=24, Nlen=13, Tlen=16, Count=225 */ +static const uint8_t ccmKey[32] = { + 0x31, 0x4A, 0x20, 0x2F, 0x83, 0x6F, 0x9F, 0x25, + 0x7E, 0x22, 0xD8, 0xC1, 0x17, 0x57, 0x83, 0x2A, + 0xE5, 0x13, 0x1D, 0x35, 0x7A, 0x72, 0xDF, 0x88, + 0xF3, 0xEF, 0xF0, 0xFF, 0xCE, 0xE0, 0xDA, 0x4E, +}; + +static const uint8_t ccmNonce[13] = { + 0xA5, 0x44, 0x21, 0x8D, 0xAD, 0xD3, 0xC1, 0x05, + 0x83, 0xDB, 0x49, 0xCF, 0x39, +}; + +static const uint8_t ccmAad[32] = { + 0x3C, 0x0E, 0x28, 0x15, 0xD3, 0x7D, 0x84, 0x4F, + 0x7A, 0xC2, 0x40, 0xBA, 0x9D, 0x6E, 0x3A, 0x0B, + 0x2A, 0x86, 0xF7, 0x06, 0xE8, 0x85, 0x95, 0x9E, + 0x09, 0xA1, 0x00, 0x5E, 0x02, 0x4F, 0x69, 0x07, +}; + +static const uint8_t ccmPt[24] = { + 0xE8, 0xDE, 0x97, 0x0F, 0x6E, 0xE8, 0xE8, 0x0E, + 0xDE, 0x93, 0x35, 0x81, 0xB5, 0xBC, 0xF4, 0xD8, + 0x37, 0xE2, 0xB7, 0x2B, 0xAA, 0x8B, 0x00, 0xC3, +}; + +static const uint8_t ccmCt[24] = { + 0x8D, 0x34, 0xCD, 0xCA, 0x37, 0xCE, 0x77, 0xBE, + 0x68, 0xF6, 0x5B, 0xAF, 0x33, 0x82, 0xE3, 0x1E, + 0xFA, 0x69, 0x3E, 0x63, 0xF9, 0x14, 0xA7, 0x81, +}; + +static const uint8_t ccmTag[16] = { + 0x36, 0x7F, 0x30, 0xF2, 0xEA, 0xAD, 0x8C, 0x06, + 0x3C, 0xA5, 0x07, 0x95, 0xAC, 0xD9, 0x02, 0x03, +}; + +static int BoardHasOp(size_t op) +{ + return op < g_whalCrypto.opsCount && g_whalCrypto.ops[op] != 0; +} + +static void Test_Crypto_AesEcb_Basic(void) +{ + uint8_t ct[32] = {0}; + uint8_t pt[32] = {0}; + + if (!BoardHasOp(BOARD_CRYPTO_AES_ECB)) + WHAL_SKIP(); + + whal_Crypto_AesEcbArgs enc = { + .dir = WHAL_CRYPTO_ENCRYPT, .key = key, .keySz = 32, + .in = plaintext, .out = ct, .sz = sizeof(plaintext), + }; + WHAL_ASSERT_EQ(whal_Crypto_Op(&g_whalCrypto, BOARD_CRYPTO_AES_ECB, &enc), + WHAL_SUCCESS); + + whal_Crypto_AesEcbArgs dec = { + .dir = WHAL_CRYPTO_DECRYPT, .key = key, .keySz = 32, + .in = ct, .out = pt, .sz = sizeof(ct), + }; + WHAL_ASSERT_EQ(whal_Crypto_Op(&g_whalCrypto, BOARD_CRYPTO_AES_ECB, &dec), + WHAL_SUCCESS); + + WHAL_ASSERT_MEM_EQ(pt, plaintext, sizeof(plaintext)); +} + +static void Test_Crypto_AesCbc_Basic(void) +{ + uint8_t ct[32] = {0}; + uint8_t pt[32] = {0}; + + if (!BoardHasOp(BOARD_CRYPTO_AES_CBC)) + WHAL_SKIP(); + + whal_Crypto_AesCbcArgs enc = { + .dir = WHAL_CRYPTO_ENCRYPT, .key = key, .keySz = 32, + .iv = iv, .in = plaintext, .out = ct, .sz = sizeof(plaintext), + }; + WHAL_ASSERT_EQ(whal_Crypto_Op(&g_whalCrypto, BOARD_CRYPTO_AES_CBC, &enc), + WHAL_SUCCESS); + + whal_Crypto_AesCbcArgs dec = { + .dir = WHAL_CRYPTO_DECRYPT, .key = key, .keySz = 32, + .iv = iv, .in = ct, .out = pt, .sz = sizeof(ct), + }; + WHAL_ASSERT_EQ(whal_Crypto_Op(&g_whalCrypto, BOARD_CRYPTO_AES_CBC, &dec), + WHAL_SUCCESS); + + WHAL_ASSERT_MEM_EQ(pt, plaintext, sizeof(plaintext)); +} + +static void Test_Crypto_AesCtr_Basic(void) +{ + uint8_t ct[32] = {0}; + uint8_t pt[32] = {0}; + + if (!BoardHasOp(BOARD_CRYPTO_AES_CTR)) + WHAL_SKIP(); + + whal_Crypto_AesCtrArgs enc = { + .dir = WHAL_CRYPTO_ENCRYPT, .key = key, .keySz = 32, + .iv = iv, .in = plaintext, .out = ct, .sz = sizeof(plaintext), + }; + WHAL_ASSERT_EQ(whal_Crypto_Op(&g_whalCrypto, BOARD_CRYPTO_AES_CTR, &enc), + WHAL_SUCCESS); + + whal_Crypto_AesCtrArgs dec = { + .dir = WHAL_CRYPTO_DECRYPT, .key = key, .keySz = 32, + .iv = iv, .in = ct, .out = pt, .sz = sizeof(ct), + }; + WHAL_ASSERT_EQ(whal_Crypto_Op(&g_whalCrypto, BOARD_CRYPTO_AES_CTR, &dec), + WHAL_SUCCESS); + + WHAL_ASSERT_MEM_EQ(pt, plaintext, sizeof(plaintext)); +} + +static void Test_Crypto_AesGcm_Basic(void) +{ + uint8_t ct[32] = {0}; + uint8_t pt[32] = {0}; + uint8_t encTag[16] = {0}; + uint8_t decTag[16] = {0}; + + if (!BoardHasOp(BOARD_CRYPTO_AES_GCM)) + WHAL_SKIP(); + + whal_Crypto_AesGcmArgs enc = { + .dir = WHAL_CRYPTO_ENCRYPT, .key = key, .keySz = 32, + .iv = nonce, .ivSz = sizeof(nonce), + .in = plaintext, .out = ct, .sz = sizeof(plaintext), + .aad = aad, .aadSz = sizeof(aad), + .tag = encTag, .tagSz = sizeof(encTag), + }; + WHAL_ASSERT_EQ(whal_Crypto_Op(&g_whalCrypto, BOARD_CRYPTO_AES_GCM, &enc), + WHAL_SUCCESS); + + whal_Crypto_AesGcmArgs dec = { + .dir = WHAL_CRYPTO_DECRYPT, .key = key, .keySz = 32, + .iv = nonce, .ivSz = sizeof(nonce), + .in = ct, .out = pt, .sz = sizeof(ct), + .aad = aad, .aadSz = sizeof(aad), + .tag = decTag, .tagSz = sizeof(decTag), + }; + WHAL_ASSERT_EQ(whal_Crypto_Op(&g_whalCrypto, BOARD_CRYPTO_AES_GCM, &dec), + WHAL_SUCCESS); + + WHAL_ASSERT_MEM_EQ(pt, plaintext, sizeof(plaintext)); + WHAL_ASSERT_MEM_EQ(decTag, encTag, sizeof(encTag)); +} + +static void Test_Crypto_AesGmac_Basic(void) +{ + uint8_t tag1[16] = {0}; + uint8_t tag2[16] = {0}; + + if (!BoardHasOp(BOARD_CRYPTO_AES_GMAC)) + WHAL_SKIP(); + + whal_Crypto_AesGmacArgs args1 = { + .key = key, .keySz = 32, + .iv = nonce, .ivSz = sizeof(nonce), + .aad = aad, .aadSz = sizeof(aad), + .tag = tag1, .tagSz = sizeof(tag1), + }; + WHAL_ASSERT_EQ(whal_Crypto_Op(&g_whalCrypto, BOARD_CRYPTO_AES_GMAC, &args1), + WHAL_SUCCESS); + + whal_Crypto_AesGmacArgs args2 = { + .key = key, .keySz = 32, + .iv = nonce, .ivSz = sizeof(nonce), + .aad = aad, .aadSz = sizeof(aad), + .tag = tag2, .tagSz = sizeof(tag2), + }; + WHAL_ASSERT_EQ(whal_Crypto_Op(&g_whalCrypto, BOARD_CRYPTO_AES_GMAC, &args2), + WHAL_SUCCESS); + + WHAL_ASSERT_MEM_EQ(tag1, tag2, sizeof(tag1)); +} + +static void Test_Crypto_AesCcm_Basic(void) +{ + uint8_t ct[32] = {0}; + uint8_t pt[32] = {0}; + uint8_t encTag[16] = {0}; + uint8_t decTag[16] = {0}; + + if (!BoardHasOp(BOARD_CRYPTO_AES_CCM)) + WHAL_SKIP(); + + whal_Crypto_AesCcmArgs enc = { + .dir = WHAL_CRYPTO_ENCRYPT, .key = key, .keySz = 32, + .nonce = nonce, .nonceSz = sizeof(nonce), + .in = plaintext, .out = ct, .sz = sizeof(plaintext), + .aad = aad, .aadSz = sizeof(aad), + .tag = encTag, .tagSz = sizeof(encTag), + }; + WHAL_ASSERT_EQ(whal_Crypto_Op(&g_whalCrypto, BOARD_CRYPTO_AES_CCM, &enc), + WHAL_SUCCESS); + + whal_Crypto_AesCcmArgs dec = { + .dir = WHAL_CRYPTO_DECRYPT, .key = key, .keySz = 32, + .nonce = nonce, .nonceSz = sizeof(nonce), + .in = ct, .out = pt, .sz = sizeof(ct), + .aad = aad, .aadSz = sizeof(aad), + .tag = decTag, .tagSz = sizeof(decTag), + }; + WHAL_ASSERT_EQ(whal_Crypto_Op(&g_whalCrypto, BOARD_CRYPTO_AES_CCM, &dec), + WHAL_SUCCESS); + + WHAL_ASSERT_MEM_EQ(pt, plaintext, sizeof(plaintext)); + WHAL_ASSERT_MEM_EQ(decTag, encTag, sizeof(encTag)); +} + +static void Test_Crypto_AesEcb_KnownAnswer(void) +{ + uint8_t ct[16] = {0}; + + if (!BoardHasOp(BOARD_CRYPTO_AES_ECB)) + WHAL_SKIP(); + + whal_Crypto_AesEcbArgs enc = { + .dir = WHAL_CRYPTO_ENCRYPT, .key = nistKey, .keySz = 32, + .in = nistPt, .out = ct, .sz = sizeof(nistPt), + }; + WHAL_ASSERT_EQ(whal_Crypto_Op(&g_whalCrypto, BOARD_CRYPTO_AES_ECB, &enc), + WHAL_SUCCESS); + + WHAL_ASSERT_MEM_EQ(ct, nistEcbCt, sizeof(nistEcbCt)); +} + +static void Test_Crypto_AesCbc_KnownAnswer(void) +{ + uint8_t ct[16] = {0}; + + if (!BoardHasOp(BOARD_CRYPTO_AES_CBC)) + WHAL_SKIP(); + + whal_Crypto_AesCbcArgs enc = { + .dir = WHAL_CRYPTO_ENCRYPT, .key = nistKey, .keySz = 32, + .iv = nistCbcIv, .in = nistPt, .out = ct, .sz = sizeof(nistPt), + }; + WHAL_ASSERT_EQ(whal_Crypto_Op(&g_whalCrypto, BOARD_CRYPTO_AES_CBC, &enc), + WHAL_SUCCESS); + + WHAL_ASSERT_MEM_EQ(ct, nistCbcCt, sizeof(nistCbcCt)); +} + +static void Test_Crypto_AesCtr_KnownAnswer(void) +{ + uint8_t ct[16] = {0}; + + if (!BoardHasOp(BOARD_CRYPTO_AES_CTR)) + WHAL_SKIP(); + + whal_Crypto_AesCtrArgs enc = { + .dir = WHAL_CRYPTO_ENCRYPT, .key = nistKey, .keySz = 32, + .iv = nistCtrIv, .in = nistPt, .out = ct, .sz = sizeof(nistPt), + }; + WHAL_ASSERT_EQ(whal_Crypto_Op(&g_whalCrypto, BOARD_CRYPTO_AES_CTR, &enc), + WHAL_SUCCESS); + + WHAL_ASSERT_MEM_EQ(ct, nistCtrCt, sizeof(nistCtrCt)); +} + +static void Test_Crypto_AesGcm_KnownAnswer(void) +{ + uint8_t ct[64] = {0}; + uint8_t tag[16] = {0}; + + if (!BoardHasOp(BOARD_CRYPTO_AES_GCM)) + WHAL_SKIP(); + + whal_Crypto_AesGcmArgs enc = { + .dir = WHAL_CRYPTO_ENCRYPT, .key = gcmKey, .keySz = 32, + .iv = gcmIv, .ivSz = sizeof(gcmIv), + .in = gcmPt, .out = ct, .sz = sizeof(gcmPt), + .aad = NULL, .aadSz = 0, + .tag = tag, .tagSz = sizeof(tag), + }; + WHAL_ASSERT_EQ(whal_Crypto_Op(&g_whalCrypto, BOARD_CRYPTO_AES_GCM, &enc), + WHAL_SUCCESS); + + WHAL_ASSERT_MEM_EQ(ct, gcmCt, sizeof(gcmCt)); + WHAL_ASSERT_MEM_EQ(tag, gcmTag, sizeof(gcmTag)); +} + +static void Test_Crypto_AesGmac_KnownAnswer(void) +{ + uint8_t tag[16] = {0}; + + if (!BoardHasOp(BOARD_CRYPTO_AES_GMAC)) + WHAL_SKIP(); + + whal_Crypto_AesGmacArgs args = { + .key = gmacKey, .keySz = 32, + .iv = gmacIv, .ivSz = sizeof(gmacIv), + .aad = gmacAad, .aadSz = sizeof(gmacAad), + .tag = tag, .tagSz = sizeof(tag), + }; + WHAL_ASSERT_EQ(whal_Crypto_Op(&g_whalCrypto, BOARD_CRYPTO_AES_GMAC, &args), + WHAL_SUCCESS); + + WHAL_ASSERT_MEM_EQ(tag, gmacTag, sizeof(gmacTag)); +} + +static void Test_Crypto_AesCcm_KnownAnswer(void) +{ + uint8_t ct[24] = {0}; + uint8_t tag[16] = {0}; + + if (!BoardHasOp(BOARD_CRYPTO_AES_CCM)) + WHAL_SKIP(); + + whal_Crypto_AesCcmArgs enc = { + .dir = WHAL_CRYPTO_ENCRYPT, .key = ccmKey, .keySz = 32, + .nonce = ccmNonce, .nonceSz = sizeof(ccmNonce), + .in = ccmPt, .out = ct, .sz = sizeof(ccmPt), + .aad = ccmAad, .aadSz = sizeof(ccmAad), + .tag = tag, .tagSz = sizeof(tag), + }; + WHAL_ASSERT_EQ(whal_Crypto_Op(&g_whalCrypto, BOARD_CRYPTO_AES_CCM, &enc), + WHAL_SUCCESS); + + WHAL_ASSERT_MEM_EQ(ct, ccmCt, sizeof(ccmCt)); + WHAL_ASSERT_MEM_EQ(tag, ccmTag, sizeof(ccmTag)); +} + +void whal_Test_Crypto(void) +{ + WHAL_TEST_SUITE_START("crypto"); + WHAL_TEST(Test_Crypto_AesEcb_Basic); + WHAL_TEST(Test_Crypto_AesEcb_KnownAnswer); + WHAL_TEST(Test_Crypto_AesCbc_Basic); + WHAL_TEST(Test_Crypto_AesCbc_KnownAnswer); + WHAL_TEST(Test_Crypto_AesCtr_Basic); + WHAL_TEST(Test_Crypto_AesCtr_KnownAnswer); + WHAL_TEST(Test_Crypto_AesGcm_Basic); + WHAL_TEST(Test_Crypto_AesGcm_KnownAnswer); + WHAL_TEST(Test_Crypto_AesGmac_Basic); + WHAL_TEST(Test_Crypto_AesGmac_KnownAnswer); + WHAL_TEST(Test_Crypto_AesCcm_Basic); + WHAL_TEST(Test_Crypto_AesCcm_KnownAnswer); + WHAL_TEST_SUITE_END(); +} diff --git a/tests/main.c b/tests/main.c index 5100f9d..81a24be 100644 --- a/tests/main.c +++ b/tests/main.c @@ -42,9 +42,15 @@ void whal_Test_Ipc_Platform(void); #endif #endif +#ifdef WHAL_TEST_ENABLE_CRYPTO +void whal_Test_Crypto(void); +#endif + int g_whalTestPassed; int g_whalTestFailed; +int g_whalTestSkipped; int g_whalTestCurFailed; +int g_whalTestCurSkipped; void whal_Test_Puts(const char *s) { @@ -61,6 +67,7 @@ void main(void) { g_whalTestPassed = 0; g_whalTestFailed = 0; + g_whalTestSkipped = 0; if (Board_Init() != WHAL_SUCCESS) while (1); @@ -109,6 +116,10 @@ void main(void) #endif #endif +#ifdef WHAL_TEST_ENABLE_CRYPTO + whal_Test_Crypto(); +#endif + WHAL_TEST_SUMMARY(); if (g_whalTestFailed == 0) { diff --git a/tests/test.h b/tests/test.h index 1d5b794..e6b25b6 100644 --- a/tests/test.h +++ b/tests/test.h @@ -78,7 +78,9 @@ static inline void whal_Test_Printf(const char *fmt, ...) extern int g_whalTestPassed; extern int g_whalTestFailed; +extern int g_whalTestSkipped; extern int g_whalTestCurFailed; +extern int g_whalTestCurSkipped; #define WHAL_TEST_SUITE_START(name) \ do { \ @@ -88,11 +90,22 @@ extern int g_whalTestCurFailed; #define WHAL_TEST_SUITE_END() \ do { } while (0) +#define WHAL_SKIP() \ + do { \ + g_whalTestCurSkipped = 1; \ + return; \ + } while (0) + #define WHAL_TEST(fn) \ do { \ g_whalTestCurFailed = 0; \ + g_whalTestCurSkipped = 0; \ fn(); \ - if (g_whalTestCurFailed) { \ + if (g_whalTestCurSkipped) { \ + whal_Test_Printf(#fn ": SKIP\n"); \ + g_whalTestSkipped++; \ + } \ + else if (g_whalTestCurFailed) { \ whal_Test_Printf(#fn ": FAIL\n"); \ g_whalTestFailed++; \ } \ @@ -140,6 +153,7 @@ extern int g_whalTestCurFailed; do { \ whal_Test_Printf("\n"); \ whal_Test_Printf("--- Results ---\n"); \ + whal_Test_Printf("Skipped: %d\n", g_whalTestSkipped); \ whal_Test_Printf("Passed: %d\n", g_whalTestPassed); \ whal_Test_Printf("Failed: %d\n", g_whalTestFailed); \ } while (0) diff --git a/wolfHAL/crypto/crypto.h b/wolfHAL/crypto/crypto.h new file mode 100644 index 0000000..d20b4a9 --- /dev/null +++ b/wolfHAL/crypto/crypto.h @@ -0,0 +1,179 @@ +#ifndef WHAL_CRYPTO_H +#define WHAL_CRYPTO_H + +#include +#include +#include +#include + +/* + * @file crypto.h + * @brief Generic crypto accelerator abstraction and driver interface. + */ + +/* ---- Common enums ---- */ + +typedef enum { + WHAL_CRYPTO_ENCRYPT, + WHAL_CRYPTO_DECRYPT, +} whal_Crypto_Dir; + +/* ---- Per-algorithm argument structs ---- */ + +/* + * @brief Arguments for AES-ECB. + */ +typedef struct { + whal_Crypto_Dir dir; + const uint8_t *key; + size_t keySz; /* 16, 24, or 32 */ + const uint8_t *in; + uint8_t *out; + size_t sz; /* Must be a multiple of 16 */ +} whal_Crypto_AesEcbArgs; + +/* + * @brief Arguments for AES-CBC. + */ +typedef struct { + whal_Crypto_Dir dir; + const uint8_t *key; + size_t keySz; /* 16, 24, or 32 */ + const uint8_t *iv; /* 16 bytes */ + const uint8_t *in; + uint8_t *out; + size_t sz; /* Must be a multiple of 16 */ +} whal_Crypto_AesCbcArgs; + +/* + * @brief Arguments for AES-CTR. + */ +typedef struct { + whal_Crypto_Dir dir; + const uint8_t *key; + size_t keySz; /* 16, 24, or 32 */ + const uint8_t *iv; /* 16 bytes (initial counter block) */ + const uint8_t *in; + uint8_t *out; + size_t sz; +} whal_Crypto_AesCtrArgs; + +/* + * @brief Arguments for AES-GCM. + */ +typedef struct { + whal_Crypto_Dir dir; + const uint8_t *key; + size_t keySz; /* 16, 24, or 32 */ + const uint8_t *iv; + size_t ivSz; /* Typically 12 */ + const uint8_t *in; + uint8_t *out; + size_t sz; + const uint8_t *aad; + size_t aadSz; + uint8_t *tag; + size_t tagSz; /* Up to 16 */ +} whal_Crypto_AesGcmArgs; + +/* + * @brief Arguments for AES-CCM. + */ +typedef struct { + whal_Crypto_Dir dir; + const uint8_t *key; + size_t keySz; /* 16, 24, or 32 */ + const uint8_t *nonce; + size_t nonceSz; /* 7-13 */ + const uint8_t *in; + uint8_t *out; + size_t sz; + const uint8_t *aad; + size_t aadSz; + uint8_t *tag; + size_t tagSz; /* 4, 6, 8, 10, 12, 14, or 16 */ +} whal_Crypto_AesCcmArgs; + +/* + * @brief Arguments for AES-GMAC (authentication only, no payload). + */ +typedef struct { + const uint8_t *key; + size_t keySz; /* 16, 24, or 32 */ + const uint8_t *iv; + size_t ivSz; /* Typically 12 */ + const uint8_t *aad; + size_t aadSz; + uint8_t *tag; + size_t tagSz; /* Up to 16 */ +} whal_Crypto_AesGmacArgs; + +/* ---- Device and driver ---- */ + +typedef struct whal_Crypto whal_Crypto; + +/* + * @brief Operation function pointer type for per-device ops tables. + */ +typedef whal_Error (*whal_Crypto_OpFunc)(whal_Crypto *cryptoDev, void *opArgs); + +/* + * @brief Driver vtable for crypto devices. + */ +typedef struct { + /* Initialize the crypto hardware. */ + whal_Error (*Init)(whal_Crypto *cryptoDev); + /* Deinitialize the crypto hardware. */ + whal_Error (*Deinit)(whal_Crypto *cryptoDev); +} whal_CryptoDriver; + +/* + * @brief Crypto device instance tying a register map, driver, and ops table. + */ +struct whal_Crypto { + const whal_Regmap regmap; + const whal_CryptoDriver *driver; + const whal_Crypto_OpFunc *ops; + size_t opsCount; + const void *cfg; +}; + +#ifdef WHAL_CFG_DIRECT_CALLBACKS +#define whal_Crypto_Init(cryptoDev) ((cryptoDev)->driver->Init((cryptoDev))) +#define whal_Crypto_Deinit(cryptoDev) ((cryptoDev)->driver->Deinit((cryptoDev))) +#define whal_Crypto_Op(cryptoDev, op, opArgs) ((cryptoDev)->ops[(op)]((cryptoDev), (opArgs))) +#else +/* + * @brief Initializes a crypto device and its driver. + * + * @param cryptoDev Pointer to the crypto instance to initialize. + * + * @retval WHAL_SUCCESS Driver-specific init completed. + * @retval WHAL_EINVAL Null pointer or driver rejected configuration. + */ +whal_Error whal_Crypto_Init(whal_Crypto *cryptoDev); + +/* + * @brief Deinitializes a crypto device and releases resources. + * + * @param cryptoDev Pointer to the crypto instance to deinitialize. + * + * @retval WHAL_SUCCESS Driver-specific deinit completed. + * @retval WHAL_EINVAL Null pointer or driver refused to deinit. + */ +whal_Error whal_Crypto_Deinit(whal_Crypto *cryptoDev); + +/* + * @brief Perform a crypto operation. + * + * @param cryptoDev Pointer to the crypto instance. + * @param op Operation index into the platform-specific ops table. + * @param opArgs Platform-specific operation arguments. + * + * @retval WHAL_SUCCESS Operation completed. + * @retval WHAL_EINVAL Null pointer, invalid op, or driver failed. + */ +whal_Error whal_Crypto_Op(whal_Crypto *cryptoDev, size_t op, void *opArgs); +#endif + +#endif /* WHAL_CRYPTO_H */ diff --git a/wolfHAL/crypto/stm32wb_aes.h b/wolfHAL/crypto/stm32wb_aes.h new file mode 100644 index 0000000..57cbbc2 --- /dev/null +++ b/wolfHAL/crypto/stm32wb_aes.h @@ -0,0 +1,136 @@ +#ifndef WHAL_STM32WB_AES_H +#define WHAL_STM32WB_AES_H + +#include +#include +#include + +/* + * @file stm32wb_aes.h + * @brief STM32WB AES hardware accelerator driver. + * + * The STM32WB AES1 peripheral supports 128/256-bit keys in ECB, CBC, + * CTR, GCM, GMAC, and CCM modes. This driver exposes those modes through the + * generic whal_Crypto Op interface. + */ + +/* + * @brief AES device configuration. + */ +typedef struct { + whal_Clock *clkCtrl; + const void *clk; + +} whal_Stm32wbAes_Cfg; + +/* + * @brief Driver instance for STM32WB AES peripheral. + */ +extern const whal_CryptoDriver whal_Stm32wbAes_Driver; + +/* + * @brief Initialize the STM32WB AES peripheral. + * + * @param cryptoDev Crypto device instance. + * + * @retval WHAL_SUCCESS Initialization completed. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Stm32wbAes_Init(whal_Crypto *cryptoDev); + +/* + * @brief Deinitialize the STM32WB AES peripheral. + * + * @param cryptoDev Crypto device instance. + * + * @retval WHAL_SUCCESS Deinit completed. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Stm32wbAes_Deinit(whal_Crypto *cryptoDev); + + +/* + * @brief Perform AES-ECB encrypt or decrypt. + * + * Compatible with whal_Crypto_OpFunc. Cast opArgs to whal_Crypto_AesEcbArgs. + * + * @param cryptoDev Crypto device instance. + * @param opArgs Pointer to whal_Crypto_AesEcbArgs. + * + * @retval WHAL_SUCCESS Operation completed. + * @retval WHAL_EINVAL Invalid arguments. + * @retval WHAL_EHARDWARE Hardware error during operation. + */ +whal_Error whal_Stm32wbAes_AesEcb(whal_Crypto *cryptoDev, void *opArgs); + +/* + * @brief Perform AES-CBC encrypt or decrypt. + * + * Compatible with whal_Crypto_OpFunc. Cast opArgs to whal_Crypto_AesCbcArgs. + * + * @param cryptoDev Crypto device instance. + * @param opArgs Pointer to whal_Crypto_AesCbcArgs. + * + * @retval WHAL_SUCCESS Operation completed. + * @retval WHAL_EINVAL Invalid arguments. + * @retval WHAL_EHARDWARE Hardware error during operation. + */ +whal_Error whal_Stm32wbAes_AesCbc(whal_Crypto *cryptoDev, void *opArgs); + +/* + * @brief Perform AES-CTR encrypt or decrypt. + * + * Compatible with whal_Crypto_OpFunc. Cast opArgs to whal_Crypto_AesCtrArgs. + * + * @param cryptoDev Crypto device instance. + * @param opArgs Pointer to whal_Crypto_AesCtrArgs. + * + * @retval WHAL_SUCCESS Operation completed. + * @retval WHAL_EINVAL Invalid arguments. + * @retval WHAL_EHARDWARE Hardware error during operation. + */ +whal_Error whal_Stm32wbAes_AesCtr(whal_Crypto *cryptoDev, void *opArgs); + +/* + * @brief Perform AES-GCM encrypt or decrypt. + * + * Compatible with whal_Crypto_OpFunc. Cast opArgs to whal_Crypto_AesGcmArgs. + * + * @param cryptoDev Crypto device instance. + * @param opArgs Pointer to whal_Crypto_AesGcmArgs. + * + * @retval WHAL_SUCCESS Operation completed. + * @retval WHAL_EINVAL Invalid arguments. + * @retval WHAL_EHARDWARE Hardware error during operation. + */ +whal_Error whal_Stm32wbAes_AesGcm(whal_Crypto *cryptoDev, void *opArgs); + +/* + * @brief Perform AES-GMAC authentication (no payload). + * + * Compatible with whal_Crypto_OpFunc. Cast opArgs to whal_Crypto_AesGmacArgs. + * + * @param cryptoDev Crypto device instance. + * @param opArgs Pointer to whal_Crypto_AesGmacArgs. + * + * @retval WHAL_SUCCESS Operation completed. + * @retval WHAL_EINVAL Invalid arguments. + * @retval WHAL_EHARDWARE Hardware error during operation. + */ +whal_Error whal_Stm32wbAes_AesGmac(whal_Crypto *cryptoDev, void *opArgs); + +/* + * @brief Perform AES-CCM encrypt or decrypt. + * + * Compatible with whal_Crypto_OpFunc. Cast opArgs to whal_Crypto_AesCcmArgs. + * + * @param cryptoDev Crypto device instance. + * @param opArgs Pointer to whal_Crypto_AesCcmArgs. + * + * @retval WHAL_SUCCESS Operation completed. + * @retval WHAL_EINVAL Invalid arguments. + * @retval WHAL_EHARDWARE Hardware error during operation. + */ +whal_Error whal_Stm32wbAes_AesCcm(whal_Crypto *cryptoDev, void *opArgs); + +#endif /* WHAL_STM32WB_AES_H */ diff --git a/wolfHAL/endian.h b/wolfHAL/endian.h new file mode 100644 index 0000000..d0db593 --- /dev/null +++ b/wolfHAL/endian.h @@ -0,0 +1,31 @@ +#ifndef WHAL_ENDIAN_H +#define WHAL_ENDIAN_H + +/* + * @file endian.h + * @brief Byte-order conversion helpers. + */ + +#include + +/* + * @brief Load a 32-bit value from a big-endian byte array. + */ +static inline uint32_t whal_LoadBe32(const uint8_t *p) +{ + return ((uint32_t)p[0] << 24) | ((uint32_t)p[1] << 16) | + ((uint32_t)p[2] << 8) | p[3]; +} + +/* + * @brief Store a 32-bit value into a big-endian byte array. + */ +static inline void whal_StoreBe32(uint8_t *p, uint32_t v) +{ + p[0] = (uint8_t)(v >> 24); + p[1] = (uint8_t)(v >> 16); + p[2] = (uint8_t)(v >> 8); + p[3] = (uint8_t)v; +} + +#endif /* WHAL_ENDIAN_H */ diff --git a/wolfHAL/platform/st/stm32wb55xx.h b/wolfHAL/platform/st/stm32wb55xx.h index c75bf89..ca05c17 100644 --- a/wolfHAL/platform/st/stm32wb55xx.h +++ b/wolfHAL/platform/st/stm32wb55xx.h @@ -9,6 +9,7 @@ #include #include #include +#include /* * @file stm32wb55xx.h @@ -64,6 +65,13 @@ }, \ .driver = &whal_Stm32wbRng_Driver +#define WHAL_STM32WB55_AES1_DEVICE \ + .regmap = { \ + .base = 0x50060000, \ + .size = 0x400, \ + }, \ + .driver = &whal_Stm32wbAes_Driver + #define WHAL_STM32WB55_FLASH_DEVICE \ .regmap = { \ .base = 0x58004000, \ @@ -87,6 +95,11 @@ .enableMask = (1UL << 1), \ .enablePos = 1 +#define WHAL_STM32WB55_AES1_CLOCK \ + .regOffset = 0x4C, \ + .enableMask = (1UL << 16), \ + .enablePos = 16 + #define WHAL_STM32WB55_RNG_CLOCK \ .regOffset = 0x50, \ .enableMask = (1UL << 18), \ @@ -112,4 +125,5 @@ .enableMask = (1UL << 12), \ .enablePos = 12 + #endif /* WHAL_STM32WB55XX_H */ diff --git a/wolfHAL/regmap.h b/wolfHAL/regmap.h index 353053c..c04b4a3 100644 --- a/wolfHAL/regmap.h +++ b/wolfHAL/regmap.h @@ -56,4 +56,29 @@ static inline void whal_Reg_Get(size_t base, size_t offset, size_t msk, *value = whal_GetBits(msk, pos, val); } +/* + * @brief Write a 32-bit value to a memory-mapped register. + * + * @param base Base address of the register block. + * @param offset Byte offset from @p base to the register. + * @param value Value to write. + */ +static inline void whal_Reg_Write(size_t base, size_t offset, size_t value) +{ + *(volatile size_t *)(base + offset) = value; +} + +/* + * @brief Read a 32-bit value from a memory-mapped register. + * + * @param base Base address of the register block. + * @param offset Byte offset from @p base to the register. + * + * @return The register value. + */ +static inline size_t whal_Reg_Read(size_t base, size_t offset) +{ + return *(volatile size_t *)(base + offset); +} + #endif /* WHAL_REGMAP_H */ diff --git a/wolfHAL/wolfHAL.h b/wolfHAL/wolfHAL.h index 29499ec..716a1e8 100644 --- a/wolfHAL/wolfHAL.h +++ b/wolfHAL/wolfHAL.h @@ -18,5 +18,6 @@ #include #include #include +#include #endif /* WOLFHAL_H */