3、密码学基础(二):RSA算法原理、椭圆曲线密码学(ECC)简介

好,我们接着往下聊。上一章我们把哈希函数和对称加密讲透了,这一章要啃两块硬骨头——RSA 和 ECC。说实话,这两者在固件签名验证里是绝对的主角。你去看市面上任何一款支持 OTA 的物联网芯片,签名算法不是 RSA 就是 ECC,几乎没有例外。

我个人习惯是先理解数学原理,再去看工程实现。别怕,我不会给你推公式推到睡着。咱们用工程师的视角,把这两个算法「拆开揉碎」了讲。

3.1 RSA 算法:大数分解的数学游戏

RSA 的核心思想,说白了就是一句话:两个大质数相乘很容易,但把乘积分解回两个质数极难。你想想看,给你两个 1024 位的质数 p 和 q,计算机算 n = p × q 只要几毫秒。但反过来,给你一个 2048 位的 n,让你找出 p 和 q——嗯,用目前最好的算法,也得算到宇宙毁灭。

这就是 RSA 的安全根基。我当年第一次接触这个思想时,觉得这简直是个数学魔术。

3.1.1 密钥生成流程

RSA 的密钥对生成,我建议你记住这五个步骤。在嵌入式开发中,我们通常是在 PC 端生成密钥对,然后把公钥烧进设备固件里。

  1. 选两个大质数:p 和 q,长度至少 1024 位(实际中常用 2048 位)
  2. 计算 n:n = p × q,n 就是密钥长度
  3. 计算欧拉函数 φ(n):φ(n) = (p-1) × (q-1)
  4. 选公钥指数 e:通常取 65537(0x10001),这个值有工程上的讲究
  5. 计算私钥 d:d ≡ e⁻¹ mod φ(n),即 e 关于 φ(n) 的模逆元

关键点:公钥是 (e, n),私钥是 (d, n)。公钥公开,私钥绝对保密。在 OTA 场景中,签名方(服务器)持有私钥,验证方(设备)持有公钥。

3.1.2 签名与验证过程

RSA 签名和加密其实是「镜像操作」。签名用私钥,验证用公钥。我在项目中遇到过不少新手搞反了,结果签名验证死活过不去。

操作 输入 计算 输出
签名 消息 m,私钥 d s = md mod n 签名值 s
验证 消息 m,签名 s,公钥 e m' = se mod n 若 m' == m,验证通过

实际工程中,我们不会直接对固件做 RSA 签名——固件动不动几 MB,RSA 算起来太慢了。正确的做法是:先对固件做哈希,再对哈希值做 RSA 签名。这个我在上一章提过,这里再强调一遍。

工程经验:RSA-2048 在 Cortex-M4 上做一次签名验证大约需要 50-100ms。如果设备对启动时间有严格要求(比如汽车 ECU),这个延迟必须提前评估。

3.1.3 填充方案:PKCS#1 v1.5 vs PSS

直接做 RSA 签名是不安全的。为什么?因为 RSA 是确定性算法,同样的输入永远得到同样的输出。攻击者可以利用这个特性做选择明文攻击。

所以我们需要填充方案。目前主流的有两种:

  • PKCS#1 v1.5:老牌方案,实现简单,但理论上存在一些攻击面。我在 2017 年的一个项目中用过,当时芯片的加密库只支持这个。
  • PSS(Probabilistic Signature Scheme):新标准,引入了随机数,安全性更高。现在新设计的系统我建议直接用 PSS。

避坑指南:我曾经在一个 OTA 项目中,因为用了 PKCS#1 v1.5 且没有做额外的随机化处理,被安全审计打回来重做。从那以后,只要芯片支持,我一律用 PSS。

3.2 椭圆曲线密码学(ECC):更小的密钥,同等的安全

ECC 是 RSA 的「后浪」。它用更短的密钥长度,提供和 RSA 同等级别的安全性。你想想看,RSA-2048 和 ECC-256 的安全强度差不多,但 ECC 的密钥只有 256 位,计算量也小得多。这对嵌入式设备来说,简直是天赐之物。

3.2.1 椭圆曲线的数学直觉

