全部例程

硬件加密中实现DES/3DES功能

W55MH32 其他标签

2025/02/12 更新

WIZnet W55MH32 是一款集成硬件加密引擎的高性能微控制器,具备高达 216 MHz 的 ARM Cortex-M3 内核。其硬件加密引擎支持多种对称加密算法,包括 DES 和 3DES。通过硬件加速,W55MH32 可高效执行加密任务,显著减轻主 CPU 运算负担,提升系统数据安全性。本应用笔记介绍 DES 和 3DES 的基本概念、ECB/CBC 模式、两者的区别、操作流程、在 SSL/TLS 协议中的应用及适用场景。

DES/3DES简介


DES(数据加密标准)

DES 是一种对称加密算法,用于对数据以 64 位数据块为单位进行加密,每个块用 56 位密钥(64 位密钥中 8 位用于奇偶校验)处理。由于密钥长度较短,DES 在现代计算能力面前已不再安全,易受到暴力破解攻击。

3DES(三重 DES)

3DES 是对 DES 的安全增强版,通过对每个数据块执行三次 DES 运算(加密-解密-加密或三次加密),提升安全性。3DES 可使用 2 组或 3 组独立密钥,密钥长度分别是 112 位或 168 位。3DES 大大增加了穷举密钥空间的难度,使得暴力破解变得不可行。

DES 与 3DES 的主要区别

特性 DES 3DES
密钥长度 56 位有效密钥 112-位(2-密钥 3DES)或 168-位(3-密钥 3DES)
加密过程 单次 DES 加密 三次 DES 运算(加密-解密-加密)
安全性 易受暴力破解攻击 提供显著更高的安全性(但不如 AES)
速度 约为 DES 的 1/3 速度(因三重运算)
适用场景 已不推荐用于新应用,仅用于兼容性 金融、老旧系统兼容、对安全性要求较高的传统系统

    3DES 的设计初衷是作为一种过渡方案,用于在 AES 等现代算法普及前增强基于 DES 系统的安全性。

ECB 与 CBC 模式简介

    ECB(电子密码本模式)

    ECB 模式中,每个数据块独立加密。相同的明文块在相同密钥下会生成相同的密文块,因此容易暴露数据模式。优点是简单、支持并行运算,但因安全性不足不推荐用于敏感数据。

    CBC(密码块链接模式)

    CBC 模式中,每个明文块在加密前与前一个密文块(或第一个块与 IV)异或。这样即使明文中存在重复块,加密后密文也会不同,从而更安全。CBC 模式能防止模式泄露,但加密过程中块间存在依赖关系。

操作流程

  • 在 W55MH32 硬件引擎中,DES / 3DES 操作流程包括:

    1. 初始化加密引擎,选择模式(DES 或 3DES)、块模式(ECB 或 CBC)、配置密钥及 IV(若使用 CBC)。
    2. 分块输入数据,按 64 位(8 字节)处理。
    3. 输出加密或解密后的数据结果。

在 SSL/TLS 协议中的作用

    在早期 SSL/TLS(如 SSL 3.0, TLS 1.0, TLS 1.1)中,3DES 是主要的对称加密算法(特别是 CBC 模式)。

  • DES 已基本不用于 SSL/TLS(因不安全)。
  • 3DES + CBC 曾用于保护数据传输的机密性。
  • 现代TLS1.2/1.3已淘汰DES和3DES,转向更高强度算法(如 AES-GCM、ChaCha20-Poly1305)。

应用场景

W55MH32 的硬件 DES / 3DES 功能可应用于以下典型领域:

  • POS机/金融终端数据加密用于确保交易数据在终端与后台系统之间传输过程中的机密性,例如 POS 机或 ATM 设备中的数据加密。
  • 配置文件或固件加密保护 用于对设备配置文件、固件或授权文件进行加密,防止在传输或存储过程中被泄露或篡改。
  • 工控系统与老旧设备兼容适用于需要与传统工业控制设备或加密终端通信的应用场景,提供对称加密支持以实现数据安全。
  • 数据库或日志文件加密用于加密存储在本地的敏感数据、日志文件或配置数据,防止数据在设备丢失或被入侵时泄露。

使用步骤

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

步骤 1:头文件

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


#include "wiz_des.h"

步骤2:DES程序

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


