后量子密码学(PQC)在 STM32 上的探索(一):mbedTLS 移植与 SHA256 验证
2026/7/23 12:34:47 网站建设 项目流程

1. 为什么做这个实验?

1.1 研究背景

2024年,NIST 正式发布了 FIPS 203(ML-KEM,原 Kyber)和 FIPS 204(ML-DSA,原Dilithium)等后量子密码学(Post-Quantum Cryptography, PQC)标准。这意味着:

- 量子计算机的威胁已经进入倒计时
- 传统公钥密码(RSA、ECDSA)将在未来 10-15 年内被逐步淘汰
- 嵌入式设备(IoT、汽车、工业控制)必须提前规划 PQC 迁移路径

然而,PQC 算法(如 Kyber、Dilithium)的计算量远大于传统算法,在资源受限的STM32F103(72MHz,64KB RAM)上能否运行?性能如何?这是本系列研究要回答的核心问题。

1.2 本实验的定位

在直接移植 PQC 算法之前,必须先确保传统密码学基础环境可用。因此,本实验的目标是:

在 STM32F103 上移植 mbedTLS,验证 SHA256 哈希算法,为后续移植 Kyber 等 PQC算法提供基础支撑。

本实验是这个 PQC 研究系列的第 1 篇,后续将逐步深入

2. 硬件与软件环境

项目版本/型号
开发板正点原子 战舰V3
主控芯片STM32F103ZET6
主频72MHz
Flash512KB
RAM64KB
IDESTM32CubeIDE 1.15.0
中间件mbedTLS(手动移植)
烧录工具FlyMCU(串口ISP)

为什么选 STM32F103?

它是资源受限设备的典型代表(主播的手上目前也只有这个)。如果 PQC 算法能在 F103 上跑通,那在更高性能的 STM32H7/F7 上只会更轻松;如果 F103 跑不通,就需要研究优化策略或硬件加速方案。

3. CubeMX 工程配置

3.1 选择 MCU

打开 STM32CubeMX → `ACCESS TO MCU SELECTOR` → 搜索 `STM32F103ZET6` → 双击选中。

3.2 配置 RCC(时钟)

`System Core` → `RCC` → `High Speed Clock (HSE)` → 选 `Crystal/Ceramic Resonator`

(注意:这里右边芯片部分只会芯片图上 PA8 和 PC9 这两个引脚会变成绿色,因为主播把已经完成的项目拿来演示一遍,所以别的引脚也亮了颜色)

3.3 配置 SYS(调试接口)

`System Core` → `SYS` → `Debug` → 选 `Serial Wire`

⚠️ 必须选 Serial Wire,否则烧录一次后芯片会锁死!

3.4 配置 USART1(串口)

`Connectivity` → `USART1` → `Mode` → 选 `Asynchronous`,波特率 `115200`

3.5 生成工程

点击 `Project Manager` → 填写工程名和路径 → `Toolchain/IDE` 选 `STM32CubeIDE` → 点击 `GENERATE CODE`。

4. mbedTLS 源码移植

4.1 为什么不用 CubeMX 自带的 mbedTLS?

CubeMX 的 `Middleware` 中虽然提供了 mbedTLS 选项,但:
1. 需要额外下载 X-CUBE-TLS 软件包(网络问题可能失败)
2. 会自动引入大量不需要的 SSL/TLS 模块(增加 Flash 占用)
3. 不利于理解 mbedTLS 的内部结构

因此,采用手动移植方式,只引入 SHA256 所需的最小文件集。

4.2 源码结构
工程目录/
├── Core/
│ ├── Inc/
│ │ ├── mbedtls/
│ │ │ ├── mbedtls_config.h # mbedTLS 配置文件
│ │ │ └── sha256.h # SHA256 头文件
│ │ ├── main.h
│ │ └── stm32f1xx_hal_conf.h
│ └── Src/
│ ├── main.c # 主程序(含 SHA256 测试代码)
│ ├── sha256.c # SHA256 算法实现(简化版)
│ └── ...
└── ...

