密码学基础(上):对称加密与非对称加密、哈希函数、数字签名原理
各位做固件安全的同行,咱们今天聊点实在的。密码学这东西,听起来高大上,其实说白了就是几把锁和几把钥匙的事。我在嵌入式安全这行摸爬滚打了十几年,见过太多因为密码学基础不牢,导致整个安全体系崩塌的案例。
嗯,咱们这一章不讲虚的,直接上干货。对称加密、非对称加密、哈希函数、数字签名,这四个概念是固件签名的地基。地基不稳,房子再漂亮也得塌。
对称加密:一把钥匙开一把锁
对称加密,顾名思义,加密和解密用的是同一把密钥。就像你家的门锁,用同一把钥匙锁门和开门。
我刚开始做嵌入式时,觉得对称加密太简单了,不就是 AES 吗?后来踩了坑才知道,简单的东西往往最容易出问题。
核心要点:对称加密速度快,适合大量数据加密。但密钥分发是个大麻烦——你怎么把密钥安全地交给对方?
常见的对称加密算法有:
- AES(Advanced Encryption Standard)—— 目前最主流,密钥长度 128/192/256 位
- DES(Data Encryption Standard)—— 太老了,56 位密钥,现在用暴力破解分分钟搞定
- 3DES(Triple DES)—— DES 的加强版,但效率低,不推荐新项目用
- SM4 —— 国标算法,国内项目必须考虑
我在一个 IoT 项目里遇到过这样的问题:设备固件升级包用 AES 加密,但密钥硬编码在代码里。你想想看,这跟没锁门有什么区别?反编译工具一跑,密钥就出来了。
避坑指南:我曾经见过一个团队,把 AES 密钥直接写在头文件里,还上传到了公开的 GitHub 仓库。嗯,后果可想而知。密钥必须安全存储,最好用硬件安全模块(HSM)或安全元件(SE)来保护。
非对称加密:公钥私钥,各司其职
非对称加密解决了对称加密的密钥分发难题。它用一对密钥:公钥公开,私钥保密。公钥加密的数据只能用私钥解密,反过来,私钥签名的数据可以用公钥验证。
说白了,公钥就像一把锁,谁都可以拿来锁东西;私钥就是唯一的钥匙,只有你能打开。
| 特性 | 对称加密 | 非对称加密 |
|---|---|---|
| 密钥数量 | 1 个 | 2 个(公钥 + 私钥) |
| 加密速度 | 快(适合大数据) | 慢(适合小数据) |
| 密钥分发 | 困难 | 公钥可公开 |
| 典型算法 | AES, SM4 | RSA, ECC, SM2 |
| 典型用途 | 数据加密 | 密钥交换、数字签名 |
常见的非对称算法:
- RSA —— 经典算法,基于大整数分解难题。密钥长度至少 2048 位,推荐 4096 位
- ECC(椭圆曲线密码学)—— 同等安全强度下,密钥比 RSA 短得多。256 位 ECC 约等于 3072 位 RSA
- SM2 —— 国标椭圆曲线算法,国内项目首选
个人经验:在资源受限的嵌入式设备上,我建议优先考虑 ECC。为什么?因为 RAM 和 Flash 都有限,ECC 的密钥和签名都更小,计算也更快。我在一个 STM32 项目上做过对比,同样安全等级,ECC 签名比 RSA 快了将近 10 倍。
哈希函数:数据的指纹
哈希函数,说白了就是给数据算一个「指纹」。不管输入多大,输出都是固定长度。而且,哪怕只改一个比特,指纹也会完全变样。
哈希函数有几个关键特性:
- 单向性:从哈希值无法反推出原始数据
- 抗碰撞性:很难找到两个不同数据有相同的哈希值
- 雪崩效应:输入微小变化,输出天翻地覆
常用的哈希算法:
- SHA-256 —— 输出 256 位,目前最常用
- SHA-3 —— 新一代标准,安全性更高
- SM3 —— 国标哈希算法,输出 256 位
- MD5 —— 128 位,已经不安全了,别用
注意:MD5 和 SHA-1 已经被证明存在碰撞攻击。我见过有厂商还在用 MD5 做固件完整性校验,这跟纸糊的锁没什么区别。至少要用 SHA-256。
数字签名:防伪造、防篡改、防抵赖
数字签名是非对称加密和哈希函数的组合应用。它解决了三个问题:
- 身份认证:确认签名者是谁
- 完整性:数据没有被篡改
- 不可抵赖:签名者不能否认签过名
签名过程其实很简单:
- 对原始数据计算哈希值
- 用私钥对哈希值加密,得到签名
- 把原始数据和签名一起发给对方
验证过程:
- 用公钥解密签名,得到哈希值 A
- 对收到的原始数据计算哈希值 B
- 比较 A 和 B,一致则验证通过
// 伪代码示例:固件签名与验证
// 签名端(私钥签名)
hash = SHA256(firmware_data)
signature = RSA_Sign(private_key, hash)
// 输出:firmware_data + signature
// 验证端(公钥验证)
hash_received = SHA256(firmware_data)
hash_decrypted = RSA_Verify(public_key, signature)
if (hash_received == hash_decrypted) {
printf("固件验证通过,可以升级\n");
} else {
printf("固件被篡改,拒绝升级\n");
}
为什么先哈希再签名?因为非对称加密慢。对大固件直接签名,性能扛不住。先哈希压缩成固定长度,再签名,效率高得多。这也是实际工程中的标准做法。
知识体系总览
下面这张图把本章的核心逻辑串起来了。我建议你多看几遍,理解各个概念之间的关系。
实际工程中的选择建议
做固件签名联调时,怎么选算法?我个人的经验是:
- 签名算法:优先 ECC(如 ECDSA)或 SM2。RSA 也能用,但密钥太长,嵌入式设备吃不消
- 哈希算法:SHA-256 或 SM3。别用 MD5 和 SHA-1,真的不安全
- 密钥长度:ECC 256 位起步,RSA 2048 位起步
- 国密要求:国内项目必须用 SM2 + SM3 + SM4 全套国密算法
一个小技巧:在联调阶段,可以先在 PC 上用 OpenSSL 生成测试密钥和签名,验证流程通了再移植到嵌入式平台。这样能省不少调试时间。我每次做新项目都这么干。