1. 课程导入与目标设定

在嵌入式设备上使用密码学,往往不是“把开源密码库编译进去”这么简单。以常见的 mbedTLS、wolfSSL、OpenSSL 或国密实现为例,一个完整密码库动辄包含数十万行代码、上百个算法模块、多种协议栈与平台抽象层。而目标设备可能只有 64 KB RAM、256 KB Flash,甚至运行在无操作系统的裸机环境,主频仅几十兆赫兹。密码库裁剪与嵌入式适配,正是解决“功能完整”与“资源受限”之间矛盾的一门工程实践技术。

本课程的核心问题可以归纳为三个层面。第一是空间问题:如何在不破坏必要安全功能的前提下,把代码体积、常量表、静态缓冲区压缩到目标平台可接受的范围。第二是运行问题:如何在有限算力、有限内存、无动态分配或受限分配的条件下,让加解密、签名验签、密钥协商等操作稳定完成。第三是适配问题:如何把密码库与具体芯片的硬件加速器、随机数发生器、存储介质、编译工具链和启动流程正确对接。三者相互制约,裁剪过度可能导致功能缺失或安全强度下降,适配不当则可能引入随机数质量差、侧信道泄露或运行崩溃等风险。

学习本课程后,你应当能够:读懂一个密码库的模块依赖关系;根据产品需求确定最小算法集合;使用配置宏、链接脚本和编译选项完成裁剪;为无 OS 平台提供熵源、时钟和内存接口;验证裁剪后库的功能正确性与资源占用;并形成可复现的构建与测试记录。

从需求到最小密码集合

裁剪的第一步不是删代码,而是明确“必须保留什么”。假设一个智能门锁项目需要与手机 App 建立安全通道,并支持固件签名校验。典型需求可拆解为:设备端生成临时密钥并完成 ECDH 密钥协商;使用 AES-128-GCM 保护通信数据;使用 SHA-256 做完整性校验;使用 ECDSA P-256 验证固件签名;使用真随机数生成会话密钥和 nonce。由此得到最小算法集合:ECDH、ECDSA、AES-GCM、SHA-256、CTR-DRBG 或硬件 TRNG。像 RSA、DH、3DES、MD5、SHA-1、X.509 完整解析、TLS 服务端等模块,如果没有明确需求,就可以在配置阶段关闭。

这里有一个常见误区:认为“关掉宏定义就等于删掉代码”。实际上,很多密码库的模块之间存在隐式依赖。例如关闭 MBEDTLS_X509_CRT_PARSE_C 后,若仍启用 MBEDTLS_SSL_SRV_C,编译可能失败或链接时缺少符号。因此,裁剪必须建立在依赖图之上,而不是凭感觉删宏。

密码库裁剪与嵌入式适配:核心关系图 需求层 安全通信 固件签名校验 设备身份认证 随机数质量 资源上限 最小算法集合 ECDH P-256 ECDSA P-256 AES-128-GCM SHA-256 CTR-DRBG TRNG 裁剪手段 配置宏开关 链接段回收 编译优化 适配接口 熵源/TRNG 硬件加速器 内存/时钟 验证闭环 功能正确性 资源占用(Flash/RAM) 性能与功耗 随机数质量 可复现构建

工具链概览与实战环境搭建

本课程使用的工具链分为四类。第一类是交叉编译工具链,例如 arm-none-eabi-gcc 用于 Cortex-M 系列,riscv64-unknown-elf-gcc 用于 RISC-V 平台。第二类是构建与配置工具,包括密码库自带的配置脚本、CMake、Makefile,以及用于生成配置头文件的脚本。第三类是分析与度量工具,例如 arm-none-eabi-size 查看段大小,nm 查看符号,objdump 反汇编确认关键函数是否被链接,gcov 或 lcov 做覆盖率分析。第四类是运行与调试环境,包括 QEMU 模拟器、J-Link/ST-Link 调试器、串口日志,以及目标板上的基准测试程序。

下面给出一个可复现的实战环境搭建示例,目标平台为 Cortex-M4,使用 mbedTLS 作为裁剪对象。示例参数为教学假设,实际使用时需根据芯片手册和项目需求调整。

# 1. 获取源码
git clone https://github.com/Mbed-TLS/mbedtls.git
cd mbedtls
git checkout v3.6.0

# 2. 准备交叉编译环境
export CROSS_COMPILE=arm-none-eabi-
export CC=${CROSS_COMPILE}gcc
export AR=${CROSS_COMPILE}ar

# 3. 生成最小配置(示例:仅保留 ECDH/ECDSA/AES-GCM/SHA-256)
cp configs/config-ccm-psk-tls1_2.h include/mbedtls/mbedtls_config.h

# 4. 使用 CMake 构建静态库
cmake -S . -B build \
  -DCMAKE_C_COMPILER=${CC} \
  -DCMAKE_AR=${AR} \
  -DENABLE_TESTING=Off \
  -DENABLE_PROGRAMS=Off \
  -DCMAKE_BUILD_TYPE=MinSizeRel
cmake --build build -j

# 5. 查看资源占用
${CROSS_COMPILE}size build/library/libmbedcrypto.a

执行 size 后,你会看到类似 text data bss dec hex filename 的输出。其中 text 对应 Flash 占用,data 和 bss 对应 RAM 占用。教学示例中,裁剪后的 libmbedcrypto.a 可能从默认的约 300 KB text 降到 60~90 KB,具体数值取决于优化等级、是否启用硬件加速以及编译器版本。这个数字不是实测结论,而是帮助你建立量级概念。

建议在项目初期就建立“资源预算表”:列出 Flash 总量、RAM 总量、协议栈占用、应用占用、密码库预算,并预留 15%~20% 余量。裁剪目标不是越小越好,而是在满足安全需求的前提下留出可维护空间。

学习路径与常见陷阱

本课程后续将按照“需求分析 → 依赖梳理 → 配置裁剪 → 平台适配 → 功能验证 → 性能优化”的路径展开。你需要重点掌握三类技能:第一,能读懂密码库的配置宏和模块依赖,知道关闭一个宏会影响哪些功能;第二,能为裸机或 RTOS 环境实现必要的移植接口,尤其是熵源、时钟和内存分配;第三,能通过符号表、段大小和运行时日志判断裁剪是否成功、适配是否正确。

常见陷阱包括:关闭了 MBEDTLS_ENTROPY_C 却仍使用需要随机数的算法,导致运行时失败;只关注 Flash 占用而忽略 RAM 中的大缓冲区;在无 MMU 平台上使用默认的 malloc 导致堆碎片;以及忘记验证硬件加速器与软件实现的结果一致性。这些问题在后续章节会逐一展开,本章的目标是让你先建立全局视图,知道每一步在解决什么问题、用什么工具、看什么指标。

请先完成环境搭建,并尝试用 size 和 nm 记录默认配置与最小配置的差异。这个基线数据将贯穿整个课程,帮助你判断每一次裁剪和适配带来的真实变化。