4.3 简化版 sha256.c

mbedTLS 官方的 `sha256.c` 依赖较多内部头文件(如 `common.h`、`platform_util.h` 等),直接移植会导致连锁报错。因此,我实现了一个独立版 SHA256,只依赖标准库,完全兼容 mbedTLS 的 API 接口。(其实主播有点懒,之前下载的`mbedtls-development`包不是完整版,不想再重新下一遍,个人认为手动添加也是一个不错的选择)

//核心代码片段: //c typedef struct { uint32_t state[8]; uint32_t total[2]; unsigned char buffer[64]; int is224; int size; } mbedtls_sha256_context; void mbedtls_sha256_init(mbedtls_sha256_context *ctx) { ... } int mbedtls_sha256_starts(mbedtls_sha256_context *ctx, int is224) { ... } int mbedtls_sha256_update(mbedtls_sha256_context *ctx, const unsigned char *input, size_t ilen) { ... } int mbedtls_sha256_finish(mbedtls_sha256_context *ctx, unsigned char *output) { ... }

这个版本的好处是:

  • 零外部依赖,只需string.hstdint.h

  • API 与 mbedTLS 完全兼容,后续可无缝切换回官方版本

  • 代码量小,便于理解和调试

完整代码见文末 GitHub 链接。

5. 主程序代码

/* Includes */ #include "main.h" #include <string.h> #include <stdio.h> #include "mbedtls/sha256.h" /* printf 重定向到串口 */ int __io_putchar(int ch) { HAL_UART_Transmit(&huart1, (uint8_t*)&ch, 1, HAL_MAX_DELAY); return ch; } int _write(int file, char *ptr, int len) { for(int i = 0; i < len; i++) { __io_putchar(ptr[i]); } return len; } void print_hex(uint8_t *data, size_t len) { for(size_t i = 0; i < len; i++) { printf("%02x", data[i]); } printf("\r\n"); } int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_USART1_UART_Init(); printf("\r\n"); printf("============================================\r\n"); printf(" PQC Research Series (Part 1):\r\n"); printf(" STM32F103 + mbedTLS SHA256 Test\r\n"); printf(" Board: Alientek Warship V3\r\n"); printf(" MCU: STM32F103ZET6 @ 72MHz\r\n"); printf("============================================\r\n"); // ===== Test 1: SHA256 ===== printf("\r\n--- Test 1: SHA256 Hash ---\r\n"); char *msg = "Hello PQC!"; uint8_t hash[32]; mbedtls_sha256_context ctx; mbedtls_sha256_init(&ctx); mbedtls_sha256_starts(&ctx, 0); mbedtls_sha256_update(&ctx, (uint8_t*)msg, strlen(msg)); mbedtls_sha256_finish(&ctx, hash); mbedtls_sha256_free(&ctx); printf("Message: %s\r\n", msg); printf("SHA256: "); print_hex(hash, 32); // ===== Test 2: Standard Vector ===== printf("\r\n--- Test 2: Standard Vector SHA256(\"abc\") ---\r\n"); char *msg2 = "abc"; uint8_t hash2[32]; uint8_t expected[] = { 0xBA, 0x78, 0x16, 0xBF, 0x8F, 0x01, 0xCF, 0xEA, 0x41, 0x41, 0x40, 0xDE, 0x5D, 0xAE, 0x22, 0x23, 0xB0, 0x03, 0x61, 0xA3, 0x96, 0x17, 0x7A, 0x9C, 0xB4, 0x10, 0xFF, 0x61, 0xF2, 0x00, 0x15, 0xAD }; mbedtls_sha256_context ctx2; mbedtls_sha256_init(&ctx2); mbedtls_sha256_starts(&ctx2, 0); mbedtls_sha256_update(&ctx2, (uint8_t*)msg2, strlen(msg2)); mbedtls_sha256_finish(&ctx2, hash2); mbedtls_sha256_free(&ctx2); printf("Message: %s\r\n", msg2); printf("SHA256: "); print_hex(hash2, 32); if(memcmp(hash2, expected, 32) == 0) { printf("Result: PASSED!\r\n"); } else { printf("Result: FAILED!\r\n"); } printf("\r\n============================================\r\n"); printf(" SHA256 validation completed.\r\n"); printf(" Next: Kyber-512 on STM32F103...\r\n"); printf("============================================\r\n"); while(1) { HAL_Delay(1000); } }

