3、签名算法基础(下):RSA签名原理、ECDSA签名原理、SM2国密算法简介

上一节我们把哈希算法聊透了。哈希是签名的“原材料”,但真正让签名具备法律效力的,是非对称密钥体系。这一节我们深入三种主流签名算法:RSA、ECDSA 和国密 SM2。

说实话,这三种算法我都在生产环境里踩过坑。RSA 用得最广,但坑也最多;ECDSA 性能好,但参数选不对直接崩;SM2 嘛,国内合规绕不开。咱们一个一个来。

3.1 RSA 签名:经典但容易用错

RSA 签名,说白了就是“私钥加密,公钥解密”。但这里有个关键点:RSA 签名不是直接对消息加密,而是对消息的哈希值做签名运算。

核心流程:

  1. 对原始消息做哈希,得到摘要 H(M)
  2. 用私钥对 H(M) 做 RSA 签名运算,得到签名值 S
  3. 验证时,用公钥解密 S 得到 H'(M),再对比 H(M) 是否一致

我在项目中遇到过最典型的坑——填充模式选错。RSA 签名有几种填充方式,最常用的是 PKCS#1 v1.5 和 PSS。

填充模式 特点 安全性 推荐场景
PKCS#1 v1.5 兼容性好,几乎所有库都支持 有已知攻击向量(需注意实现) 旧系统兼容、跨语言调用
PSS (PKCS#1 v2.1) 概率性填充,每次签名结果不同 更高,有严格安全证明 新系统、高安全要求

我曾经踩过的坑:有一次对接银行接口,对方要求 RSA 签名,但文档没写填充模式。我默认用了 PSS,结果验签一直失败。折腾了两天,最后发现对方用的是 PKCS#1 v1.5。所以,对接外部系统时,第一件事就是确认填充模式。

另外,RSA 密钥长度也很关键。1024 位已经不安全了,业界标准是 2048 位。4096 位更安全,但签名速度会慢不少。我个人习惯,内部系统用 2048 位,对外高安全场景用 4096 位。

3.2 ECDSA 签名:短小精悍

ECDSA(椭圆曲线数字签名算法)是 RSA 的有力竞争者。它的核心优势是:同等安全强度下,密钥更短,签名更小。

举个例子:RSA 2048 位的安全强度,ECDSA 用 256 位的密钥就能达到。签名长度也从 256 字节降到 64 字节左右。这在移动端、IoT 设备上优势非常明显。

我的经验:在做支付网关时,我们对接过一家欧洲的支付公司。他们要求所有请求签名用 ECDSA P-256。一开始我不理解为什么不用 RSA,后来发现他们的 API 网关每秒要处理上万笔请求,ECDSA 的签名速度比 RSA 快 3-5 倍,而且签名体积小,网络传输也省带宽。

ECDSA 的原理稍微复杂一些。简单说,它基于椭圆曲线上的离散对数问题。签名过程会生成两个值:r 和 s。验证时用公钥和消息哈希,检查 r 和 s 是否匹配。

这里有个容易翻车的地方——随机数 k 的生成。ECDSA 签名需要一个随机数 k,如果 k 重复或者可预测,私钥就会被泄露。著名的 PlayStation 3 签名破解事件,就是因为索尼用了固定的 k 值。

避坑指南:我曾经在调试一个 ECDSA 签名库时,发现每次签名结果都一样。查了半天,原来是底层随机数生成器没初始化。所以,务必使用密码学安全的随机数生成器(CSPRNG),别用 rand() 或者时间戳。

常见的椭圆曲线有几种:

  • P-256 (secp256r1):最常用,NIST 标准,兼容性最好
  • P-384 (secp384r1):更高安全等级,但性能稍差
  • P-521 (secp521r1):超高标准,一般用不到
  • Curve25519:新兴曲线,性能极佳,但部分旧系统不支持

我个人建议,新项目优先选 P-256 或 Curve25519。前者兼容性好,后者性能更优。

3.3 SM2 国密算法:合规必选

SM2 是国家密码管理局发布的椭圆曲线公钥密码算法。它和 ECDSA 类似,但有一些关键区别。

为什么要有 SM2?说白了,就是自主可控。RSA 和 ECDSA 都是国外标准,在某些行业(金融、政务、军工)必须用国密算法。

对比项 SM2 ECDSA (P-256)
曲线参数 国密标准曲线 NIST 标准曲线
密钥长度 256 位 256 位
签名长度 64 字节 64 字节
签名流程 先计算 Z 值(用户标识+曲线参数) 直接对哈希签名
合规要求 国内金融、政务强制 国际通用

SM2 签名有个独特步骤——计算 Z 值。Z 值包含了用户标识(IDA)、曲线参数和公钥。这意味着,同一个消息,不同用户签出来的结果天然不同。嗯,这其实是个安全增强。

SM2 签名流程(简化版):

  1. 拼接 Z 值和消息 M,得到 M' = Z || M
  2. 对 M' 做哈希,得到摘要 e
  3. 用私钥对 e 做椭圆曲线签名,得到 (r, s)

我在对接某国有银行时,第一次接触 SM2。当时最大的困惑是:为什么同样的消息,每次签名结果都不一样?后来才明白,SM2 也是概率性签名,每次会生成随机数 k。

实用建议:如果项目需要对接国内金融或政务系统,尽早引入 SM2 支持。常用的密码库(如 OpenSSL 1.1.1+、GmSSL、Bouncy Castle)都支持 SM2。但要注意,不同库的 SM2 实现可能有细微差异,尤其是 Z 值的计算方式。对接前一定要做交叉验证。

3.4 三种算法对比与选型

你想想看,实际项目中怎么选?我整理了一张对比表:

维度 RSA ECDSA SM2
密钥长度 2048+ 位 256 位 256 位
签名速度 慢 快 快
验签速度 快 慢(相对 RSA) 慢(相对 RSA)
签名体积 256 字节 64 字节 64 字节
兼容性 最好 好 国内好,国际一般
合规 国际通用 国际通用 国内强制

我的选型建议:

  • 通用场景:RSA 2048 + PSS 填充,兼容性最好
  • 高性能/移动端:ECDSA P-256,签名快、体积小
  • 国内合规:SM2,没得选
  • 混合方案:同时支持 RSA 和 SM2,根据调用方切换

3.5 知识体系总览

下面这张图,把三种签名算法的核心逻辑串起来了。你可以看到,它们都基于哈希,但底层数学原理不同。

签名算法知识体系总览 哈希算法(SHA-256/SM3) RSA 签名 私钥加密哈希值 填充模式:PKCS#1 / PSS 密钥长度:2048 / 4096 位 ECDSA 签名 椭圆曲线离散对数 生成 (r, s) 签名对 曲线:P-256 / Curve25519 SM2 国密签名 先计算 Z 值(用户标识) SM3 哈希 + 椭圆曲线 国内金融/政务合规 输出:数字签名(字节数组) 三种算法均需配合哈希使用,输出固定长度的签名值

看到这张图,你应该能理解:不管底层是 RSA、ECDSA 还是 SM2,它们都离不开哈希。哈希是“原料”,私钥是“印章”,签名就是“盖了章的文件摘要”。