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 |
| Flash | 512KB |
| RAM | 64KB |
| IDE | STM32CubeIDE 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.h和stdint.hAPI 与 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 方式烧录:
BOOT0 拨到 1,按 RESET
打开 FlyMCU,选择 COM 口,打开
.hex文件点击「编程」
烧录完成,BOOT0 拨回 0,按 RESET
7.2 串口输出
打开 XCOM(波特率 115200),按 RESET:
8. 资源占用
编译后资源占用(优化级别 -O0):
| 区域 | 大小 |
|---|---|
| text(代码) | 13.7 KB |
| data | 104 B |
| bss | 14.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/NN、Drivers/CMSIS/DSP、Drivers/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 算法的移植提供了:
可用的编译环境(CubeMX + CubeIDE 配置已验证)
可用的基础代码(printf 重定向、串口通信、内存配置)
性能基线(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 支持!