6. 内存配置

STM32F103 的 RAM 只有 64KB,需要确保堆栈足够:

STM32F103ZETX_FLASH.ld中修改:

_Min_Heap_Size = 0x2000; /* 8KB */ _Min_Stack_Size = 0x1800; /* 6KB */

7. 烧录与验证

7.1 烧录

使用 FlyMCU 通过串口 ISP 方式烧录:

  1. BOOT0 拨到 1,按 RESET

  2. 打开 FlyMCU,选择 COM 口,打开.hex文件

  3. 点击「编程」

  4. 烧录完成,BOOT0 拨回 0,按 RESET

7.2 串口输出

打开 XCOM(波特率 115200),按 RESET:

8. 资源占用

编译后资源占用(优化级别 -O0):

区域大小
text(代码)13.7 KB
data104 B
bss14.8 KB
总计28.6 KB

Flash 512KB,RAM 64KB,完全够用

9. 踩坑记录

坑1:编译报错common.h: No such file or directory

原因:从 mbedTLS 源码包完整复制的sha256.c依赖内部头文件。

解决:使用独立版 SHA256,去除对common.h等文件的依赖,只保留核心算法。

坑2:串口无输出

原因:没有实现printf重定向。

解决:在main.c中添加_write()__io_putchar()函数。

坑3:CubeMX 工程包含了不需要的 CMSIS 子目录

原因:CubeMX 默认包含 DSP、NN、RTOS2 等模块。

解决:在 CubeIDE 中右键排除Drivers/CMSIS/NNDrivers/CMSIS/DSPDrivers/CMSIS/RTOS2等文件夹。

坑4:堆栈不足导致 HardFault

原因:默认堆栈太小。

解决:在.ld文件中增大_Min_Heap_Size_Min_Stack_Size

10. 总结与下一步

10.1 本实验总结

项目结果
mbedTLS 移植✅ 成功
SHA256 哈希计算✅ 成功
标准向量验证✅ PASSED
资源占用✅ 28.6KB,F103 完全够用

10.2 研究意义

本实验验证了mbedTLS 可以在 STM32F103 上正常运行,为后续 PQC 算法的移植提供了:

  1. 可用的编译环境(CubeMX + CubeIDE 配置已验证)

  2. 可用的基础代码(printf 重定向、串口通信、内存配置)

  3. 性能基线(SHA256 在 F103 上的运行时间可作为参考)

10.3 下一步计划

第 2 篇预告:将尝试移植Kyber-512(NIST PQC 标准 ML-KEM 的前身)到 STM32F103,评估其:

  • 代码大小(Flash 占用)

  • 内存占用(RAM 使用)

  • 运行时间(密钥生成、封装、解封装耗时)

  • 是否能在 F103 上实时运行


📎 参考资料

  • NIST FIPS 203: Module-Lattice-Based Key-Encapsulation Mechanism Standard

  • mbedTLS 官方文档

  • PQClean: Clean implementations of PQC algorithms

  • 正点原子 战舰V3 资料


📦 源码下载

完整工程源码已上传 GitHub:

GitHub - tangchunxia281-dotcom/STM32F103-PQC-Exploration: 后量子密码学(PQC)在 STM32 上的探索系列源码 · GitHub

如果对你有帮助,欢迎 ⭐Star 支持!

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询