AES(ECB/CBC)硬件加密功能
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 的加密结构
- 1. SubBytes(字节替换):通过固定的 S-Box 进行非线性替换。
- 2. ShiftRows(行移位): 对状态矩阵中的每行进行循环移位。
- 3. MixColumns(列混合): 在有限域上对每列执行矩阵乘法,实现扩散效果。
- 4. AddRoundKey(轮密钥异或):状态矩阵与当前轮的密钥进行异或操作。
AES 的运算基于一个 4×4 字节的状态矩阵。加密过程包括多个轮次,每轮主要由以下四个步骤组成:
AES-128 总共执行 10 轮 加密;解密过程则为上述步骤的逆运算。
W55MH32 支持的 AES 加密模式
-
ECB(电子密码本模式)
- 每个 128-位块独立加密。
- 简单、速度快、易于并行处理。
- 缺点:相同的明文块生成相同的密文块,容易暴露数据结构。
- 应用场景:适用于加密无结构或随机数据的情况。 CBC(密码块链接模式)
- 每个明文块在加密前与前一个密文块进行异或。
- 第一个块使用 初始化向量(IV)。
- 优点:避免相同明文生成相同密文,提升安全性。
- 应用场景:适合常规数据保护,TLS 通信,固件存储等。
AES 在 W55MH32 中的工作流程
- →设置AES模式(ECB/CBC)。
- →加载128位密钥。
- →设置初始化向量(CBC 模式下)。
- →将16字节的明文写入AES硬件引擎
- →启动 AES 引擎进行运算
- →获取加密或解密后的 16 字节结果。
加密/解密步骤:
W55MH32 的 AES 引擎可通过寄存器或 DMA 实现高速数据加解密,其典型使用流程如下:
1. 参数初始化:2. 加载输入数据:
3. 触发加解密操作:
4. 读取输出数据:
硬件加速优势:
- 降低 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 加密引擎可广泛应用于以下典型场合:
进度
要使用此硬件 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 协议中的应用及适用场景,敬请期待!