MbedTLS库完全指南:从GitHub下载到嵌入式移植

为什么你的物联网设备需要加密?如何将MbedTLS库移植到STM32等嵌入式平台?本文将为你详细解答。

一、为什么要移植MbedTLS?------背景篇

1.1 物联网的安全困境

在SSL/TLS协议出现之前,很多应用层协议(HTTP、FTP、MQTT等)都面临着严峻的网络安全问题:

  • 信息泄露:HTTP等协议使用明文传输,报文一旦被截获便会泄露传输内容
  • 数据篡改:传输过程中报文如果被篡改,接收方无法察觉
  • 身份伪造:无法保证通信对端身份的真实性

你可能会问:这些和物联网设备有什么关系?

想象一下:你的智能门锁、智能摄像头、工业传感器通过明文传输数据------攻击者可以轻松截获开锁指令、窃取敏感数据、甚至冒充服务器下发恶意指令。这不仅是隐私问题,更是安全隐患

1.2 MbedTLS是什么?

Mbed TLS是一个开源的、可移植的、轻量级的SSL/TLS库,使用标准C语言编写。它的核心特点包括:

特性 说明
轻量级 代码占用空间小,适合资源受限的嵌入式设备
模块化 独立模块设计,可按需裁剪功能
功能完整 包含加密库、X.509证书操作、SSL/TLS和DTLS协议
开源许可 Apache 2.0许可证,商业友好

1.3 有了MbedTLS能做什么?

将MbedTLS库移植到你的设备后,可以实现:

复制代码
TCP + TLS = TCP(S)     → 安全的TCP通信
MQTT + TLS = MQTT(S)   → 安全的MQTT连接(物联网常用)
HTTP + TLS = HTTPS     → 安全的HTTP请求
COAP + DTLS = COAP(S)  → 安全的COAP协议

简单来说:MbedTLS为你的设备穿上了"安全铠甲"

1.4 为什么不用OpenSSL?

OpenSSL功能更强大,但体量也更大。对于资源受限的嵌入式设备(如只有几十KB RAM的MCU),MbedTLS是更合适的选择:

对比项 OpenSSL MbedTLS
代码体积 较大(MB级别) 小巧(KB级别)
资源消耗
配置灵活性 一般 极高(宏定义裁剪)
适用场景 服务器、PC 嵌入式设备、IoT

二、下载MbedTLS库------获取篇

2.1 官方下载方式

Mbed TLS的官方源码托管在GitHub上。打开终端,执行以下命令:

bash 复制代码
# 克隆完整仓库(包含子模块)
git clone --recurse-submodules https://github.com/Mbed-TLS/mbedtls.git

# 或者指定版本(推荐)
git clone --recurse-submodules --branch v3.6.0 https://github.com/Mbed-TLS/mbedtls.git

如果只需要源码包,也可以访问GitHub Release页面下载压缩包:

2.2 源码结构解析

下载后,你会看到以下核心目录:

复制代码
mbedtls/
├── include/mbedtls/      # 头文件(API声明)
│   ├── config.h          # 核心配置文件(重要!)
│   ├── ssl.h             # SSL/TLS API
│   ├── sha1.h            # 哈希算法API
│   └── ...
├── library/              # 源码实现(.c文件)
├── programs/             # 示例程序
│   └── ssl/              # SSL示例(ssl_client2.c等)
└── tests/                # 测试代码

重点关注include/mbedtls/config.h 是整个库的"开关面板",通过宏定义控制编译哪些功能。

三、移植MbedTLS库------实战篇

3.1 移植的本质

MbedTLS在电脑上可以直接运行,但在嵌入式平台上,需要替换三部分内容:

复制代码
┌─────────────────────────────────────────┐
│  MbedTLS 需要平台提供三个能力:          │
├─────────────────────────────────────────┤
│  1. 网络接口 - 数据的收发能力            │
│  2. 内存管理 - malloc/free能力           │
│  3. 定时器   - 时间计算能力(DTLS需要)   │
└─────────────────────────────────────────┘

3.2 方法一:使用STM32CubeMX(STM32芯片专用)

如果你的芯片是STM32且使用STM32CubeMX,这是最简单的方法。

步骤1:准备基础工程

先创建一个可以正常使用printf打印的工程,确保串口能输出信息。

步骤2:开启RNG外设(可选)

一些STM32系列有硬件随机数发生器(RNG),开启它可以增强安全性。没有的话也没关系,MbedTLS会用软件实现。

步骤3:在Middleware中开启mbedtls

在STM32CubeMX的中间件选项中找到mbedtls,勾选启用。

步骤4:配置需要的功能模块

MbedTLS提供了大量加密算法,你可以通过勾选/取消勾选来决定编译哪些模块。原则是:只选你需要的,以节省资源。

步骤5:生成代码并测试

生成工程后,在main.c中添加测试代码:

c 复制代码
#include "mbedtls/sha1.h"
#include "string.h"

// 测试SHA1加密
char *source = "hello mbedtls";
char encrypt[64];

printf("原文: %s\r\n", source);

mbedtls_sha1_context ctx;
mbedtls_sha1_init(&ctx);
mbedtls_sha1_starts(&ctx);
mbedtls_sha1_update(&ctx, (unsigned char *)source, strlen(source));
mbedtls_sha1_finish(&ctx, (unsigned char *)encrypt);
mbedtls_sha1_free(&ctx);

printf("SHA1加密结果: ");
for(int i = 0; i < 20; i++) {
    printf("%02x", (unsigned char)encrypt[i]);
}
printf("\r\n");

注意:Keil-MDK需要改为ANSI编码,否则字符串编码问题会导致加密结果出错。

3.3 方法二:手动移植(通用方法)

不使用CubeMX或使用其他MCU时,可采用手动移植。

