2. 密码学基础回顾:对称加密与非对称加密、哈希函数、数字签名原理
做OTA安全,说白了就是跟「信任」打交道。你刷出去的固件,怎么让设备相信它是你发的?设备传回来的数据,你怎么确认没被篡改?这些问题的答案,全埋在密码学里。
我见过不少工程师,一上来就调加密库,结果密钥硬编码在代码里,或者签名验证逻辑写反了。嗯,基础不牢,后面全是坑。这一节咱们就把四个核心概念捋清楚:对称加密、非对称加密、哈希函数、数字签名。不扯太深的理论,重点是你写代码时真正用得上的东西。
2.1 对称加密:快,但密钥怎么分?
对称加密,就是加密和解密用同一把钥匙。你想想看,就像你家里大门,用一把钥匙锁上,也用同一把钥匙打开。
常见的算法有 AES(Advanced Encryption Standard)和 SM4(国密标准)。AES 的密钥长度通常是 128、192 或 256 位。我个人习惯用 AES-256-GCM,因为它除了加密还能做认证,能检测数据是否被篡改。
- 加密速度快,适合大数据量(比如固件包本身)
- 密钥管理是最大痛点——发送方和接收方必须事先共享同一个密钥
- 在OTA场景里,如果直接用对称密钥加密固件,那密钥怎么安全地发给每一台设备?
我在项目中遇到过一个问题:某团队用 AES 加密固件,然后把密钥硬编码在 Bootloader 里。结果固件被提取后,攻击者反编译 Bootloader 直接拿到了密钥。嗯,这相当于把钥匙贴在门上。
2.2 非对称加密:慢,但密钥分发简单
非对称加密用一对密钥:公钥和私钥。公钥可以公开,私钥必须保密。用公钥加密的数据,只能用对应的私钥解密;反过来,用私钥加密的数据,只能用对应的公钥解密。
常见的算法有 RSA 和 ECC(椭圆曲线密码学)。ECC 在同等安全强度下,密钥更短、计算更快。我个人更推荐 ECC,尤其是在资源受限的嵌入式设备上。
| 特性 | 对称加密 | 非对称加密 |
|---|---|---|
| 密钥数量 | 1 个(共享密钥) | 2 个(公钥 + 私钥) |
| 加密速度 | 快(适合大数据) | 慢(适合小数据) |
| 密钥分发 | 困难(需要安全通道) | 简单(公钥可公开) |
| 典型算法 | AES, SM4 | RSA, ECC (SM2) |
| OTA 典型用途 | 加密固件内容 | 加密对称密钥、数字签名 |
你想想看,在OTA场景里,我们通常怎么做?用非对称加密来传递对称密钥。设备出厂时预置服务器的公钥,服务器生成一个随机的 AES 密钥,用公钥加密后发给设备。设备用私钥解密,拿到 AES 密钥,然后用它解密固件。这叫「混合加密」,既解决了密钥分发问题,又保证了加密速度。
2.3 哈希函数:指纹,不是加密
很多人把哈希和加密搞混。哈希函数不是加密,它没有「解密」这一说。它的作用是把任意长度的数据,映射成一个固定长度的摘要(digest),就像给数据算一个「指纹」。
常见的哈希算法有 SHA-256 和 SM3。SHA-256 输出 256 位(32 字节)的摘要。好的哈希函数有几个特性:
- 单向性:从摘要反推原始数据,计算上不可行
- 抗碰撞性:很难找到两个不同的输入,产生相同的输出
- 雪崩效应:输入改一个比特,输出会变化一半左右的比特
2.4 数字签名:证明「你是谁」和「没被改过」
数字签名是非对称加密的典型应用。它的核心逻辑是:私钥签名,公钥验签。
流程是这样的:
- 服务器对固件计算哈希值
- 用服务器的私钥对这个哈希值进行签名,生成签名数据
- 服务器把固件 + 签名数据一起发给设备
- 设备用预置的公钥解密签名,得到哈希值 A
- 设备自己计算固件的哈希值 B
- 如果 A == B,说明固件确实是服务器签发的,且没有被篡改
为什么能防篡改?因为攻击者没有私钥,他无法生成一个合法的签名。他改了固件内容,哈希值就变了,用公钥验签就会失败。
常见的签名算法有 RSA-PSS 和 ECDSA。ECDSA 基于椭圆曲线,签名短、性能好,在 IoT 设备上越来越流行。国密标准对应的是 SM2 签名算法。
2.5 知识体系总览
下面这张图把四个概念的关系串起来了。你仔细看,对称加密负责「加密数据」,非对称加密负责「加密密钥」和「数字签名」,哈希函数负责「完整性校验」,数字签名负责「身份认证 + 完整性」。它们各司其职,组合起来才能构建安全的 OTA 流程。
2.6 小结:怎么选?
做 OTA 安全设计时,我的建议是:
- 固件加密:用对称加密(AES-256-GCM),速度快,能同时做认证
- 密钥交换:用非对称加密(ECC),密钥短,适合嵌入式
- 完整性校验:用哈希函数(SHA-256),简单可靠
- 身份认证:用数字签名(ECDSA),确保固件来源可信
你想想看,这四个东西组合起来,就是一套完整的 OTA 安全方案。后面几章我们会一步步把它落地到代码里。嗯,先把基础打牢,后面写代码时才不会慌。