全部例程

AES(ECB / CBC)硬件加密功能

W55MH32

更新于 2026年8月19日

本篇总结

使用硬件 AES-128,实现 ECB/CBC 模式的加解密。

🔑 KEIL MDK、UART调试、AES

W55MH32L 集成了硬件 AES-128 加密引擎,支持 ECB(电子密码本)和 CBC(密码块链接)两种工作模式。本示例演示如何使用硬件 AES 对 48 字节明文进行 ECB/CBC 加密并解密验证。

前置工具准备

开始本例程前,请确认以下工具已安装:

硬件连接

本例程无需外部硬件连接,AES 运算完全在芯片内部完成。USART1 的 TX(PA9) 和 RX(PA10) 通过板载 USB 转串口芯片连接到 DEBUG USB 口,用于输出加密解密结果。

引脚 功能 方向 模式
PA9 USART1_TX 开发板 → PC 复用推挽输出 (AF_PP)
PA10 USART1_RX PC → 开发板 浮空输入 (IN_FLOATING)

工程结构

工程位于 SDK 内 1.SDK\ModuleDemo\ADC\,核心文件如下:

AES/
├── USER/
│   ├── main.c            ← AES加解密测试 + printf重定向
│   ├── w55mh32_conf.h    ← 外设头文件集中包含
│   ├── w55mh32_it.c/h    ← 中断服务函数
│   ├── system_w55mh32.c/h← 系统初始化(时钟配置)
│   └── startup_w55mh32.s ← 启动文件
└── SYSTEM/
    └── delay/
        └── delay.c/h      ← SysTick 延时函数

步骤1:AES 结构体与 ECB 加解密

文件:USER/main.c | 函数:AES_Func_Test() — 定义明文、密钥,填充 WIZ_SYN_CRYPTO_CAL_t 结构体后调用 WIZAES_EncDec() 执行 ECB 加密,再用密文作为输入执行解密。

void AES_Func_Test()
{
    uint8_t ausPlain[AES_TEST_LEN] = {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,0x20,
        0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,
        0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x30};
    uint8_t ausResult[AES_TEST_LEN] = {0};
    uint8_t ausKey[16] = {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,
        0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10};
    WIZ_SYN_CRYPTO_CAL_t callAes;

    printf("The AES data input is:\r\n");
    for (i = 0; i < AES_TEST_LEN; i++)
        printf("%02X", ausPlain[i]);
    printf("\r\n");

    /* ECB 加密 */
    memset((uint8_t *)&callAes, 0, sizeof(callAes));
    callAes.pu8In      = ausPlain;
    callAes.ui32InLen  = AES_TEST_LEN;
    callAes.pu8Out     = ausResult;
    callAes.ui32OutLen = AES_TEST_LEN;
    callAes.pu8Key     = ausKey;
    callAes.ui32Key    = WIZ_AES_KEY_SIZE_128 | WIZ_AES_OP_MODE_ECB | WIZ_AES_OP_MODE_ENCRYPT;
    callAes.ui32Ctrl   = WIZC_CalcBuffCrc((uint8_t *)&callAes, sizeof(WIZ_SYN_CRYPTO_CAL_t) - 8);
    WIZAES_EncDec(&callAes);

    printf("The AES (ECB) encrypted message is:\r\n");
    for (i = 0; i < AES_TEST_LEN; i++)
        printf("%02X", ausResult[i]);
    printf("\r\n");

    /* ECB 解密 */
    memset((uint8_t *)&callAes, 0, sizeof(callAes));
    callAes.pu8In      = ausResult;
    callAes.ui32InLen  = AES_TEST_LEN;
    callAes.pu8Out     = ausPlain;
    callAes.ui32OutLen = AES_TEST_LEN;
    callAes.pu8Key     = ausKey;
    callAes.ui32Key    = WIZ_AES_KEY_SIZE_128 | WIZ_AES_OP_MODE_ECB | WIZ_AES_OP_MODE_DECRYPT;
    callAes.ui32Ctrl   = WIZC_CalcBuffCrc((uint8_t *)&callAes, sizeof(WIZ_SYN_CRYPTO_CAL_t) - 8);
    WIZAES_EncDec(&callAes);

    printf("The AES (ECB) decrypted message is:\r\n");
    for (i = 0; i < AES_TEST_LEN; i++)
        printf("%02X", ausPlain[i]);
    printf("\r\n");
}  

ECB 模式中每个 128 位块独立加密,结构简单速度快。通过 ui32Key 字段选择密钥长度(128位)、工作模式(ECB)和操作类型(加密/解密)。ui32Ctrl 字段存放 CRC 校验值,确保结构体数据完整性。

如果你想自定义

  • 换采集通道 → 修改 ADC_CovChannel[] 数组和对应的 GPIO 引脚,如改为 ADC_Channel_0 对应 PA0
  • 改采样精度 → 修改 ADC_SampleTIME[],可选 1.5/7.5/13.5/28.5/41.5/55.5/71.5/239.5 周期,周期越长精度越高
  • 改为连续转换 → 将 ADC_ContinuousConvMode 设为 ENABLE,ADC 会自动连续转换,无需软件反复触发

