全部例程

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

W55MH32 其他标签

2025/02/12 更新

WIZnet 的 W55MH32 是一款高性能微控制器,内建 ARM Cortex-M3 内核,并集成了硬件加密引擎。其支持的对称加密算法之一是 AES(高级加密标准),被广泛应用于现代嵌入式系统中的数据安全保护。本应用笔记介绍了 AES 算法的结构、W55MH32 中的工作流程、支持的工作模式(ECB 和 CBC),以及在 SSL/TLS 协议中的重要性和常见应用场景。

AES 算法概述


什么是 AES?

AES 是一种对称块加密算法,由 NIST 在 FIPS PUB 197 标准中发布。它以 128 位(16 字节)块 为单位进行加密,支持的密钥长度为 128、192 或 256 位。W55MH32 内建 AES-128(128 位密钥) 的硬件加密模块,支持 ECB(电子密码本) 和 CBC(密码块链接) 两种模式。

AES 的加密结构

    AES 的运算基于一个 4×4 字节的状态矩阵。加密过程包括多个轮次,每轮主要由以下四个步骤组成:

  • 1. SubBytes(字节替换):通过固定的 S-Box 进行非线性替换。
  • 2. ShiftRows(行移位): 对状态矩阵中的每行进行循环移位。
  • 3. MixColumns(列混合): 在有限域上对每列执行矩阵乘法,实现扩散效果。
  • 4. AddRoundKey(轮密钥异或):状态矩阵与当前轮的密钥进行异或操作。
  • AES-128 总共执行 10 轮 加密;解密过程则为上述步骤的逆运算。

W55MH32 支持的 AES 加密模式

    ECB(电子密码本模式)
  • 每个 128-位块独立加密。
  • 简单、速度快、易于并行处理。
  • 缺点:相同的明文块生成相同的密文块,容易暴露数据结构。
  • 应用场景:适用于加密无结构或随机数据的情况。
  • CBC(密码块链接模式)
  • 每个明文块在加密前与前一个密文块进行异或。
  • 第一个块使用 初始化向量(IV)。
  • 优点:避免相同明文生成相同密文,提升安全性。
  • 应用场景:适合常规数据保护,TLS 通信,固件存储等。

AES 在 W55MH32 中的工作流程

    加密/解密步骤:

    W55MH32 的 AES 引擎可通过寄存器或 DMA 实现高速数据加解密,其典型使用流程如下:

    1. 参数初始化:
    • →设置AES模式(ECB/CBC)。
    • →加载128位密钥。
    • →设置初始化向量(CBC 模式下)。

    2. 加载输入数据:
    • →将16字节的明文写入AES硬件引擎

    3. 触发加解密操作:
    • →启动 AES 引擎进行运算

    4. 读取输出数据:
    • →获取加密或解密后的 16 字节结果。

硬件加速优势:

  • 降低 CPU 运算负担,提升系统性能。
  • 具备恒定时延,增强抗侧信道攻击能力。
  • 高速且节能,适用于低功耗嵌入式设备。

AES 在 SSL/TLS 协议中的重要性

在 SSL/TLS 等安全协议中,AES 是数据加密的核心算法之一:

  • 在 TLS 握手阶段:
    • 客户端与服务器通过非对称加密(如 RSA、ECDHE)协商共享密钥。
    • 握手完成后,使用 AES 对称加密算法 对数据传输进行加密保护。
  • AES 常用于以下 TLS 模式中:
    • CBC 模式(TLS 1.0~1.2 常见)
    • GCM 模式(TLS 1.2+ 的认证加密方案)
    为什么 AES 对 TLS 至关重要:
  • 提供高速、低延迟的数据加密能力。
  • 与 HMAC 搭配可实现完整性保护。
  • 已被所有现代网络通信协议广泛支持。

在嵌入式系统中,W55MH32 提供的硬件 AES-CBC 能高效支持 TLS 协议的负载加密部分,适用于嵌入式服务器、物联网安全通信等场景。

W55MH32 AES 的应用场景

