密码学基础回顾:对称加密与非对称加密、哈希函数、数字签名原理
各位好,我是老周。今天咱们聊点基础但绕不开的东西——密码学。你可能会想:“做固件签名,直接上工具链不就行了?干嘛还要啃理论?”
嗯,我当年也这么想。直到有一次,我帮客户排查一个签名验证失败的问题,折腾了两天,最后发现是哈希算法选错了。从那以后,我养成了一个习惯:动手之前,先把密码学的基本功捋一遍。
这一章,我们就来回顾一下对称加密、非对称加密、哈希函数,以及数字签名的工作原理。别担心,我不会堆公式,咱们用工程师的视角来看这些概念。
核心观点:固件签名的本质,就是用非对称加密和哈希函数,给固件打上一个“防伪标签”。你不需要成为密码学家,但必须理解这几个工具是怎么配合的。
2.1 对称加密 vs 非对称加密
先说说加密。加密这事儿,说白了就是把明文变成密文,让别人看不懂。但怎么变,就有讲究了。
2.1.1 对称加密:一把钥匙开一把锁
对称加密,顾名思义,加密和解密用的是同一把密钥。就像你家的门锁,用同一把钥匙锁门和开门。
- 优点:速度快,适合加密大量数据。比如 AES(高级加密标准),在硬件加速下,吞吐量能到几十 Gbps。
- 缺点:密钥分发是个大麻烦。你想想,如果我要给全世界的人发加密固件,我得先把密钥安全地交给每个人。这几乎不可能。
我在做 IoT 设备时,遇到过一个小型传感器项目。设备之间通信量很小,我们用了 AES-128 对称加密。密钥预置在工厂烧录阶段,还算可控。但一旦设备需要 OTA 更新,对称加密就捉襟见肘了——密钥怎么安全地传给设备?
我的经验:对称加密适合“封闭环境”,比如同一个芯片内部的 Flash 加密、或者安全元件(SE)和主控之间的通信。但在互联网上分发密钥,千万别用对称加密硬扛。
2.1.2 非对称加密:公钥和私钥,一对好搭档
非对称加密就聪明多了。它用一对密钥:公钥(Public Key)和私钥(Private Key)。公钥可以公开,私钥必须保密。
- 公钥加密,私钥解密:任何人都可以用你的公钥加密一段消息,但只有你能用私钥解密。这解决了密钥分发问题。
- 私钥签名,公钥验签:这是数字签名的核心。你用私钥给数据“盖章”,别人用你的公钥来验证这个章是不是真的。
非对称加密的典型算法有 RSA 和 ECC(椭圆曲线密码学)。RSA 基于大整数分解难题,ECC 基于椭圆曲线离散对数问题。ECC 在同等安全强度下,密钥长度更短,计算更快。我个人更偏爱 ECC,尤其是在资源受限的嵌入式设备上。
| 特性 | 对称加密 (AES) | 非对称加密 (RSA/ECC) |
|---|---|---|
| 密钥数量 | 1 个 | 2 个(公钥 + 私钥) |
| 速度 | 快(硬件加速可达 Gbps) | 慢(比对称加密慢 100-1000 倍) |
| 密钥分发 | 困难 | 容易(公钥可公开) |
| 典型用途 | 数据加密、批量加密 | 密钥交换、数字签名 |
| 嵌入式常用算法 | AES-128/256 | RSA-2048, ECDSA P-256 |
避坑指南:我曾经见过一个团队,直接用 RSA 加密整个固件包。结果设备解密花了 30 秒,用户直接退货。正确的做法是:用非对称加密交换对称密钥,然后用对称加密(如 AES)加密固件本体。这叫“混合加密”,既安全又高效。
2.2 哈希函数:数据的“指纹”
哈希函数,也叫散列函数。它能把任意长度的数据,压缩成固定长度的“摘要”(Digest)。这个摘要就像数据的指纹,独一无二。
- 单向性:从摘要反推原始数据,在计算上是不可能的。
- 抗碰撞性:很难找到两个不同的数据,拥有相同的哈希值。
- 雪崩效应:输入数据哪怕只改一个比特,输出的哈希值也会面目全非。
在固件签名中,我们最常用的哈希函数是 SHA-256。它输出 256 位(32 字节)的摘要。为什么是 SHA-256?因为它的安全性经过了长期验证,而且大多数嵌入式硬件都内置了 SHA-256 加速引擎。
关键点:哈希函数本身不是加密,它不保护数据的机密性。它的作用是“完整性校验”——确保数据没有被篡改。
举个例子。你下载了一个固件包,怎么知道它是不是原厂的?你可以计算它的 SHA-256 值,然后和官方公布的哈希值对比。如果一致,说明固件在传输过程中没有被修改。
但这里有个问题:如果攻击者同时篡改了固件和官方网页上的哈希值呢?这时候,就需要数字签名出场了。
2.3 数字签名原理:RSA 与 ECDSA
数字签名,就是把哈希函数和非对称加密结合起来,实现“认证 + 完整性 + 不可否认性”。
流程很简单,就两步:
- 签名(Sign):发送方用私钥对固件的哈希值进行加密,生成签名。
- 验签(Verify):接收方用公钥解密签名,得到哈希值,再和自己计算的哈希值对比。如果一致,签名有效。
你想想看,攻击者没有私钥,他伪造的签名无法通过公钥验证。这就保证了固件的来源可信。
2.3.1 RSA 签名
RSA 签名是最经典的数字签名算法。它的原理是:私钥持有者用私钥的指数 d 对哈希值进行模幂运算,生成签名。验证时,用公钥的指数 e 对签名做同样的运算,恢复出哈希值。
RSA 的优点是成熟、标准、支持广泛。缺点是密钥长度长(至少 2048 位),签名和验签速度慢,尤其是在没有硬件加速的 MCU 上。
# 伪代码示例:RSA 签名与验签
# 签名
hash = SHA256(firmware_data)
signature = RSA_sign(private_key, hash)
# 验签
hash_calculated = SHA256(firmware_data)
hash_recovered = RSA_verify(public_key, signature)
if hash_calculated == hash_recovered:
print("签名验证通过")
else:
print("签名无效,固件可能被篡改")
我的建议:如果你的设备主频低于 100MHz,又没有硬件 RSA 加速器,尽量别用 RSA 做签名验证。我曾经在一个 Cortex-M0 上跑 RSA-2048 验签,花了将近 2 秒,这在实际产品中是不可接受的。
2.3.2 ECDSA 签名
ECDSA(椭圆曲线数字签名算法)是 RSA 的现代替代方案。它基于椭圆曲线密码学,在同等安全强度下,密钥更短(256 位 ECC 相当于 3072 位 RSA),计算更快。
ECDSA 的签名过程涉及椭圆曲线上的点乘运算。虽然数学上比 RSA 复杂,但在嵌入式领域,它的优势非常明显:
- 密钥小:P-256 曲线的公钥只有 32 字节,私钥也是 32 字节。RSA-2048 的公钥是 256 字节。
- 签名短:ECDSA 签名通常只有 64 字节(两个 32 字节的整数 r 和 s)。RSA-2048 签名是 256 字节。
- 验签快:在支持 ECC 硬件加速的芯片上,验签时间可以控制在毫秒级。
| 对比项 | RSA-2048 | ECDSA P-256 |
|---|---|---|
| 安全强度 | 112 位 | 128 位 |
| 公钥长度 | 256 字节 | 32 字节 |
| 签名长度 | 256 字节 | 64 字节 |
| 验签速度(软件) | 慢 | 中等 |
| 验签速度(硬件加速) | 中等 | 快 |
| 嵌入式适用性 | 低(资源消耗大) | 高(适合资源受限设备) |
避坑指南:ECDSA 虽然好,但实现起来坑不少。我曾经遇到过一个案例,因为随机数生成器(RNG)质量不好,导致 ECDSA 签名时产生了相同的随机数 k,结果私钥被直接算出来了。记住:ECDSA 的随机数必须真随机,不能用伪随机数生成器凑合。
2.4 知识体系总览
为了让你更直观地理解这些概念之间的关系,我画了一张图。它展示了从原始固件到签名固件的完整流程,以及每个环节用到的密码学工具。
这张图把签名和验证两个过程放在一起对比。左边是签名方,右边是验证方。你注意看,签名方用私钥,验证方用公钥。中间通过 SHA-256 把固件“浓缩”成摘要,再对摘要进行签名或验签。