// 将所有变量传入 CallDes 结构体
// pu8In – 输入数据
callDes.pu8In = au8Plain;
// u32InLen 表示输入数据的大小,单位为 64 字节
callDes.u32InLen = DES_TEST_LEN;
// au8Result – 输出数据
callDes.pu8Out = au8Result;
// u32OutLen 表示输出数据的大小,单位为 64 字节
callDes.u32OutLen = DES_TEST_LEN;
// u16Opt 表示使用 ECB 加密消息的方式
callDes.u16Opt = WIZ_DES_OPT_BLK_ECB | WIZ_DES_OPT_MODE_ENCRYPT;
// pu8Key 表示加密或解密消息的密钥
callDes.pu8Key = au8Key;
// 运行硬件 DES
WIZDES_EncDec(&callDes);
其他条件:
// pu8IV 是用于加密或解密消息的 IV
callDes.pu8IV = au8Iv;
// u16Opt 是使用 CBC 解密消息的方法选择
callDes.u16Opt = WIZ_DES_OPT_BLK_CBC | WIZ_DES_OPT_MODE_DECRYPT;
// u16Opt 是使用 3DES 加密消息的 CBC 方法选择
callTdes.u16Opt = WIZ_DES_OPT_BLK_ECB | WIZ_DES_OPT_MODE_ENCRYPT | WIZ_TDES_OPT_KEY_3;

步骤 3:主代码

在这个主代码中,包含了操作DES和3DES的方法

DES 的主代码