W55MH32 的 AES 加密引擎可广泛应用于以下典型场合:

  • 固件加密与升级验证对固件镜像进行加密,防止被非法修改或复制。
  • 安全通信(TLS/SSL) 支持硬件加速的 AES-CBC 用于 HTTPS、MQTT 等安全通信。
  • 本地存储加密 对日志、配置文件、凭据等数据进行加密存储。
  • 加密串口/无线数据传输 使用 AES-CBC 对串口、SPI 或无线模块之间的数据进行保护。
  • 认证与访问控制基于 AES 实现设备身份验证或授权令牌加密机制。
  • 进度

    要使用此硬件 AES,需要执行以下步骤。

    步骤 1:头文件

    要激活 AES 功能,需要包含 WIZnet 加密库中的 AES 头文件。

    
    include "wiz_aes.h"

    步骤 2:AES 程序

    在 AES 程序中,需要将所有变量输入到 AES 结构体中并进行 AES 运算。EBC 和 CBC 方法的操作相同,但 CBC 方法需要添加一个额外的 IV 变量。

    
    // 将所有变量输入到 CallDes 结构体中
    // pu8In – 输入数据
    callAes.pu8In = au8Plain;
    // u32InLen 表示输入数据的大小(64 字节)
    callAes.u32InLen = AES_TEST_LEN;
    // au8Result – 输出数据
    callAes.pu8Out = au8Result;
    // u32OutLen 表示输出数据的大小(64 字节)
    callDes.u32OutLen = DES_TEST_LEN;
    // u16Opt 是使用 ECB 加密消息的方法选择
    callAes.u16Opt = WIZ_AES_OPT_BLK_ECB | WIZ_AES_OPT_MODE_ENCRYPT | WIZ_AES_OPT_KEY_128;
    //或者您可以将其更改为解密消息
    callAes.u16Opt = WIZ_AES_OPT_BLK_ECB | WIZ_AES_OPT_MODE_DECRYPT | WIZ_AES_OPT_KEY_128;
    // pu8Key 是用于加密或解密消息的密钥
    callAes.pu8Key = au8Key;
    // 运行硬件 AES
    WIZDES_EncDec(&callAes);
    其他情况:
    // pu8IV 是用于加密或解密消息的 IV
    callAes.pu8IV = au8Iv;
    // u16Opt 是使用 CBC 加密消息的方法的选择
    callAes.u16Opt = WIZ_AES_OPT_BLK_CBC | WIZ_AES_OPT_MODE_ENCRYPT | WIZ_AES_OPT_KEY_128;
    // 或者您可以将其更改为解密消息
    callAes.u16Opt = WIZ_AES_OPT_BLK_CBC | WIZ_AES_OPT_MODE_DECRYPT | WIZ_AES_OPT_KEY_128;

    步骤 3:主代码

    此主代码包含在两种情况下操作 AES 的方法

    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 ausAESCipher_ECB[AES_TEST_LEN] = {0x31, 0x0E, 0x06, 0x66, 0x72, 0x5B, 0x3B, 0x36, 0x60, 0x14, 0x05, 0x04, 0x52, 0xFA, 0x64, 0x5A,
                                                  0x03, 0x62, 0xB6, 0x5C, 0x75, 0x78, 0xCA, 0x5A, 0xAA, 0x9E, 0x5D, 0x70, 0x29, 0x31, 0x2E, 0x43,
                                                  0x07, 0x02, 0x0A, 0x0E, 0x75, 0x2A, 0x47, 0x22, 0xB9, 0xF0, 0x2A, 0x06, 0x03, 0x2E, 0xA0, 0x59};
        uint8_t ausAESCipher_CBC[AES_TEST_LEN] = {0x65, 0x05, 0x00, 0x0A, 0x0E, 0x15, 0x04, 0x07, 0x0B, 0x55, 0x27, 0x07, 0x0A, 0x02, 0x00, 0x2A,
                                                  0x0A, 0x05, 0x07, 0x01, 0x0C, 0x1A, 0x15, 0x01, 0x20, 0x01, 0x27, 0x07, 0x01, 0x12, 0x0D, 0x0E,
                                                  0x0E, 0x02, 0x0B, 0x0A, 0x05, 0x2A, 0x01, 0x02, 0x03, 0x04, 0x2A, 0x06, 0x03, 0x2E, 0xA0, 0x59};
        uint8_t ausResult[AES_TEST_LEN]    = {0};
        uint8_t ausPR[AES_TEST_LEN]        = {0};
        uint8_t ausIV[16] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10};
        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");
        printf("The AES key is :\r\n");
        for (i = 0; i < 16; i++)
        {
            printf("%02X", ausKey[i]);
        }
        printf("\r\n");
        printf("The AES IV is :\r\n");
        for (i = 0; i < 16; i++)
        {
            printf("%02X", ausIV[i]);
        }
        printf("\r\n");
        memset((uint8_t *)&callAes, 0, sizeof(callAes));
        //ECB ENC
        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");
        //_tprintf((0 == memcmp(ausAESCipher_ECB, ausResult, AES_TEST_LEN)), "wiz_aes_128_ecb_ENC test\r\n");
    
        memset((uint8_t *)&callAes, 0, sizeof(callAes));
        //ECB DEC
        callAes.pu8In      = ausResult;
        callAes.ui32InLen  = AES_TEST_LEN;
        callAes.pu8Out     = ausPR;
        callAes.ui32OutLen = AES_TEST_LEN;
    }

    CBC 的主代码

    
    memset((uint8_t *)&callAes, 0, sizeof(callAes));
    //CBC ENC
    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");
    //_tprintf((0 == memcmp(ausAESCipher_CBC, ausResult, AES_TEST_LEN)), "wiz_aes_128_cbc ENC test\n");
    
    memset((uint8_t *)&callAes, 0, sizeof(callAes));
    //CBC DEC
    callAes.pu8In      = ausAESCipher_CBC;
    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_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", ausPR[i]);
    }
    printf("\r\n");
    //_tprintf((0 == memcmp(ausPlain, ausResult, AES_TEST_LEN)), "wiz_aes_128_cbc DEC test\n");
    
    void AES_Test()
    {
        AES_Func_Test();
    }

    步骤 4:测试结果

    程序下载到 W55MH32 的 EVB 后,显示以下结果。

    AES(全部十六进制值):

    密钥和 AI 值:

    
    0102030405060708090a0b0c0d0e0f10

    输入消息 :

    
    0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40

    加密输出消息 (ECB):

    
    34c33b7f14fd53dcea25e01a02e16727d721a0f194231822f398706dd1fff2b70328d32575fa476f38f624d673eaa09ba9050c10ce1904e750597797a172b0f0

    解密输出消息 (ECB):

    
    0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40

    加密输出消息 (CBC):

    
    dbf184112eb9111659712bafcff2ab24f72d2c50445d1d3bebf8b50d323288b4f628d8a653b220e27937bb4149cdd3646778adad93b9811d4fb505b9f424efb9

    解密输出消息 (CBC):

    
    0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40

    Python 结果

    
    from Crypto.Cipher import AES
    
    # Key and IV (both 16 bytes)
    key = bytes.fromhex("0102030405060708090a0b0c0d0e0f10")
    iv = bytes.fromhex("0102030405060708090a0b0c0d0e0f10")
    
    # Data to encrypt (64 bytes = 4 blocks of 16 bytes)
    data = bytes.fromhex(
        "0102030405060708090a0b0c0d0e0f10"
        "1112131415161718191a1b1c1d1e1f20"
        "2122232425262728292a2b2c2d2e2f30"
        "3132333435363738393a3b3c3d3e3f40"
    )
    cipher = AES.new(key, AES.MODE_ECB)
    
    # Encrypt (no padding needed)
    ciphertext = cipher.encrypt(data)
    
    # Decrypt
    plaintext = cipher.decrypt(ciphertext)
    
    # Output
    print("AES ECB Encrypted:", ciphertext.hex())
    print("AES ECB Decrypted:", plaintext.hex())
    
    # Encrypt using CBC (no padding)
    cipher_enc = AES.new(key, AES.MODE_CBC, iv)
    ciphertext = cipher_enc.encrypt(data)
    
    # Decrypt using CBC (no padding)
    cipher_dec = AES.new(key, AES.MODE_CBC, iv)
    decrypted = cipher_dec.decrypt(ciphertext)
    
    # Output
    print("AES CBC Encrypted:", ciphertext.hex())
    print("AES CBC Decrypted:", decrypted.hex())

    结论

    WIZnet 的 W55MH32 通过硬件实现的 AES-128 加密引擎,支持 ECB 和 CBC 两种模式,为嵌入式设备提供了快速、安全的数据加解密能力。通过减少 CPU 占用和降低能耗,W55MH32 特别适用于安全通信、数据保护和身份验证等嵌入式安全场景。在 SSL/TLS 等关键安全协议中,AES 是保证数据保密性和完整性的核心算法。W55MH32 强大的硬件加密能力,为物联网与工业控制等安全敏感型应用提供了坚实的保障基础。

    接下来的文章将重点介绍在 W55MH32 芯片上使用硬件加密中实现 DES / 3DES 功能,ECB/CBC 模式、两者的区别、操作流程、在 SSL/TLS 协议中的应用及适用场景,敬请期待!

    下载本章例程

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

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