硬件加密中实现DES / 3DES功能
更新于 2026年9月11日
本篇总结
使用硬件加密引擎,实现 DES/3DES 的 ECB/CBC 模式加解密,串口打印测试通过结果。
硬件平台:本例程基于 W55MH32L-EVB 开发板运行。
采购推荐:点击前往 WIZnet 官方淘宝店铺 选购 W55MH32L-EVB
WIZnet W55MH32 集成硬件加密引擎,支持多种对称加密算法,包括 DES 和 3DES。通过硬件加速,W55MH32 可高效执行加密任务,显著减轻主 CPU 运算负担,提升系统数据安全性。本示例演示如何调用硬件引擎完成 DES / 3DES 的 ECB/CBC 模式加解密。
前置工具准备
开始本例程前,请确认以下工具已安装:
- WIZ UartTool V1.0:串口调试工具:点击下载
硬件连接
加密引擎为片内外设,无需额外连线。结果通过 USART1 串口打印,USART1 的 TX(PA9) 和 RX(PA10) 通过板载 USB 转串口芯片连接到 DEBUG USB 口。仅需一根 Micro USB 线连接开发板 DEBUG USB 口到 PC 即可。
| 引脚 | 功能 | 方向 | 模式 |
|---|---|---|---|
| PA9 | USART1_TX | 开发板 → PC | 复用推挽输出 (AF_PP) |
| PA10 | USART1_RX | PC → 开发板 | 浮空输入 (IN_FLOATING) |
工程结构
工程位于 SDK 内 1.SDK\ModuleDemo\ 下硬件加密例程目录,核心文件如下:
硬件加密例程/
├── USER/
│ ├── main.c ← 主流程:时钟/USART 初始化 + 调用 DES/3DES 测试
│ ├── debug.c/h ← DES_Func_Test() / TDES_Func_Test() 实现
│ ├── w55mh32_conf.h ← 外设头文件集中包含
│ ├── w55mh32_it.c/h ← 中断服务函数
│ ├── system_w55mh32.c/h← 系统初始化(时钟配置)
│ └── startup_w55mh32.s ← 启动文件
└── SYSTEM/
└── delay/
└── delay.c/h ← SysTick 延时函数
DES/3DES 简介
DES(数据加密标准)是一种对称加密算法,以 64 位数据块为单位加密,每个块用 56 位有效密钥(64 位中 8 位为奇偶校验)处理。由于密钥较短,DES 已易受暴力破解,不再推荐用于新应用。
3DES(三重 DES)对每个数据块执行三次 DES 运算(加密-解密-加密),可使用 2 组(112 位)或 3 组(168 位)独立密钥,安全性显著提升,约为 DES 速度的 1/3。
| 特性 | DES | 3DES |
|---|---|---|
| 密钥长度 | 56 位有效 | 112 位(2 密钥)/ 168 位(3 密钥) |
| 加密过程 | 单次 DES | 三次 DES 运算(加密-解密-加密) |
| 安全性 | 易受暴力破解 | 显著更高(但不如 AES) |
| 速度 | 快 | 约为 DES 的 1/3 |
| 适用场景 | 仅兼容性 | 金融、老旧系统兼容 |
ECB(电子密码本)模式中每个数据块独立加密,相同明文块生成相同密文块,易暴露数据模式,简单且支持并行,不推荐用于敏感数据。
CBC(密码块链接)模式中每个明文块加密前先与前一个密文块(首块与 IV)异或,即使明文重复密文也不同,更安全,但块间存在依赖。
操作流程
初始化加密引擎 → 选择算法(DES/3DES)与块模式(ECB/CBC)→ 配置密钥及 IV(CBC 需要)→ 按 64 位(8 字节)分块输入数据 → 引擎输出加/解密结果。
步骤1:包含头文件
为激活 DES 功能,需包含 WIZnet 加密库中的 DES 头文件及相关依赖。
#include "debug.h"
#include "w55mh32.h"
#include "wiz_des.h"
#include "wiz_rand.h"
#include <stdio.h>
#include <string.h>步骤2:配置加密结构体
将所有参数填入 WIZ_SYM_CRYPT_CALL 结构体后调用引擎执行。ECB 与 CBC 操作相同,CBC 仅需额外传入 IV。
/* 将所有变量传入 callDes 结构体 */
callDes.pu8In = au8Plain; // 输入数据
callDes.u32InLen = DES_TEST_LEN; // 输入长度(8 字节倍数)
callDes.pu8Out = au8Result; // 输出数据
callDes.u32OutLen = DES_TEST_LEN; // 输出长度
callDes.u16Opt = WIZ_DES_OPT_BLK_ECB | WIZ_DES_OPT_MODE_ENCRYPT; // ECB 加密
callDes.pu8Key = au8Key; // 密钥
callDes.u32Crc = WIZCRC_CalcBuff(0xffff, &callDes, sizeof(WIZ_SYM_CRYPT_CALL) - 4);
WIZDES_EncDec(&callDes); // 运行硬件 DES
/* CBC 解密需额外配置 IV */
callDes.pu8IV = au8Iv;
callDes.u16Opt = WIZ_DES_OPT_BLK_CBC | WIZ_DES_OPT_MODE_DECRYPT;
/* 3DES 加密(ECB,3 组密钥)*/
callTdes.u16Opt = WIZ_DES_OPT_BLK_ECB | WIZ_DES_OPT_MODE_ENCRYPT | WIZ_TDES_OPT_KEY_3;如果你想自定义
- 切换 ECB / CBC → 修改
u16Opt的块模式位:WIZ_DES_OPT_BLK_ECB或WIZ_DES_OPT_BLK_CBC - 切换加密 / 解密 → 修改模式位:
WIZ_DES_OPT_MODE_ENCRYPT或WIZ_DES_OPT_MODE_DECRYPT - 3DES 密钥组数 → 通过
WIZ_TDES_OPT_KEY_3选择 3 组密钥(24 字节)
步骤3:DES 加解密主代码
文件:USER/debug.c | 函数:DES_Func_Test() — 演示 DES 的 ECB 加密与 CBC 解密:ECB 加密后用预设密文比对,CBC 解密后用原文比对,通过 r_printf() 打印测试结果。
#define DES_TEST_LEN (64)
void DES_Func_Test()
{
uint8_t au8Plain[DES_TEST_LEN] = {0x01, 0x02, ..., 0x40};
uint8_t au8DESCipher_ECB[DES_TEST_LEN] = {0x77, 0xA7, ..., 0x04};
uint8_t au8DESCipher_CBC[DES_TEST_LEN] = {0xB0, 0x73, ..., 0xD5};
uint8_t au8Result[DES_TEST_LEN] = {0};
uint8_t au8Iv[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
uint8_t au8Key[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
WIZ_SYM_CRYPT_CALL callDes;
memset(&callDes, 0, sizeof(callDes));
// ECB ENC
callDes.pu8In = au8Plain;
callDes.u32InLen = DES_TEST_LEN;
callDes.pu8Out = au8Result;
callDes.u32OutLen= DES_TEST_LEN;
callDes.u16Opt = WIZ_DES_OPT_BLK_ECB | WIZ_DES_OPT_MODE_ENCRYPT;
callDes.pu8Key = au8Key;
callDes.u32Crc = WIZCRC_CalcBuff(0xffff, &callDes, sizeof(WIZ_SYM_CRYPT_CALL) - 4);
WIZDES_EncDec(&callDes);
r_printf((0 == memcmp(au8DESCipher_ECB, au8Result, DES_TEST_LEN)), "wiz_des_ecb test\n");
// CBC DEC
callDes.pu8In = au8DESCipher_CBC;
callDes.u32InLen = DES_TEST_LEN;
callDes.pu8Out = au8Result;
callDes.u32OutLen= DES_TEST_LEN;
callDes.pu8IV = au8Iv;
callDes.u16Opt = WIZ_DES_OPT_BLK_CBC | WIZ_DES_OPT_MODE_DECRYPT;
callDes.pu8Key = au8Key;
callDes.u32Crc = WIZCRC_CalcBuff(0xffff, &callDes, sizeof(WIZ_SYM_CRYPT_CALL) - 4);
WIZDES_EncDec(&callDes);
r_printf((0 == memcmp(au8Plain, au8Result, DES_TEST_LEN)), "wiz_des_cbc test\n");
}
void DES_Test() { DES_Func_Test(); }
关键点:u32Crc 字段需用 WIZCRC_CalcBuff() 对结构体(除最后 4 字节 CRC 自身)计算,引擎据此校验配置完整性,缺失会导致执行失败。
步骤4:3DES 加解密主代码
文件:USER/debug.c | 函数:TDES_Func_Test() — 与 DES 流程一致,区别在于密钥 24 字节(3 组)、选项加 WIZ_TDES_OPT_KEY_3、调用 WIZTDES_EncDec()。
void TDES_Func_Test()
{
uint8_t au8Plain[DES_TEST_LEN] = {0x01, 0x02, ..., 0x40};
uint8_t au8TDESCipher_ECB[DES_TEST_LEN] = {0x7D, 0x78, ..., 0xD2};
uint8_t au8TDESCipher_CBC[DES_TEST_LEN] = {0xAD, 0x17, ..., 0xD4};
uint8_t au8Result[DES_TEST_LEN] = {0};
uint8_t au8Key[24] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x09, 0x0A, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
uint8_t au8Iv[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
WIZ_SYM_CRYPT_CALL callTdes;
memset(&callTdes, 0, sizeof(callTdes));
// ECB ENC
callTdes.pu8In = au8Plain;
callTdes.u32InLen = DES_TEST_LEN;
callTdes.pu8Out = au8Result;
callTdes.u32OutLen= DES_TEST_LEN;
callTdes.u16Opt = WIZ_DES_OPT_BLK_ECB | WIZ_DES_OPT_MODE_ENCRYPT | WIZ_TDES_OPT_KEY_3;
callTdes.pu8Key = au8Key;
callTdes.u32Crc = WIZCRC_CalcBuff(0xffff, &callTdes, sizeof(WIZ_SYM_CRYPT_CALL) - 4);
WIZTDES_EncDec(&callTdes);
r_printf((0 == memcmp(au8TDESCipher_ECB, au8Result, DES_TEST_LEN)), "wiz_tdes_ecb test\n");
// CBC DEC
callTdes.pu8In = au8TDESCipher_CBC;
callTdes.u32InLen = DES_TEST_LEN;
callTdes.pu8Out = au8Result;
callTdes.u32OutLen= DES_TEST_LEN;
callTdes.pu8IV = au8Iv;
callTdes.u16Opt = WIZ_DES_OPT_BLK_CBC | WIZ_DES_OPT_MODE_DECRYPT | WIZ_TDES_OPT_KEY_3;
callTdes.pu8Key = au8Key;
callTdes.u32Crc = WIZCRC_CalcBuff(0xffff, &callTdes, sizeof(WIZ_SYM_CRYPT_CALL) - 4);
WIZTDES_EncDec(&callTdes);
r_printf((0 == memcmp(au8Plain, au8Result, DES_TEST_LEN)), "wiz_tdes_cbc test\n");
}
void TDES_Test() { TDES_Func_Test(); }步骤5:主函数调用
文件:USER/main.c | 函数:main() — 配置系统时钟 72MHz、初始化 USART1、打印加密库版本,然后依次调用 DES_Test() 与 TDES_Test() 执行测试。
void main(int args)
{
uint32_t ver = 1;
RCC_ClocksTypeDef clocks;
RCC_DeInit();
RCC_HSEConfig(RCC_HSE_ON);
RCC_WaitForHSEStartUp();
RCC_PLLCmd(DISABLE);
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); // 8MHz × 9 = 72MHz
RCC_PLLCmd(ENABLE);
while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
RCC_HCLKConfig(RCC_SYSCLK_Div1);
RCC_PCLK1Config(RCC_HCLK_Div2);
RCC_PCLK2Config(RCC_HCLK_Div1);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
SysTick->CTRL |= 0x04;
/* 使能加密引擎时钟/配置寄存器 */
*(uint32_t *)(0x400210F0) = 0x01;
*(uint32_t *)(0x40016C00) = 0xCDED3526;
*(uint32_t *)(0x40016CCC) = 0x07;
UART_Configuration(115200);
WIZRAND_Init((uint32_t *)&u8RngBuff, sizeof(u8RngBuff));
ver = wiz_crypt_version();
DBG_PRINT("WIZnet CARD Secure Test Demo V1.0, secure lib version is V%02x.%02x.%02x.%02x\n",
ver >> 24, (ver >> 16) & 0xFF, (ver >> 8) & 0xFF, ver & 0xFF);
DBG_PRINT("WIZnet CARD Crypt Test V1.0 start......\r\n");
DES_Test();
TDES_Test();
// AES_Test();
// SHA_Test();
// SM1_Test();
// SM3_Test();
// SM4_Test();
// SM7_Test();
DBG_PRINT("DES/3DES test finished, program halted.\r\n");
while (1) {}
}
注意:调用加密引擎前必须执行那三行寄存器写入(0x400210F0、0x40016C00、0x40016CCC),这是 W55MH32 加密引擎的时钟与配置寄存器初始化,缺失会导致加密结果全 0。
运行验证
打开 WIZ UartTool V1.0,选择开发板对应 COM 口,波特率 115200 / 8N1,打开串口。程序运行后串口依次打印库版本、测试开始,以及四项测试的通过结果。预期输出如下:
WIZnet CARD Secure Test Demo V1.0, secure lib version is V03.01.04.00
WIZnet CARD Crypt Test V1.0 start......
Pass wiz_des_ecb test
Pass wiz_des_cbc test
Pass wiz_tdes_ecb test
Pass wiz_tdes_cbc test
DES/3DES test finished, program halted.
四项测试全部通过(Pass)表示硬件加密引擎计算的密文/明文与预设测试向量完全一致,DES 与 3DES 的 ECB/CBC 模式加解密功能正常。
常见问题
Q: 编译报错 "cannot open source file wiz_des.h"
检查 Project → Options → C/C++ → Include Paths,确保 WIZnet 加密库的头文件目录已添加。
Q: 加密结果全 0 或测试不通过(Fail)
检查两点:① 加密引擎初始化那三行寄存器写入是否执行(0x400210F0 / 0x40016C00 / 0x40016CCC);② u32Crc 字段是否用 WIZCRC_CalcBuff(0xffff, &callDes, sizeof(...) - 4) 正确计算。
Q: CBC 模式解密结果与原文不符
CBC 链式依赖 IV,解密时 pu8IV 必须与加密时完全一致;且首块需先与前一块密文异或。确认 IV 未被改动。
Q: 数据长度非 8 字节倍数时异常
DES/3DES 按 64 位(8 字节)块处理,输入长度必须是 8 的整数倍。本示例用 DES_TEST_LEN = 64,正好是 8 的整数倍。
Q: 3DES 密钥长度报错
3 密钥模式(WIZ_TDES_OPT_KEY_3)需 24 字节密钥;2 密钥模式为 16 字节。确认 pu8Key 缓冲区长度与选项匹配。
总结
本文基于 W55MH32 硬件加密引擎实现了 DES / 3DES 的加解密:
- 硬件加速:DES/3DES 运算由片内引擎完成,主 CPU 零参与,显著减轻运算负担
- 双模式支持:ECB 简单适合非敏感数据,CBC 链式更安全;通过
u16Opt选项位切换 - 结构体配置:输入/输出/密钥/IV/模式集中填入
WIZ_SYM_CRYPT_CALL,配合 CRC 校验后一次调用引擎 - 选型建议:DES 已不安全,3DES 用于兼容场景,新设计优先选 AES(W55MH32 同样支持硬件 AES)