void DES_Func_Test()
{
    uint8_t i;
    uint8_t aucPlain[DES_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,
                                     0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40};
    uint8_t aucDESCipher_ECB[DES_TEST_LEN] = {0x77, 0x81, 0x0D, 0x0E, 0x22, 0x67, 0x82, 0x0A, 0x03, 0x7D, 0x05, 0x0F, 0x02, 0xAF, 0xA7,
                                             0x07, 0x01, 0x86, 0x8E, 0x8F, 0x75, 0x65, 0x8B, 0x8D, 0x8E, 0x8F, 0x86, 0x8F, 0x8A, 0x83,
                                             0x00, 0x3B, 0x07, 0x91, 0x0A, 0x56, 0x0A, 0x27, 0x00, 0xFB, 0x12, 0x0F, 0x2E, 0xFE, 0x0A, 0xC2};
    uint8_t aucDESCipher_CBC[DES_TEST_LEN] = {0x8B, 0x6D, 0x82, 0x0B, 0x8E, 0x0C, 0x07, 0xF0, 0x06, 0x3F, 0x1F, 0x05, 0x84, 0x0E, 0x0B, 0x91,
                                             0x01, 0x73, 0x0E, 0x81, 0x09, 0x87, 0x03, 0x8D, 0x83, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91,
                                             0x8B, 0x55, 0x85, 0x59, 0x8B, 0x5F, 0x8B, 0x41, 0x8E, 0xF1, 0x8F, 0x91, 0x8D, 0x65, 0x8C, 0x95,
                                             0x81, 0xF0, 0x8F, 0x2E, 0x0A, 0x56, 0x0F, 0x18, 0x90, 0x0B, 0x0B, 0x0C, 0x02, 0x85, 0x01, 0x05};
    uint8_t aucResult[DES_TEST_LEN] = {0};
    uint8_t aucKey[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
    WIZ_SYM_CRYPT_Call callDes;

    memset(&callDes, 0, sizeof(callDes));
    // ECB ENC
    printf("The DES (ECB) data input is \r\n");
    for (i = 0; i < DES_TEST_LEN; i++)
    {
        printf("%02x", aucPlain[i]);
    }
    printf("\r\n");
    printf("The DES key is \r\n");
    for (i = 0; i< 8; i++)
    {
        printf("%02x", aucKey[i]);
    }
    printf("\r\n");
    callDes.pu8In = aucPlain;
    callDes.u32InLen = DES_TEST_LEN;
    callDes.pu8Out = aucResult;
    callDes.pu8IV = NULL;
    callDes.u32Op = WIZ_DES_Opt_ECB | WIZ_DES_Opt_MODE_ENCRYPT;
    callDes.pu8Key = aucKey;
    callDes.u32Crc = WIZCRC_CalcBuff(0xffff, &callDes, sizeof(WIZ_SYM_CRYPT_Call) - 4);
    WIZDES_EncDec(&callDes);
    // if (0 == memcmp(aucDESCipher_ECB, aucResult, DES_TEST_LEN), "wiz_des_ecb test\n");
    printf("The DES ECB encrypted message is \r\n");
    for (i = 0; i < DES_TEST_LEN; i++)
    {
        printf("%02x", aucResult[i]);
    }
    printf("\r\n");
    printf(" \r\n");
    printf(" \r\n");

    // CBC DEC
    printf("The DES (CBC) data input is \r\n");
    for (i = 0; i <DES_TEST_LEN; i++)
    {
        printf("%02x", aucDESCipher_CBC[i]);
    }
    printf("\r\n");
    printf("The DES key is \r\n");
}

3DES 的主代码


void TDES_Func_Test()
{
    uint8_t i;
    uint8_t aucPlain[DES_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,
                                     0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40};
    uint8_t aucTDESCipher_ECB[DES_TEST_LEN] = {0x7D, 0x7B, 0x0D, 0x0C, 0xFA, 0x35, 0xB9, 0x49, 0x6A, 0xF8, 0xCE, 0x85, 0xAE, 0x3A, 0x35, 0x00,
                                              0xAC, 0xBD, 0x15, 0x53, 0xE0, 0xC4, 0x3C, 0x90, 0xF9, 0x5C, 0xE5, 0x47, 0xDE, 0xCB, 0x8F, 0x55,
                                              0x6A, 0x3A, 0x15, 0x6D, 0xE8, 0x05, 0x52, 0x8D, 0x16, 0x3A, 0x0E, 0x2B, 0x30, 0x24, 0x37, 0x4E,
                                              0x09, 0x2D, 0x46, 0x06, 0x3C, 0x61, 0x0E, 0xAA, 0x21, 0x5C, 0x0A, 0xFE, 0x3F, 0x42, 0xE8, 0xDD};
    uint8_t aucTDESCipher_CBC[DES_TEST_LEN] = {0xAD, 0x17, 0xA7, 0x56, 0x3A, 0x0F, 0xF8, 0xF3, 0x47, 0xB6, 0x3E, 0x78, 0x16, 0x72, 0xCD, 0xD7,
                                              0x6F, 0x52, 0x02, 0x8E, 0xDB, 0x00, 0x49, 0x39, 0x12, 0xD5, 0xB6, 0x8A, 0xD0, 0xCB, 0xDC, 0xC6,
                                              0xFD, 0x98, 0x82, 0x73, 0x18, 0x37, 0xCF, 0x9C, 0x68, 0x10, 0x2E, 0x94, 0x8D, 0x85, 0x2E, 0x09,
                                              0x81, 0x7F, 0x56, 0x70, 0x7E, 0x21, 0xCF, 0x1B, 0x2D, 0x66, 0xD7, 0xE8, 0x96, 0xCC, 0xAC, 0xD4};
    uint8_t aucResult[DES_TEST_LEN] = {0};
    uint8_t aucKey[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 aucIV[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
    WIZ_SYM_CRYPT_CALL callTdes;

    memset(&callTdes, 0, sizeof(callTdes));
    //ECB ENC
    printf("The 3DES (ECB) data input is \r\n");
    for (i = 0; i < DES_TEST_LEN; i++)
    {
        printf("%02x", aucPlain[i]);
    }
    printf("\r\n");
    printf("The 3DES key is \r\n");
    for (i = 0; i< 24; i++)
    {
        printf("%02x", aucKey[i]);
    }
    printf("\r\n");
    callTdes.pu8In = aucPlain;
    callTdes.u32InLen = DES_TEST_LEN;
    callTdes.pu8Out = aucResult;
    callTdes.u32OutLen = DES_TEST_LEN;
    callTdes.u32Op = WIZ_DES_Opt_ECB | WIZ_DES_Opt_MODE_ENCRYPT | WIZ_TDES_Opt_KEY_3;
    callTdes.pu8Key = aucKey;
    callTdes.u32Crc = WIZCRC_CalcBuff(0xffff, &callTdes, sizeof(WIZ_SYM_CRYPT_CALL) - 4);
    WIZTDES_EncDec(&callTdes);
    //if (0 == memcmp(aucTDESCipher_ECB, aucResult, DES_TEST_LEN), "wiz_tdes_ecb test\n");
    printf("The 3DES encrypted message is \r\n");
    for (i = 0; i < DES_TEST_LEN; i++)
    {
        printf("%02x", aucResult[i]);
    }
    printf("\r\n");
    printf(" \r\n");
    printf(" \r\n");

    //CBC DEC
    printf("The 3DES (CBC) data input is \r\n");
    for (i = 0; i < DES_TEST_LEN; i++)
    {
        printf("%02x", aucTDESCipher_CBC[i]);
    }
    printf("\r\n");
}

步骤 4:测试结果

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

DES(全部为十六进制值):

密钥和 AI 值:


0102030405060708

输入消息 (ECB):


0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40

加密输出消息(ECB):


77a7d6bcf57962b9a32d3d858fd3afa65751c8de226285aa687bc9effe26af37003ac7914a56da2760fb12df2efedac2b86d92ebeeec07f0c63fdf398a3e8b04

输入消息 (CBC):


b073dc3fb209536d93959f0724238e1825e2d1aba72baf3ee29ddecc3297bdeb51955658485f8741def4ec910d651c09c4f0fb2eda5bcf1890bb0b8c928501d5

解密输出消息(CBC):


0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40

3DES(全部为十六进制值):

AI 值:


0102030405060708

密钥值:


0102030405060708090a0b0c0d0e0f100102030405060708

输入消息 (ECB):


0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40

加密输出消息(ECB):


7d78d9c8fa35b9436af8ca58ab3a3500acbd1553e0c43c90f95ce597dec4bf58969a186de8059280163aec2b3024374e092d46063c61e9aa219ca8f63f42e4d2

输入消息(CBC):


0102030405060708

解密输出消息 (CBC):


0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40

Python 结果


from des import DesKey

keyDES = DesKey(bytes.fromhex("0102030405060708"))  # for DES
key3DES = DesKey(bytes.fromhex("0102030405060708090a0b0c0d0e0f100102030405060708"))  # for 3DES, same as "a key for TRIPLEa key fo"
ivDES = bytes.fromhex("0102030405060708")  # iv for DES and 3DES

input_text = bytes.fromhex("0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40")
des_cbc = bytes.fromhex("b073dc3fb209536d93959f0724238e1825e2d1aba72baf3ee29ddecc3297bdeb51955658485f8741def4ec910d651c09c4f0fb2eda5bcf1890bb0b8c928501d5")
tdes_cbc = bytes.fromhex("ad17a7563a0ff8f347b63e781672cdd76f52028edb00493912d5b68ad0cbdcc6fd9882731837cf9c68102e948d852e09817f56707e21cf1b2d66d7e896ccacd4")

# DES ECB Encrypt
print("DES ECB Encryption:")
print(bytes.hex(keyDES.encrypt(input_text)))

# DES CBC Decrypt
print("DES CBC Decryption:")
print(bytes.hex(keyDES.decrypt(des_cbc, initial=ivDES)))

# 3DES ECB Encrypt
print("3DES ECB Encryption:")
print(bytes.hex(key3DES.encrypt(input_text)))

# 3DES CBC Decrypt
print("3DES CBC Decryption:")
print(bytes.hex(key3DES.decrypt(tdes_cbc, initial=ivDES)))

结论

WIZnet W55MH32 所集成的硬件 DES / 3DES 引擎为嵌入式系统提供了一种高效、低功耗的对称加密方案,能够显著减轻主处理器的负担,同时提升数据的安全性和完整性。通过支持 ECB 和 CBC 两种模式,W55MH32 可满足不同场景下的数据加密需求,其中 ECB 适用于简单或非敏感数据的快速加密,而 CBC 则更适合防止模式泄露、增强安全性的应用。虽然 DES 由于密钥长度较短已逐步被淘汰,但 3DES 作为其加强版仍在一些金融、工控和对兼容性有严格要求的应用中发挥作用。然而,对于新设计,建议优先考虑更现代的算法(如 AES),以实现更高水平的安全防护。W55MH32 的硬件加密功能为嵌入式开发者提供了灵活而可靠的安全基础,可广泛应用于终端通信、固件保护和本地数据存储等场景。

下载本章例程

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

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