后量子密码学(PQC)在 STM32 上的探索(一):mbedTLS 移植与 SHA256 验证

发布时间:2026/7/23 12:34:56
后量子密码学(PQC)在 STM32 上的探索(一):mbedTLS 移植与 SHA256 验证 1. 为什么做这个实验1.1 研究背景2024年NIST 正式发布了 FIPS 203ML-KEM原 Kyber和 FIPS 204ML-DSA原Dilithium等后量子密码学Post-Quantum Cryptography, PQC标准。这意味着- 量子计算机的威胁已经进入倒计时- 传统公钥密码RSA、ECDSA将在未来 10-15 年内被逐步淘汰- 嵌入式设备IoT、汽车、工业控制必须提前规划 PQC 迁移路径然而PQC 算法如 Kyber、Dilithium的计算量远大于传统算法在资源受限的STM32F10372MHz64KB RAM上能否运行性能如何这是本系列研究要回答的核心问题。1.2 本实验的定位在直接移植 PQC 算法之前必须先确保传统密码学基础环境可用。因此本实验的目标是在 STM32F103 上移植 mbedTLS验证 SHA256 哈希算法为后续移植 Kyber 等 PQC算法提供基础支撑。本实验是这个 PQC 研究系列的第 1 篇后续将逐步深入2. 硬件与软件环境项目版本/型号开发板正点原子 战舰V3主控芯片STM32F103ZET6主频72MHzFlash512KBRAM64KBIDESTM32CubeIDE 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波特率 1152003.5 生成工程点击 Project Manager → 填写工程名和路径 → Toolchain/IDE 选 STM32CubeIDE → 点击 GENERATE CODE。4. mbedTLS 源码移植4.1 为什么不用 CubeMX 自带的 mbedTLSCubeMX 的 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.cmbedTLS 官方的 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按 RESET7.2 串口输出打开 XCOM波特率 115200按 RESET8. 资源占用编译后资源占用优化级别 -O0区域大小text代码13.7 KBdata104 Bbss14.8 KB总计28.6 KBFlash 512KBRAM 64KB完全够用。9. 踩坑记录坑1编译报错common.h: No such file or directory原因从 mbedTLS 源码包完整复制的sha256.c依赖内部头文件。解决使用独立版 SHA256去除对common.h等文件的依赖只保留核心算法。坑2串口无输出原因没有实现printf重定向。解决在main.c中添加_write()和__io_putchar()函数。坑3CubeMX 工程包含了不需要的 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.6KBF103 完全够用10.2 研究意义本实验验证了mbedTLS 可以在 STM32F103 上正常运行为后续 PQC 算法的移植提供了可用的编译环境CubeMX CubeIDE 配置已验证可用的基础代码printf 重定向、串口通信、内存配置性能基线SHA256 在 F103 上的运行时间可作为参考10.3 下一步计划第 2 篇预告将尝试移植Kyber-512NIST PQC 标准 ML-KEM 的前身到 STM32F103评估其代码大小Flash 占用内存占用RAM 使用运行时间密钥生成、封装、解封装耗时是否能在 F103 上实时运行 参考资料NIST FIPS 203: Module-Lattice-Based Key-Encapsulation Mechanism StandardmbedTLS 官方文档PQClean: Clean implementations of PQC algorithms正点原子 战舰V3 资料 源码下载完整工程源码已上传 GitHubGitHub - tangchunxia281-dotcom/STM32F103-PQC-Exploration: 后量子密码学PQC在 STM32 上的探索系列源码 · GitHub如果对你有帮助欢迎 ⭐Star 支持