密码学基础回顾:对称加密与非对称加密、哈希函数、数字签名原理

各位好,我是老周。今天咱们聊点基础但绕不开的东西——密码学。你可能会想:“做固件签名,直接上工具链不就行了?干嘛还要啃理论?”

嗯,我当年也这么想。直到有一次,我帮客户排查一个签名验证失败的问题,折腾了两天,最后发现是哈希算法选错了。从那以后,我养成了一个习惯:动手之前,先把密码学的基本功捋一遍。

这一章,我们就来回顾一下对称加密、非对称加密、哈希函数,以及数字签名的工作原理。别担心,我不会堆公式,咱们用工程师的视角来看这些概念。

核心观点:固件签名的本质,就是用非对称加密和哈希函数,给固件打上一个“防伪标签”。你不需要成为密码学家,但必须理解这几个工具是怎么配合的。

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

数字签名,就是把哈希函数和非对称加密结合起来,实现“认证 + 完整性 + 不可否认性”。

流程很简单,就两步:

  1. 签名(Sign):发送方用私钥对固件的哈希值进行加密,生成签名。
  2. 验签(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 知识体系总览

为了让你更直观地理解这些概念之间的关系,我画了一张图。它展示了从原始固件到签名固件的完整流程,以及每个环节用到的密码学工具。

固件签名与验证流程 固件签名与验证流程 签名方(私钥持有者) 原始固件 (Firmware) SHA-256 哈希计算 摘要 (Digest) 私钥签名 (RSA/ECDSA) 签名值 (Signature) 验证方(公钥持有者) 接收到的固件 SHA-256 哈希计算 计算出的摘要 公钥验签 + 摘要比较 验证通过 / 失败 签名值随固件一起传输 核心逻辑:私钥签名保证“不可伪造”,公钥验签保证“可验证”,SHA-256 保证“完整性”

这张图把签名和验证两个过程放在一起对比。左边是签名方,右边是验证方。你注意看,签名方用私钥,验证方用公钥。中间通过 SHA-256 把固件“浓缩”成摘要,再对摘要进行签名或验签。