全部例程

WIZnet W55MH32 的 TLS 硬件加密功能说明

W55MH32

更新于 2026年9月23日

本篇总结

W55MH32 基于 DES、AES、SHA 硬件加密引擎和 TRNG,通过 SDK 移植的 mbedTLS 库实现 TLS 1.2 安全通信,演示通过 HTTPS 获取百度网页内容。

🔑 KEIL MDK、UART调试、硬件TOE引擎、TLS、AES、SHA、TRNG、DHCP

硬件平台:本例程基于 W55MH32L-EVB 开发板运行。

采购推荐:点击前往 WIZnet 官方淘宝店铺 选购 W55MH32L-EVB

本示例演示 W55MH32 利用内置 AES、SHA、TRNG 硬件加密模块配合 MbedTLS 库实现 TLS 1.2 安全通信,通过 HTTPS 访问百度网站验证加密数据传输功能。

前置工具准备

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

  • WIZ UartTool V1.0:串口调试工具:点击下载
  • Wireshark:网络抓包分析工具,用于 TLS 握手报文分析:点击下载

W55MH32 硬件加密简介

W55MH32 是一款由 WIZnet 设计的增强型 32 位微控制器,拥有 216MHz 处理器核心、1024KB Flash 和 96KB SRAM,内置 DES、AES、SHA 硬件加密算法单元和真随机数发生器(TRNG),可卸载加密计算任务,配合硬连线 TCP/IP 协议栈为 TLS 1.2 安全通信提供硬件加速。

  • TLS 握手四阶段:Client Hello(TRNG 随机数 + 密码套件)→ Server Hello(证书 + DH 公钥)→ 密钥交换(SHA 验证证书)→ ChangeCipherSpec + Finished
  • 硬件分工:TRNG 生成随机数与密钥,SHA 验证证书签名与计算 MAC,AES 加解密应用数据
  • 安全三要素:数据加密保障机密性、消息认证码(MAC)保障完整性、数字证书和签名保障真实性

硬件模块分工

AES 硬件负责对称加密/解密应用数据;SHA 硬件负责证书签名验证和消息认证码计算;TRNG 负责生成真随机数(Client/Server 随机数、预主密钥);TOE 引擎提供底层硬连线 TCP/IP 协议栈支撑。

硬件连接与拓扑

请注意:

测试需要 PC 端和 W55MH32 处于同一网段,且需能访问互联网。

  1. Micro USB 线连接 DEBUG USB 口到 PC(供电 + 调试串口)
  2. 网线连接开发板 RJ45 网口 到路由器 LAN 口
┌─────────────────────────────────┐
│ 路由器(DHCP Server) │
│ 192.168.1.1 │
└────┬──────────────────┬───────────┘
│ │
┌────┴──────┐ ┌────┴──────┐
│ W55MH32 │ │ PC │
│ TLS Client│ │ 百度HTTPS │
│ IP: DHCP │ │ IP: DHCP │
└───────────┘ └───────────┘
↑ ↑
DEBUG USB ──→ WIZ UartTool
网络拓扑:开发板通过路由器接入互联网,作为 TLS 客户端访问百度 HTTPS 服务器

工程结构

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

TLS/
├── Project/
│   └── Project.uvprojx       ← Keil 工程文件
└── USER/
    ├── main.c                ← 网络初始化 + TLS 连接 + HTTPS 请求
    └── wiz_tls.c/h           ← TLS 封装函数(wiz_tls_init/connect/read/write)

步骤1:硬件与网络设置

文件:USER/main.c — 初始化 W55MH32 的以太网 MAC 和 PHY 建立物理连接,配置硬件 TCP/IP 协议栈进行网络通信。

/* network information */
wiz_NetInfo default_net_info = {
    .mac  = {0x00, 0x08, 0xdc, 0x12, 0x22, 0x12},
    .ip   = {10, 0, 1, 140},
    .gw   = {10, 0, 1, 254},
    .sn   = {255, 255, 255, 0},
    .dns  = {8, 8, 8, 8},
    .dhcp = NETINFO_DHCP
};

定义三个变量:ethernet_buf 作为网络数据收发缓冲区,ssl_target_ip 指定百度服务器的目标 IP 地址,tlsContext 用于维护 TLS 连接的所有状态和配置信息。

uint8_t ethernet_buf[ETHERNET_BUF_MAX_SIZE] = {0};
uint8_t ssl_target_ip[4] = {220, 181, 111, 1}; /* baidu */
wiz_tls_context tlsContext;

