4、非对称加密算法移植(RSA/ECC):大数运算库移植、密钥生成与存储、性能瓶颈分析
非对称加密,说白了就是公钥和私钥这对「钥匙扣」。RSA 和 ECC 是其中最常用的两种。把它们移植到嵌入式设备上,可不是简单复制代码就完事。我做过好几个项目,每次都在大数运算和密钥存储上栽过跟头。今天咱们就聊聊这些坑怎么填。
4.1 大数运算库移植:别小看这步
RSA 和 ECC 的核心,都是大数运算。嵌入式芯片通常只有 32 位或 64 位整数运算能力,而 RSA 需要处理 1024 位甚至 2048 位的数。怎么办?得靠大数运算库。
我个人习惯用 Miracl 或 OpenSSL 的 BIGNUM。但直接移植 OpenSSL 到单片机?太臃肿了。我建议用 Mbed TLS 或者 WolfSSL,它们专门为嵌入式优化过。
移植要点:
- 内存管理:大数运算需要动态分配内存。嵌入式环境里,malloc/free 可能很慢,甚至没有。我建议用静态内存池,提前分配好最大尺寸的缓冲区。
- 字节序:大端还是小端?ARM 默认小端,但 RSA 标准用大端。移植时一定要做转换。我曾经因为字节序搞反,调试了整整两天。
- 优化乘法:大数乘法是性能瓶颈。用 Karatsuba 算法或 Toom-Cook 算法能快不少。但注意,这些算法对内存有额外要求。
// 示例:Mbed TLS 中大数初始化和乘法
#include "mbedtls/bignum.h"
mbedtls_mpi a, b, result;
mbedtls_mpi_init(&a);
mbedtls_mpi_init(&b);
mbedtls_mpi_init(&result);
// 赋值:0x1234567890ABCDEF
mbedtls_mpi_read_string(&a, 16, "1234567890ABCDEF");
mbedtls_mpi_read_string(&b, 16, "FEDCBA0987654321");
// 乘法
mbedtls_mpi_mul_mpi(&result, &a, &b);
// 打印结果
char buf[512];
mbedtls_mpi_write_string(&result, 16, buf, sizeof(buf), NULL);
printf("Result: %s\n", buf);
mbedtls_mpi_free(&a);
mbedtls_mpi_free(&b);
mbedtls_mpi_free(&result);
我的经验: 在 STM32F4 上,用 Mbed TLS 做一次 2048 位 RSA 签名,大约需要 200ms。如果换成纯软件实现,可能要 2 秒以上。所以,选对库很重要。
4.2 密钥生成与存储:安全第一
密钥生成,说白了就是找两个大素数(RSA)或者一个随机数(ECC)。但嵌入式设备随机数质量往往不行。我遇到过用 rand() 生成密钥的案例,结果密钥被轻松猜出来。
正确的做法:
- 使用硬件随机数生成器(TRNG)。大多数现代 MCU 都有。
- 如果没有,用软件熵源,比如 ADC 噪声、时钟抖动。
- 生成后一定要做 素性检测(RSA)或 点验证(ECC)。
避坑指南: 我曾经在某个项目里,直接用软件生成的随机数做 ECC 密钥。结果因为随机数质量差,生成的公钥居然落在了弱曲线上。攻击者轻松算出了私钥。从那以后,我每次生成密钥都会做一次「密钥对一致性测试」。
密钥存储:
私钥不能明文存 Flash。我建议用以下方式:
- 加密存储:用设备唯一 ID 或用户口令加密私钥。
- 安全元件:如果成本允许,用 ATECC608A 这类专用芯片。
- OTP 区域:一次性可编程区域,防止被读出。
| 存储方式 | 安全性 | 成本 | 适用场景 |
|---|---|---|---|
| Flash 明文 | 低 | 低 | 仅用于测试 |
| Flash 加密 | 中 | 低 | 大多数消费类产品 |
| 安全元件 | 高 | 中 | 金融、车规 |
| OTP | 高 | 低 | 一次性烧录 |
4.3 性能瓶颈分析:哪里最慢?
非对称加密在嵌入式上,慢是常态。但到底慢在哪?我拿 RSA-2048 签名做个分析:
- 模幂运算:占了 90% 以上的时间。说白了就是
a^b mod n。 - 素性检测:生成密钥时,找素数很慢。Miller-Rabin 算法要跑很多轮。
- 点乘运算:ECC 里,
k * G是核心。用 Montgomery 阶梯法能防侧信道攻击,但会慢一些。
优化建议:
- 使用硬件加速器:很多 MCU 内置 RSA/ECC 协处理器。比如 NXP LPC55xx 系列。
- 预计算:对于固定公钥,可以预计算一些中间结果。比如 ECC 的固定点乘。
- 选择合适曲线:ECC 用 Curve25519 比 P-256 快很多,而且更安全。
- 减少模运算次数:用 Barrett 约减或 Montgomery 约减代替直接取模。
// 示例:使用硬件加速器(伪代码)
// 假设 MCU 有 RSA 硬件模块
void rsa_sign_hw(const uint8_t *hash, uint8_t *signature) {
// 1. 将数据加载到硬件寄存器
RSA_LoadMessage(hash);
RSA_LoadPrivateKey(&private_key);
// 2. 启动硬件运算
RSA_StartSign();
// 3. 等待完成(通常用中断或轮询)
while (!RSA_IsDone());
// 4. 读取结果
RSA_ReadSignature(signature);
}
我的经验: 在 STM32H7 上,用硬件 RSA 加速器做一次签名只需要 5ms,而纯软件需要 200ms。差了 40 倍!所以,选 MCU 时一定要看有没有硬件加速。
嗯,这里要注意一点:硬件加速器虽然快,但往往只支持特定算法。比如有些只支持 RSA-1024,不支持 RSA-2048。选型时一定要确认清楚。
最后,我想说:非对称加密移植,不是简单的「复制-粘贴-编译」。你得理解大数运算的原理,知道密钥怎么安全存储,还得会分析性能瓶颈。我见过太多项目,因为忽略这些细节,导致产品上市后出现安全漏洞或性能问题。希望今天的分享,能帮你少走一些弯路。