密码学基础回顾:哈希函数、非对称加密与数字签名
各位同学,在正式进入安全启动流程之前,我们得先把密码学这块地基夯实。说实话,我见过不少工程师在调试安全启动时,因为搞不清签名和加密的区别,把整个流程调得乱七八糟。今天我们就来把这几个核心概念彻底理清楚。
哈希函数:数据的「指纹」
哈希函数,说白了就是一个单向的压缩映射。你给它任意长度的数据,它给你吐出一段固定长度的摘要。这个过程不可逆——你没法从摘要反推出原始数据。
我个人习惯把哈希函数比作「数字指纹」。就像每个人的指纹是唯一的,不同数据的哈希值也几乎不可能碰撞。在安全启动中,我们最常用的是 SHA-256,它输出 256 位(32 字节)的摘要。
SHA-256 的核心特性:
- 单向性:从哈希值无法还原原始数据
- 抗碰撞性:找到两个不同数据产生相同哈希值,在计算上不可行
- 雪崩效应:输入改一个比特,输出会有一半以上的比特发生变化
我在项目中遇到过一件事:有同事想用 MD5 做固件完整性校验,结果被我一票否决了。MD5 已经被证明存在碰撞攻击,现在做安全启动,SHA-256 是底线,有些场景甚至要用 SHA-384 或 SHA-512。
实用技巧:在嵌入式平台上,硬件加速的 SHA-256 引擎通常比软件实现快 10-20 倍。选型时记得看芯片手册里有没有「HASH」或「CRYPTO」外设。
// 一个简单的 SHA-256 计算示例(使用 mbedTLS)
#include <mbedtls/sha256.h>
void compute_sha256(const uint8_t *data, size_t len, uint8_t output[32]) {
mbedtls_sha256_context ctx;
mbedtls_sha256_init(&ctx);
mbedtls_sha256_starts(&ctx, 0); // 0 表示 SHA-256,1 表示 SHA-224
mbedtls_sha256_update(&ctx, data, len);
mbedtls_sha256_finish(&ctx, output);
mbedtls_sha256_free(&ctx);
}
非对称加密:公钥与私钥的默契
非对称加密,名字听着唬人,其实核心就一句话:加密和解密用不同的钥匙。一把公开叫公钥,一把私藏叫私钥。
你想想看,如果我用私钥加密一段数据,只有对应的公钥能解开。反过来,用公钥加密的数据,也只有私钥能解开。这个特性在安全启动里太关键了——我们可以在设备里预置公钥,私钥放在安全的签名服务器上,这样就算设备被破解,攻击者也拿不到私钥。
目前主流的两大算法是 RSA 和 ECC。我做个对比表格,大家一看就明白:
| 特性 | RSA | ECC(椭圆曲线) |
|---|---|---|
| 安全性基础 | 大整数分解 | 椭圆曲线离散对数 |
| 同等安全强度密钥长度 | 2048 位 | 256 位 |
| 签名速度 | 较慢 | 较快 |
| 验签速度 | 较快 | 较慢 |
| 嵌入式资源占用 | 高(大数运算) | 低(适合 IoT 设备) |
避坑指南:我曾经在一个项目中选了 ECC P-256,结果发现某款 MCU 的硬件加速器只支持 RSA。最后只能软件实现 ECC,验签时间从预期的 5ms 变成了 200ms。所以选算法前,一定先确认硬件支持情况。
数字签名:证明「你是谁」和「没被改过」
数字签名,本质上是用私钥对数据的哈希值做加密。验证方用公钥解密,再对比哈希值。这样同时保证了两个事情:
- 完整性:数据没被篡改(哈希值对不上就说明被改了)
- 真实性:数据确实来自持有私钥的一方(公钥能解开就说明是私钥签的)
在安全启动里,流程是这样的:
- 开发阶段:对固件计算 SHA-256 哈希,然后用私钥对这个哈希签名
- 设备启动:读取固件,计算哈希,用公钥验签
- 验签通过 → 启动;验签失败 → 拒绝启动
关键点:签名不是对整个固件加密,而是对固件的哈希值加密。这样做的好处是效率高——固件可能几兆字节,但哈希只有 32 字节,签名运算量小得多。
// 使用 OpenSSL 命令行进行签名和验签(示意)
// 1. 生成私钥
openssl genpkey -algorithm RSA -out private.pem -pkeyopt rsa_keygen_bits:2048
// 2. 提取公钥
openssl rsa -pubout -in private.pem -out public.pem
// 3. 对固件签名
openssl dgst -sha256 -sign private.pem -out firmware.sig firmware.bin
// 4. 验签
openssl dgst -sha256 -verify public.pem -signature firmware.sig firmware.bin
三者关系:一张图说清楚
下面这张图展示了哈希、非对称加密和数字签名在安全启动中的协作关系。我建议你把它存下来,以后做方案设计时对照着看。
实际项目中的选择建议
说了这么多理论,最后给点实在的。我在几个量产项目里总结出来的经验:
- 资源极度受限的 MCU(比如 Cortex-M0,几十 KB Flash):用 ECC-256 + SHA-256。ECC 的密钥和签名都短,省空间。
- 性能较强的应用处理器(比如 Cortex-A 系列):RSA-2048 完全够用,而且很多芯片有硬件 RSA 加速器。
- 需要兼容现有 PKI 体系的企业级产品:RSA-2048 或 RSA-4096,因为大多数企业的 CA 证书都是 RSA 的。
一个小建议:不管选哪种算法,密钥长度一定要留余量。比如现在 SHA-256 还安全,但量子计算一旦成熟,这些算法都得换。设计时尽量把算法抽象成一层,方便以后升级。