ECC 的数学基础是椭圆曲线上的点群运算。别被「椭圆曲线」这个名字吓到,它和椭圆没有半毛钱关系。标准方程是:

y² = x³ + ax + b

这条曲线上的点构成一个群。两个点相加得到第三个点,这个「加法」有几何意义——做切线、找交点、取对称点。嗯,听起来有点绕,但实际工程中我们只需要调用现成的库函数。

ECC 的安全性建立在「椭圆曲线离散对数问题」上:给定基点 G 和公钥 Q = kG,求私钥 k 几乎不可能。这比 RSA 的大数分解问题更难破解。

3.2.2 ECDSA 签名算法

在固件签名中,ECC 最常用的签名算法是 ECDSA(Elliptic Curve Digital Signature Algorithm)。它的流程比 RSA 复杂一些,但安全性更高。

ECDSA 签名过程:

  1. 生成随机数 k,计算点 R = kG
  2. 取 R 的 x 坐标作为 r
  3. 计算 s = k⁻¹ × (hash(m) + d × r) mod n
  4. 签名值为 (r, s)

验证过程:

  1. 检查 r 和 s 是否在有效范围内
  2. 计算 w = s⁻¹ mod n
  3. 计算 u₁ = hash(m) × w mod n,u₂ = r × w mod n
  4. 计算点 P = u₁G + u₂Q
  5. 若 P 的 x 坐标等于 r,验证通过

注意:ECDSA 的随机数 k 必须每次不同且绝对保密。如果 k 泄露,私钥 d 可以直接算出来。2010 年索尼 PS3 的签名被破解,就是因为用了固定的 k 值。这个坑,千万别踩。

3.2.3 曲线选择:NIST P-256 与 Curve25519

ECC 的曲线参数选择至关重要。不同的曲线,安全性和性能差异很大。目前主流的有两条:

特性 NIST P-256 Curve25519
密钥长度 256 位 255 位
安全强度 ≈ RSA-3072 ≈ RSA-3072
性能 较快 更快(常数时间)
专利 有(部分已过期) 无(开源友好)
侧信道防护 需额外实现 天然抗侧信道

我个人更倾向于 Curve25519(Ed25519 签名)。原因很简单:它实现简单,天然抗侧信道攻击,而且没有专利包袱。我在一个智能门锁项目中用过 Ed25519,在 Cortex-M0 上签名验证只要 2ms,比 RSA 快了一个数量级。

3.3 RSA vs ECC:怎么选?

这个问题我几乎在每个技术评审会上都会被问到。我的建议是:

  • 兼容性优先:如果设备需要和旧系统交互,或者芯片只支持 RSA 硬件加速,那就用 RSA-2048 + PSS 填充
  • 性能优先:如果设备资源受限(比如 8 位 MCU),或者对启动时间有严苛要求,果断上 ECC(Ed25519)
  • 安全等级:两者在合理密钥长度下都足够安全。RSA-2048 和 ECC-256 的安全等级相当,但 ECC 的密钥更短,签名也更短(64 字节 vs 256 字节)

我的经验:新项目我基本都用 ECC。原因很简单——省空间、省时间、省电。OTA 固件包每少 1KB,几百万台设备升级下来,带宽和电费都是实打实的成本。

3.4 本章知识体系

下面这张图把 RSA 和 ECC 的核心脉络梳理了一下。你可以把它当作一个快速参考。

RSA与ECC核心知识体系 RSA 与 ECC 核心知识体系 RSA 算法 大数分解难题 密钥生成 (p,q,n,e,d) 签名: s = m^d mod n 验证: m' = s^e mod n 填充: PKCS#1 / PSS 密钥长度: 2048/4096位 椭圆曲线密码学 (ECC) 离散对数难题 曲线: y² = x³ + ax + b ECDSA 签名 (r,s) ECDSA 验证 (u₁G+u₂Q) 曲线: P-256 / Curve25519 密钥长度: 256位 对比维度:安全性 ≈ RSA-2048 vs ECC-256 | 签名大小 256B vs 64B | 性能 ECC 快 5-10x 工程选型建议 兼容性要求高 → RSA-2048 + PSS 资源受限/性能敏感 → ECC (Ed25519) 新项目默认选 ECC,省空间省时间省电