步骤1:复制源码文件

将mbedtls的library文件夹中所有.c文件复制到你的工程中。

步骤2:复制头文件

include/mbedtls文件夹复制到工程的头文件路径中。

步骤3:复制配置文件

从源码根目录复制一份config.h(或示例配置文件)到工程中,方便后续修改。

步骤4:在工程中添加文件

以Keil-MDK为例:

  • 将library中的所有.c文件添加到工程
  • 添加头文件路径
  • 在编译宏中指定配置文件:MBEDTLS_CONFIG_FILE=<config.h>

步骤5:按需裁剪配置

编辑config.h,通过注释/取消注释宏定义来控制功能:

c 复制代码
// 启用需要的功能
#define MBEDTLS_SHA1_C          // SHA1算法
#define MBEDTLS_AES_C           // AES加密
#define MBEDTLS_SSL_TLS_C       // SSL/TLS协议

// 禁用不需要的功能(节省空间)
// #define MBEDTLS_MD5_C         // 如果不需要MD5就注释掉

3.4 平台适配:替换底层接口

这是移植的核心环节。MbedTLS需要你的平台提供三个底层能力:

3.4.1 网络接口适配

MbedTLS默认的网络接口是阻塞式的,适用于电脑端。在嵌入式系统中,你需要自己实现:

c 复制代码
// 需要实现的网络接口
int mbedtls_net_connect(mbedtls_net_context *ctx, const char *host, const char *port, int proto);
int mbedtls_net_recv(void *ctx, unsigned char *buf, size_t len);
int mbedtls_net_send(void *ctx, const unsigned char *buf, size_t len);
void mbedtls_net_free(mbedtls_net_context *ctx);

实现后,通过mbedtls_ssl_set_bio注册给MbedTLS:

c 复制代码
mbedtls_ssl_set_bio(&ssl, &server_fd,
    custom_send,   // 你的发送函数
    custom_recv,   // 你的接收函数
    custom_recv_timeout);
3.4.2 内存管理适配

如果你的系统有自己的内存管理,可以替换默认的malloc/free:

c 复制代码
// 注册自定义内存管理函数
mbedtls_platform_set_calloc_free(custom_calloc, custom_free);
3.4.3 定时器适配(DTLS需要)

如果使用DTLS(UDP版本的TLS),需要实现定时器接口:

c 复制代码
// 定时器回调
void platform_timing_set_delay(void *data, uint32_t int_ms, uint32_t fin_ms);
int platform_timing_get_delay(void *data);

// 注册给MbedTLS
mbedtls_ssl_set_timer_cb(&ssl, &timer_ctx,
    platform_timing_set_delay,
    platform_timing_get_delay);
3.4.4 随机数适配

MbedTLS需要熵源(随机数)来生成密钥。如果你的芯片有硬件随机数发生器(RNG),可以实现:

c 复制代码
// 硬件随机数接口
int mbedtls_hardware_poll(void *data, unsigned char *output, size_t len, size_t *olen);

并在配置中定义:

c 复制代码
#define MBEDTLS_ENTROPY_HARDWARE_ALT

四、常见问题与解决

Q1:编译报错,说某个功能需要依赖其他功能?

在 MbedTLS 的配置文件(mbedtls_config.h,适用于 3.0 及以上版本)中,系统会自动检查各个配置宏之间的依赖关系。如果配置不完整,编译器会给出提示,你只需要根据报错信息,把缺失的依赖宏打开即可。

需要注意的是:这些宏开关中,大部分控制的是库本身的功能,而有一小部分则决定了某些功能是使用库的实现,还是交给平台去完成。

其中,以 ALT 结尾的宏就属于后者。它们的作用是告诉 MbedTLS:

"不要用我默认的软件实现,换成我自己(用户)提供的硬件或定制版本。"

例如,当你打开 MBEDTLS_AES_ALT 时,MbedTLS 就不再提供自带的 AES 实现,而是期望你在外部实现相关接口。

Q2:提示找不到time.h或网络相关头文件?

在配置文件中添加:

c 复制代码
#define MBEDTLS_NO_PLATFORM_ENTROPY   // 没有平台熵源时

Q3:我的设备没有文件系统,如何加载证书?

嵌入式设备通常将证书以数组形式存储,而不是文件:

c 复制代码
// 将证书文件转为数组
const unsigned char my_cert[] = {
    0x2D, 0x2D, 0x2D, 0x2D, 0x2D, ...  // 证书内容
};

// 使用内存方式加载
mbedtls_x509_crt_parse(&cacert, my_cert, sizeof(my_cert));

五、移植总结与建议

移植MbedTLS的整体思路可以概括为:

复制代码
┌─────────────────────────────────────────────────┐
│  1. 获取源码 → 2. 添加文件 → 3. 裁剪配置          │
│           ↓                                      │
│  4. 适配底层(网络/内存/定时器/随机数)           │
│           ↓                                      │
│  5. 编写测试代码验证 → 完成!                    │
└─────────────────────────────────────────────────┘

关键原则

  • 按需裁剪:只开启你需要的加密算法和协议特性,这能显著减少代码体积和内存占用
  • 善用配置检查:MbedTLS自带依赖检查,编译错误时根据提示补充宏定义即可
  • 从简单开始:先测试纯算法功能(如SHA1),再逐步集成网络功能
相关推荐
草莓工作室7 个月前
mbedtls哈希值计算
c语言·哈希算法·mbedtls
YaoYuan93237 个月前
Ubuntu 下编译 mbedtls 并使用
mbedtls
mickey03801 年前
开源加密库mbedtls及其Windows编译库
信息安全·密码技术·mbedtls
Thiac3 年前
ubuntu16.04 交叉编译 mbedtls
交叉编译·mbedtls