步骤2:CBC 模式加解密

CBC 模式需要额外的初始化向量(IV),每个明文块在加密前与前一个密文块异或。在 ECB 基础上设置 pu8IV 字段并将模式改为 CBC 即可。

/* CBC 加密 */
    uint8_t ausIV[16] = {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,
        0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10};

    memset((uint8_t *)&callAes, 0, sizeof(callAes));
    callAes.pu8In      = ausPlain;
    callAes.u32InLen   = AES_TEST_LEN;
    callAes.pu8Out     = ausResult;
    callAes.u32OutLen  = AES_TEST_LEN;
    callAes.pu8IV      = ausIV;
    callAes.pu8Key     = ausKey;
    callAes.ulOpt      = WIZ_AES_OPT_BLK_CBC | WIZ_AES_OPT_MODE_ENCRYPT | WIZ_AES_OPT_KEY_128;
    callAes.u32Crc     = WIZCRC_CalcBuff(0xffff, &callAes, sizeof(WIZ_SYN_CRYPTO_CALL) - 4);
    WIZAES_EncDec(&callAes);

    printf("The AES (CBC) encrypted message is:\r\n");
    for (i = 0; i < AES_TEST_LEN; i++)
        printf("%02x", ausResult[i]);
    printf("\r\n");

    /* CBC 解密 */
    memset((uint8_t *)&callAes, 0, sizeof(callAes));
    callAes.pu8In      = ausResult;
    callAes.u32InLen   = AES_TEST_LEN;
    callAes.pu8Out     = ausPlain;
    callAes.u32OutLen  = AES_TEST_LEN;
    callAes.pu8IV      = ausIV;
    callAes.pu8Key     = ausKey;
    callAes.ulOpt      = WIZ_AES_OPT_BLK_CBC | WIZ_AES_OPT_MODE_DECRYPT | WIZ_AES_OPT_KEY_128;
    callAes.u32Crc     = WIZCRC_CalcBuff(0xffff, &callAes, sizeof(WIZ_SYN_CRYPTO_CALL) - 4);
    WIZAES_EncDec(&callAes);

    printf("The AES (CBC) decrypted message is:\r\n");
    for (i = 0; i < AES_TEST_LEN; i++)
        printf("%02x", ausPlain[i]);
    printf("\r\n");  

CBC 模式避免了相同明文块生成相同密文块的问题,安全性更高,是 TLS 通信中常用的模式。IV(初始化向量)用于第一个块的异或,后续块使用前一个密文块。

如果你想自定义

  • 换IV → 修改 ausIV[16] 数组和对应的 GPIO 引脚,如改为 ADC_Channel_0 对应 PA0
  • 切换ECB/CBC → 修改 ulOpt 中的 WIZ_AES_OPT_BLK_ECB / WIZ_AES_OPT_BLK_CBC

编译与下载

Keil MDK 中打开 AES.uvprojxF7 编译,确认 0 Error(s)。连接 DEBUG USB 口到 PC,F8 下载。下载成功后按 RESET 键启动新固件。

运行验证

打开 WIZ UartTool V1.0,选择开发板对应 COM 口,波特率 115200 / 8N1,打开串口。下载固件并按 RESET 后,串口会依次打印明文输入、密钥、ECB 加密结果、ECB 解密结果、CBC 加密结果、CBC 解密结果。

WIZ UartTool V1.0 显示 AES ECB/CBC 加密解密结果:明文、密文、解密后数据均为十六进制

常见问题

Q: 加密结果与 Python 等工具计算的结果不一致

确认密钥、IV、明文数据完全一致。注意 W55MH32L 使用 AES-128(16字节密钥),检查数据对齐和字节序。ECB 模式无需 IV,CBC 模式必须设置 IV。

Q: WIZAES_EncDec 调用后无输出

检查 callAes 结构体的 ui32Ctrl/ui32Crc 校验字段是否正确计算。该字段用于确保结构体数据完整性,校验不通过时硬件不会执行运算。

Q: 串口无任何输出

确认 COM 口号正确、波特率 115200,下载后需按 RESET 键启动。检查 printf 重定向的 fputc 函数是否正确实现。

总结

本文基于 W55MH32L 的硬件 AES-128 引擎实现了 ECB 和 CBC 两种模式的加密与解密:

  • ECB 模式每个 128 位块独立加密,简单快速,适合加密无结构的随机数据
  • CBC 模式 每个明文块与前一个密文块异或后再加密,安全性更高,适合 TLS 通信和固件保护
  • 通过 WIZ_SYN_CRYPTO_CAL_t 结构体配置密钥、IV、模式和操作类型,调用 WIZAES_EncDec()执行硬件加速运算
  • 硬件 AES 降低了 CPU 负担,具备恒定时延,适用于安全通信、固件加密、本地存储加密等场景

下载本章例程

我们提供完整的工程文件以及配套开发板,方便你随时测试,快速完成产品开发:

开发环境: Keil MDK5 配套开发板

Andy

W5500 技术支持专家