密码学基础回顾:哈希、非对称加密与数字签名
做 Bootloader 安全启动,说白了就是解决三个问题:怎么证明固件没被改过?怎么证明固件是官方发的?怎么防止别人伪造你的固件?这三个问题的答案,都藏在密码学里。
我刚开始接触安全启动时,觉得密码学就是一堆数学公式,离工程很远。后来踩了几次坑才明白——不理解这些基础,你连芯片的 Secure Boot 文档都读不懂。今天咱们就把这三个核心概念掰开揉碎,讲清楚。
2.1 哈希算法:固件的「指纹」
哈希算法,你可以把它理解成给数据算一个「指纹」。不管你的固件是 1KB 还是 1GB,算出来的哈希值都是固定长度。而且只要改一个 bit,哈希值就完全变了。
SHA256 是目前最常用的哈希算法,输出 256 位(32 字节)。我个人习惯在 Bootloader 里只用 SHA256,SHA1 已经不安全了,SHA512 又太慢,256 刚刚好。
- 单向性:从哈希值反推原始数据,计算上不可行
- 抗碰撞性:找不到两个不同的输入,产生相同的哈希值
- 雪崩效应:输入微变,输出剧变
在 Bootloader 里,哈希的典型用法是这样的:
// 计算固件镜像的 SHA256 哈希
uint8_t hash[32];
SHA256_CTX ctx;
sha256_init(&ctx);
sha256_update(&ctx, firmware_image, firmware_size);
sha256_final(&ctx, hash);
// 将计算出的哈希与存储的参考哈希比较
if (memcmp(hash, stored_hash, 32) == 0) {
// 固件完整性校验通过
} else {
// 固件被篡改,拒绝启动
}
2.2 非对称加密:公钥与私钥的配对
非对称加密,说白了就是两把钥匙:一把公开(公钥),一把私藏(私钥)。公钥加密的数据只能用私钥解密,私钥签名的数据只能用公钥验证。
在 Bootloader 场景里,我们几乎不用非对称加密来做数据加密,而是用它来做签名验证。为什么?因为公钥可以公开放在芯片里,私钥留在服务器上,这样任何人都能验证签名,但只有你才能签名。
目前主流的选择有两个:RSA 和 ECC。
| 特性 | RSA (2048位) | ECC (256位) |
|---|---|---|
| 安全强度 | 112 位 | 128 位 |
| 密钥长度 | 2048 位 | 256 位 |
| 签名速度 | 较慢 | 较快 |
| 验签速度 | 较快 | 较慢 |
| 资源占用 | 高 | 低 |
我个人更倾向 ECC,尤其是在资源受限的 MCU 上。256 位的 ECC 密钥,安全性和 3072 位的 RSA 差不多,但计算量和存储空间都小得多。不过要注意,ECC 的验签比 RSA 慢,如果你的 Bootloader 对启动时间要求极高,可能需要权衡。
2.3 数字签名:给固件盖上「官方印章」
数字签名,就是把哈希和非对称加密结合起来。流程很简单:
- 对固件计算 SHA256 哈希
- 用私钥对哈希值进行签名
- 把签名附加到固件上
验证时,Bootloader 做三件事:
- 计算固件的 SHA256 哈希
- 用公钥解密签名,得到原始哈希
- 比较两个哈希是否一致
你想想看,如果攻击者篡改了固件,哈希值就变了,用公钥解密签名得到的还是原来的哈希,两者不匹配,启动失败。如果攻击者想用自己的私钥签名,但 Bootloader 里存的是你的公钥,验签照样失败。
- 完整性:固件没有被篡改
- 真实性:固件确实来自持有私钥的合法发布者
下面这张图展示了完整的签名与验证流程:
2.4 密钥管理:安全启动的命门
算法选得再好,密钥管不好,一切都是白搭。我在项目里见过太多「安全启动」被攻破的案例,问题都出在密钥管理上。
几个关键原则:
- 私钥永远不出服务器:签名操作在离线的 HSM(硬件安全模块)或专用签名服务器上完成
- 公钥要烧死在芯片里:用 eFuse 或 OTP(一次性可编程)存储器,烧进去就改不了
- 密钥要有生命周期:产品量产前用测试密钥,量产后换生产密钥,退役后要能吊销
2.5 小结
哈希、非对称加密、数字签名,这三个东西是 Bootloader 安全启动的基石。哈希保证完整性,非对称加密提供密钥分离,数字签名把两者结合起来,形成完整的信任链。
记住一句话:签名在服务器,验签在芯片,密钥在硬件。这个原则贯穿整个安全启动设计。