密码学基础(上):对称加密与非对称加密、哈希函数、数字签名原理
各位同学,欢迎来到密码学基础的第一部分。说实话,很多做嵌入式固件的工程师,一听到“密码学”三个字就头大。我当年也一样,觉得这是数学博士才该操心的事。直到我第一次接手一个OTA升级项目,客户要求必须防篡改——嗯,从那以后,我再也不敢跳过这些基础了。
这一章,我们不讲复杂的数学公式。我会用实战的视角,把对称加密、非对称加密、哈希函数和数字签名这四块基石讲透。你不需要成为密码学家,但你需要知道它们怎么用、用在哪儿、坑在哪儿。
核心观点:固件签名的本质,就是用非对称加密+哈希函数,给固件打上一个“谁也无法伪造的防拆标签”。
2.1 对称加密:一把钥匙开一把锁
对称加密,说白了就是加密和解密用同一个密钥。就像你家里的门锁,用同一把钥匙锁门和开门。
我最早接触对称加密是在做串口固件升级的时候。那时候图省事,直接把固件用AES-128加密后传输,接收端用同样的密钥解密。简单粗暴,但问题来了——密钥怎么安全地分发给每一台设备?
常见的对称加密算法有:
| 算法 | 密钥长度 | 典型应用场景 |
|---|---|---|
| AES | 128 / 192 / 256 bit | 固件加密存储、通信加密 |
| DES / 3DES | 56 / 112 bit | 已淘汰,不建议新项目使用 |
| SM4 | 128 bit | 国密标准,国内项目常用 |
我的建议:新项目直接上AES-256。别问我为什么,我在一个遗留项目里见过还在用DES的,破解只需要几分钟。你想想看,固件被破解意味着什么?整个产品线都得召回。
对称加密最大的优势是快。在嵌入式设备上,硬件AES加速器几乎是标配,加解密一个固件包可能只需要几十毫秒。但它的致命弱点,就是密钥分发。
我曾经在一个IoT项目里,需要在生产线上给每台设备预置同一个AES密钥。结果工厂的烧录脚本被泄露了——你猜怎么着?所有设备的固件都等于裸奔。从那以后,我养成了一个习惯:能用非对称解决的问题,绝不用对称。
2.2 非对称加密:公钥和私钥,天生一对
非对称加密的出现,解决了密钥分发的世纪难题。它用一对密钥:公钥公开,私钥保密。公钥加密的数据只能用私钥解密,反过来,私钥签名的数据可以用公钥验证。
你想想看,这多适合固件签名场景?
- 私钥:放在安全的签名服务器上,只有发布人员能接触。
- 公钥:烧录在每一台设备的BootROM里,谁都能读。
常见的非对称算法:
| 算法 | 密钥长度 | 签名速度 | 验证速度 |
|---|---|---|---|
| RSA | 2048 / 4096 bit | 慢 | 较快 |
| ECDSA | 256 / 384 bit | 快 | 快 |
| Ed25519 | 256 bit | 极快 | 极快 |
| SM2 | 256 bit | 快 | 快 |
注意:RSA 1024位及以下已经被认为不安全。我在2019年审计过一个项目,对方还在用RSA-1024签名固件。我用一台普通的笔记本电脑,花了两天就找到了碰撞。别省那点算力,密钥长度就是你的安全底线。
非对称加密的缺点是慢。直接拿私钥加密整个固件包?不现实,一个10MB的固件用RSA-2048加密,可能要几分钟。所以实战中,我们从来不会直接用非对称加密去加密大数据块。
那怎么办?这就引出了哈希函数。
2.3 哈希函数:固件的数字指纹
哈希函数,你可以把它理解成给固件打一个“数字指纹”。不管你的固件是1KB还是1GB,哈希函数都能算出一个固定长度的摘要。而且,哪怕你只改了一个bit,摘要都会变得面目全非。
我个人习惯用SHA-256。为什么?因为它在安全性和性能之间取得了最好的平衡。SHA-1已经被攻破,SHA-512在低端MCU上跑起来有点吃力。
常见的哈希算法对比:
| 算法 | 输出长度 | 安全性 | 嵌入式性能 |
|---|---|---|---|
| MD5 | 128 bit | 已破解,不可用 | 快 |
| SHA-1 | 160 bit | 已破解,不可用 | 较快 |
| SHA-256 | 256 bit | 安全 | 适中 |
| SHA-3-256 | 256 bit | 安全 | 较慢(软件实现) |
| SM3 | 256 bit | 安全 | 适中 |
避坑指南:我曾经见过有人用MD5做固件完整性校验,还信誓旦旦说“够用了”。结果呢?攻击者伪造了一个固件,MD5碰撞成功,设备升级了恶意代码。从那以后,我所有项目的哈希底线就是SHA-256,谁提MD5我跟谁急。
哈希函数还有一个重要特性:不可逆。你无法从摘要反推出原始数据。这个特性在密码存储中很常用,但在固件签名中,它的作用是为签名“瘦身”。
2.4 数字签名:把哈希和私钥结合起来
好了,现在我们把前面三块拼起来,看看数字签名到底是怎么工作的。
数字签名的核心流程,其实就两步:
- 签名(在服务器端):
- 对固件计算哈希值(比如SHA-256)
- 用私钥对哈希值进行签名(比如ECDSA)
- 把原始固件 + 签名值打包在一起发布
- 验签(在设备端):
- 收到固件包后,提取签名值和原始固件
- 用同样的哈希算法计算固件的哈希值
- 用公钥解密签名值,得到原始的哈希值
- 对比两个哈希值:一致则固件可信,不一致则拒绝升级
你发现没有?我们并没有对整个固件做非对称加密,只对一个小小的哈希值(32字节)做了签名。这就是性能的秘诀。
下面这张图,把整个流程串起来了:
这个流程,就是现代固件安全更新的基石。你想想看,攻击者即使拿到了固件包,他没有私钥,就无法伪造一个合法的签名值。而公钥虽然公开,但只能用来验证,不能用来签名。
关键点:数字签名不是加密数据,而是加密数据的哈希值。这样做既保证了安全性,又兼顾了性能。我在实际项目中,用ECDSA P-256签名一个32字节的哈希值,在Cortex-M4上验签只需要不到10毫秒。
2.5 实战中的选择建议
说了这么多,到底该怎么选?我直接给结论:
- 哈希算法:无脑选SHA-256。国密项目选SM3。
- 签名算法:新项目优先选ECDSA P-256或Ed25519。RSA-2048作为备选,但密钥对生成和签名速度确实慢。
- 密钥长度:别省。256位椭圆曲线密钥的安全性,相当于3072位RSA密钥。但计算量小得多。
- 硬件加速:如果MCU支持硬件加密引擎(比如NXP的LPC系列、STM32的CRYP外设),一定要用。纯软件实现SHA-256在低端MCU上可能会吃掉几十毫秒。
血的教训:我曾经在一个项目里,为了省成本选了没有硬件哈希加速器的MCU。结果每次OTA验签要花1.2秒,用户升级时还以为设备死机了。最后不得不换方案,损失了两个月工期。硬件加速不是可选项,是必选项。