初始化硬件、加密模块、TRNG、定时器,初始化 wiztoe 并检查 PHY 链接,最后初始化网络。

/* hardware initialization */
rcc_clk_config();
delay_init();
console_usart_init(115200);

printf("W55MH32 TLS Example\r\n");

/* hardware crypt initialization */
*(uint32_t *)(0x400210F0) = 0x01;
*(uint32_t *)(0x40016C00) = 0xCDED3526;
*(uint32_t *)(0x40016CCC) = 0x07;

/* hardware TRNG enable */
TRNG_Out(ENABLE);

tim3_init();

/* wiztoe init */
wiz_toe_init();
getSHAR(default_net_info.mac);
wiz_phy_link_check();

network_init(ethernet_buf, &default_net_info);

硬件加密初始化

0x400210F0 = 0x01 开启加密模块时钟,0x40016C00 = 0xCDED3526 解锁 SYSCFG,TRNG_Out(ENABLE) 开启真随机数发生器,tim3_init() 为 MbedTLS 提供定时器支持。

步骤2:TLS 安全连接建立

文件:USER/main.c — 获取加密库版本信息,创建 SSL Socket 并初始化 TLS 上下文,通过 TCP 连接到目标服务器 443 端口,完成 TLS 握手。

uint32_t ver = wiz_crypt_version();
printf("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);
printf("WIZnet CARD Crypt Test V1.0 start......\r\n");

/* open socket */
wiz_tls_socket(&tlsContext, SOCKET_SSL_ID, LOCAL_PORT);

/* tls init */
wiz_tls_init(&tlsContext, 2000, (char *)ssl_target_ip, NULL, NULL, NULL);

/* connect server */
connect(tlsContext.socket_fd, (uint8_t *)ssl_target_ip, SSL_TARGET_PORT);

/* tls handshake */
wiz_tls_connect(&tlsContext, (char *)ssl_target_ip, SSL_TARGET_PORT);

printf("W55MH32 MbedTLS Transmission test start......\r\n");

步骤3:TLS 初始化与握手

文件:USER/wiz_tls.c — wiz_tls_init 函数初始化 TLS 客户端连接,参数包括 TLS 上下文、接收超时、目标服务器域名/IP、根证书、客户端证书和私钥。

int wiz_tls_init(wiz_tls_context *tlsContext, uint32_t recv_timeout,
                 char *domain_name, char *root_ca,
                 char *client_cert, char *pkey)
{
    int ret = 1;
    const char *pers = "ssl_client1";

    /* Initialize session data */
    tlsContext->entropy   = malloc(sizeof(mbedtls_entropy_context));
    tlsContext->ctr_drbg  = malloc(sizeof(mbedtls_ctr_drbg_context));
    tlsContext->ssl       = malloc(sizeof(mbedtls_ssl_context));
    tlsContext->conf      = malloc(sizeof(mbedtls_ssl_config));
    tlsContext->cacert    = malloc(sizeof(mbedtls_x509_crt));
    tlsContext->clicert   = malloc(sizeof(mbedtls_x509_crt));
    tlsContext->pkey      = malloc(sizeof(mbedtls_pk_context));

    mbedtls_entropy_init(tlsContext->entropy);
    mbedtls_ctr_drbg_init(tlsContext->ctr_drbg);
    mbedtls_ssl_init(tlsContext->ssl);
    mbedtls_ssl_config_init(tlsContext->conf);
    mbedtls_x509_crt_init(tlsContext->cacert);

    /* Seed the random number generator */
    ret = mbedtls_ctr_drbg_seed(tlsContext->ctr_drbg, mbedtls_entropy_func,
                                tlsContext->entropy,
                                (const unsigned char *)pers, strlen(pers));

    /* Parse CA root certificate */
    if (root_ca != NULL) {
        ret = mbedtls_x509_crt_parse(tlsContext->cacert,
                    (const unsigned char *)root_ca, strlen(root_ca) + 1);
        if (ret < 0) {
            printf("mbedtls_x509_crt_parse returned -0x%x\r\n", -ret);
            return -1;
        }
        mbedtls_ssl_set_hostname(tlsContext->ssl, domain_name);
        tlsContext->root_ca_option = MBEDTLS_SSL_VERIFY_REQUIRED;
    } else {
        tlsContext->root_ca_option = MBEDTLS_SSL_VERIFY_NONE;
    }

    /* Configure SSL defaults */
    mbedtls_ssl_config_defaults(tlsContext->conf,
                                MBEDTLS_SSL_IS_CLIENT,
                                MBEDTLS_SSL_TRANSPORT_STREAM,
                                MBEDTLS_SSL_PRESET_DEFAULT);

    mbedtls_ssl_conf_authmode(tlsContext->conf, tlsContext->root_ca_option);
    mbedtls_ssl_conf_ca_chain(tlsContext->conf, tlsContext->cacert, NULL);
    mbedtls_ssl_conf_rng(tlsContext->conf, SSLRandomCB, tlsContext->ctr_drbg);
    mbedtls_ssl_conf_read_timeout(tlsContext->conf, recv_timeout);

    mbedtls_ssl_setup(tlsContext->ssl, tlsContext->conf);
    mbedtls_ssl_set_bio(tlsContext->ssl, (void *)tlsContext->socket_fd,
                        SSLSendCB, SSLRecvCB, SSLRecvTimeOutCB);
    return 1;
}

测试中设置了 2 秒超时和目标服务器 IP,但未配置证书验证参数(root_ca、client_cert、pkey 均为 NULL)。

/* tls init */
wiz_tls_init(&tlsContext, 2000, (char *)ssl_target_ip, NULL, NULL, NULL);

TLS 握手过程中,TRNG_Out 函数通过开启或关闭 TRNG 模块,为 TLS 握手提供必要的真随机数来源,保障密钥生成等安全操作所需的随机熵源。

/**
  * @brief  TRNG_Out
  * @param  NewState: ENABLE or DISABLE
  * @retval None
  */
void TRNG_Out(FunctionalState NewState)
{
    if (NewState != DISABLE)
    {
        RCC->RCC_SYSCFG_CONFIG = 0x01;
        SYSCFG->SYSCFG_LOCK = 0xCDED3526;
        SYSCFG->SSC_CLK_EN |= TRNG_RNG_ENABLE;
    }
    else
    {
        RCC->RCC_SYSCFG_CONFIG = 0x00;
        SYSCFG->SSC_CLK_EN &= ~TRNG_RNG_ENABLE;
    }
}

wiz_tls_connect 是 TLS 客户端核心函数,通过循环调用 mbedtls_ssl_handshake 处理握手流程,握手成功后输出协商的加密套件。

int wiz_tls_connect(wiz_tls_context *tlsContext, char *addr, unsigned int port)
{
    int      ret;
    uint32_t flags;

    printf(" Performing the SSL/TLS handshake...\r\n");
    while ((ret = mbedtls_ssl_handshake(tlsContext->ssl)) != 0)
    {
        if (ret != MBEDTLS_ERR_SSL_WANT_READ &&
            ret != MBEDTLS_ERR_SSL_WANT_WRITE)
        {
            printf(" failed! mbedtls_ssl_handshake returned -0x%x\n\r", -ret);
            return (-1);
        }
        delay_ms(10);
    }

    if (tlsContext->root_ca_option == MBEDTLS_SSL_VERIFY_REQUIRED)
    {
        printf("  . Verifying peer X.509 certificate...\r\n");
        if ((flags = mbedtls_ssl_get_verify_result(tlsContext->ssl)) != 0)
        {
            char vrfy_buf[512];
            printf("failed\r\n");
            mbedtls_x509_crt_verify_info(vrfy_buf, sizeof(vrfy_buf), "  ! ", flags);
            printf("%s\r\n", vrfy_buf);
            return -1;
        }
        else
        {
            printf("ok\r\n");
        }
    }
    printf(" ok\n\r    [ Ciphersuite is %s ]\n\r",
           mbedtls_ssl_get_ciphersuite(tlsContext->ssl));
    return (0);
}

mbedtls_ssl_handshake 是 mbedTLS 库中执行 SSL/TLS 握手协议的核心实现,通过循环调用握手步骤函数完成加密参数协商、密钥交换和身份验证等过程。

/*
 * Perform the SSL handshake
 */
int mbedtls_ssl_handshake(mbedtls_ssl_context *ssl)
{
    int ret = 0;

    /* Sanity checks */
    if (ssl == NULL || ssl->conf == NULL) {
        return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
    }

    /* Main handshake loop */
    while (ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER) {
        ret = mbedtls_ssl_handshake_step(ssl);
        if (ret != 0) break;
    }

    return ret;
}

步骤4:安全通信

文件:USER/wiz_tls.c — 握手完成后,所有数据通过加密通道收发。核心是调用 wiz_tls_write(加密发送)和 wiz_tls_read(加密接收),AES 和 SHA 硬件处理加密解密和完整性检查。

unsigned int wiz_tls_read(wiz_tls_context *tlsContext, unsigned char *readbuf, unsigned int len)
{
    return mbedtls_ssl_read(tlsContext->ssl, readbuf, len);
}

unsigned int wiz_tls_write(wiz_tls_context *tlsContext, unsigned char *writebuf, unsigned int len)
{
    return mbedtls_ssl_write(tlsContext->ssl, writebuf, len);
}

通过已建立的 TLS 安全连接向百度服务器发送 HTTP GET 请求获取网页内容,并在无限循环中持续接收和打印服务器返回的响应数据。

printf("W55MH32 get baidu.com html content......\r\n");
mbedtls_ssl_conf_read_timeout(tlsContext.conf, 200);
sprintf(ethernet_buf,
        "GET / HTTP/1.1\r\nHost: www.baidu.com\r\n"
        "User-Agent: W55MH32/1.0\r\nAccept: text/html\r\n"
        "Connection: close\r\n\r\n");
wiz_tls_write(&tlsContext, (unsigned char *)ethernet_buf, strlen(ethernet_buf));

while (1)
{
    recv_len = wiz_tls_read(&tlsContext, ethernet_buf, ETHERNET_BUF_MAX_SIZE - 1);

    if (recv_len > 0)
    {
        printf("recv_len:%d\r\n", recv_len);
        ethernet_buf[recv_len] = '\0';
        printf("Received: %s", ethernet_buf);
    }
}

数据通信流程

应用数据使用 AES 硬件模块进行加密,使用 SHA 硬件和会话 MAC 密钥计算消息认证码(MAC)。加密后的数据和 MAC 被发送给另一方,接收方使用 AES 硬件解密数据,并使用 SHA 硬件验证 MAC,验证成功保证了数据的完整性和真实性。

运行验证

通过例程测试使用 HTTPS 获取百度网页信息,通过串口打印显示 W55MH32 PHY 链路正常、DHCP 获网成功,加载加密库后完成 TLS 握手(套件 TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256),发送请求并接收百度响应。打开 WIZ UartTool V1.0,连接 DEBUG USB 对应 COM 口(115200 / 8N1),典型输出如下:

W55MH32  TLS Example
PHY link
The current Mbtis speed : 100Mbps
The current Duplex Mode : Full-Duplex
DHCP running
DHCP success!
====================================================================================================
 W55MH32 network configuration : DHCP

 MAC         : 00:08:DC:12:22:12
 IP          : 192.168.1.7
 Subnet Mask : 255.255.255.0
 Gateway     : 192.168.1.1
 DNS         : 192.168.1.1
====================================================================================================

WIZnet CARD Secure Test Demo V1.0, secure lib version is V03.01.04.00
WIZnet CARD Crypt Test V1.0 start......
TLS-DHE-RSA-WITH-AES-256-CBC-SHA256
TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256
TLS-DHE-RSA-WITH-AES-128-GCM-SHA256
TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256
TLS-DHE-RSA-WITH-AES-128-CBC-SHA256
TLS-RSA-WITH-AES-256-CBC-SHA256
TLS-RSA-WITH-AES-128-GCM-SHA256
TLS-RSA-WITH-AES-128-CBC-SHA256
socket_fd = 1
return 1
 Performing the SSL/TLS handshake...
 ok

    [ Ciphersuite is TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256 ]

W55MH32 MbedTLS Transmission test start......
W55MH32 get baidu.com html content......
recv_len:1179
Received: HTTP/1.1 200 OK ...
WIZ UartTool 串口输出 — TLS 测试初始化(PHY 链路 + DHCP + 安全库版本 + 密码套件列表)
WIZ UartTool 串口输出 — TLS 握手成功(访问百度 HTTPS,接收1179字节响应)

TLS 握手报文分析

通过 Wireshark 进行抓包展示了从 TCP 三次握手建立连接,接着开展 TLS 握手(涵盖 Client Hello、Server Hello、密钥交换等操作)以构建安全通信通道并传输应用数据。在 Wireshark 的显示过滤器中输入表达式 ip.addr == 192.168.1.7 and tls 过滤出 TLS 协议数据包,W55MH32 为客户端(192.168.1.7)访问百度服务器(220.181.111.1)。

TLS 四次握手流程

阶段方向TLS消息
第一次握手W55MH32 -> 百度Client Hello(TLS版本、密码套件列表、客户端随机数)
第二次握手百度 -> W55MH32Server Hello、Certificate、Server Hello Done
第三次握手W55MH32 -> 百度Client Key Exchange、Change Cipher Spec、Encrypted Handshake Message
第四次握手百度 -> W55MH32Change Cipher Spec、Encrypted Handshake Message

从抓包中可以看到当前通信安全层协议版本(Version)为 TLS 1.2。TLS 共有 4 个版本:

  • TLS 1.3:发布于 2018 年,大幅简化握手过程,引入 0-RTT 握手减少延迟,删除不安全算法
  • TLS 1.2:发布于 2008 年,引入更强的加密算法和灵活的密码套件选择,是目前广泛使用的版本(本例百度网站使用)
  • TLS 1.1:发布于 2006 年,对 CBC 模式安全性改进,但仍存在已知安全问题
  • TLS 1.0:1999 年发布,SSL 3.0 的升级版本,仍存在安全问题

密码套件格式

格式为「密钥交换算法 + 签名算法(认证算法) + 对称加密算法 + 摘要算法」。例如 TLS_RSA_WITH_AES_128_GCM_SHA256 表示:RSA 密钥交换与认证、AES-128-GCM 对称加密、SHA256 摘要算法。密钥交换算法和签名算法可以相同时合二为一。

握手完成后,客户端与服务端的所有通信内容均被加密。服务器遵循 TLS 协议规范发出关闭警报(close_notify),随即发送 TCP RST 报文以快速释放连接资源。

Wireshark 抓包 — TLS Encrypted Alert(close_notify)+ TCP RST 连接释放

常见问题

Q: W55MH32 硬件加密相比软件加密有什么优势

硬件加密将计算密集型的加密运算(AES、SHA)从主 CPU 卸载到专用硬件模块执行,大幅降低 CPU 占用率,提高整体性能。同时 TRNG 提供真正的随机熵源,比软件伪随机数生成器更安全。这使得主 CPU 能够专注于应用逻辑,在 216MHz 的处理能力下实现高性能安全通信。

Q: TLS 握手过程中 W55MH32 的硬件如何参与

TRNG 在 Client Hello 阶段生成 32 字节客户端随机数,在密钥交换阶段生成预主密钥或临时 DH 密钥对。SHA 硬件用于验证服务器证书的数字签名、计算 Finished 消息的握手哈希值以及数据传输时的消息认证码(MAC)。AES 硬件在握手完成后负责所有应用数据的加密和解密操作。

Q: 如何配置证书验证

在调用 wiz_tls_init 时传入 root_ca 参数(根证书字符串),函数会通过 mbedtls_x509_crt_parse 解析证书并设置 root_ca_option 为 MBEDTLS_SSL_VERIFY_REQUIRED。若 root_ca 为 NULL,则设为 MBEDTLS_SSL_VERIFY_NONE(不验证证书)。生产环境中建议启用证书验证以确保安全性。

Q: 支持哪些密码套件

W55MH32 通过 MbedTLS 库支持多种密码套件,包括 TLS_RSA_WITH_AES_128_GCM_SHA256、TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 等。套件由密钥交换算法(DHE/RSA)、认证算法(RSA)、对称加密算法(AES-128/256-GCM)和摘要算法(SHA256/384)组合而成。握手时客户端发送支持的套件列表,服务器从中选择双方都支持的最安全套件。

总结

  • 专用硬件加速:内置 AES、SHA 加密算法单元和 TRNG 真随机数发生器,将加密计算从 CPU 卸载
  • TLS 1.2 全流程支持:通过 MbedTLS 库配合硬件模块实现完整的 TLS 握手和加密数据传输
  • 核心 API:wiz_tls_init 初始化上下文,wiz_tls_connect 执行握手,wiz_tls_read/write 进行加密通信
  • 硬件角色:TRNG 生成随机数和密钥,SHA 验证证书和计算 MAC,AES 加解密应用数据
  • 应用场景:适用于 IoT 设备的安全网络通信,如 HTTPS 客户端、MQTTS、邮件安全传输等

下载本章例程

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

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

Andy

W5500 技术支持专家