RSA与椭圆曲线数字签名实战解析
数字签名基本概念与原理
数字签名是一种基于公钥密码学的技术,用于验证数字信息的真实性、完整性和不可否认性。其核心思想是发送方使用其私钥对消息的摘要(哈希值)进行加密,生成签名;接收方使用发送方的公钥对签名进行解密,并将解密结果与接收方自己计算的消息摘要进行比对,若一致则验证通过。
一个完整的数字签名方案包含签名生成和签名验证两个核心过程:
- 签名生成:发送方对原始消息
M计算哈希值h = Hash(M),然后使用其私钥SK对哈希值进行特定运算(如加密或转换)得到签名Sig。 - 签名验证:接收方收到消息
M‘和签名Sig‘。首先计算M‘的哈希值h‘ = Hash(M‘),然后使用发送方的公钥PK对签名Sig‘进行逆向运算,得到结果h‘’。最后比较h‘和h‘’,若相等则验证成功,证明消息确实来自声称的发送方且未被篡改。
数字签名必须满足三个关键特性:
- 真实性:接收者能确认签名来自特定的发送者。
- 完整性:接收者能验证消息在传输过程中未被篡改。
- 不可否认性:发送者事后无法否认自己签发的消息。
数字签名实现方案对比分析
根据底层数学难题的不同,主流的数字签名方案可分为基于大数分解、基于离散对数和基于椭圆曲线离散对数三类。下表详细对比了它们的代表算法、原理、特点及应用场景。
| 方案类别 | 代表算法 | 核心数学难题 | 基本原理概述 | 密钥长度(同等安全强度) | 主要特点 | 典型应用场景 |
|---|---|---|---|---|---|---|
| 基于大数分解 | RSA-PSS | 大整数分解难题(RSA问题) | 利用模幂运算,私钥签名,公钥验证。 | 2048-4096位 | 算法原理简单,应用历史久,但密钥长、计算慢。 | SSL/TLS证书、软件签名、传统PKI系统。 |
| 基于离散对数 | DSA, ElGamal | 有限域上的离散对数难题 | 在模p的乘法循环群上运算,签名过程包含随机数,安全性依赖其随机性。 | 2048-3072位 | 由NIST制定标准,签名长度固定(320位)。 | 美国政府早期标准,部分遗留系统。 |
| 基于椭圆曲线离散对数 | ECDSA, EdDSA | 椭圆曲线上的离散对数难题(ECDLP) | 在椭圆曲线点群上进行标量乘法运算,私钥为整数,公钥为曲线点。 | 256-384位 | 密钥短、性能高、带宽占用小,同等安全下优势明显。 | 区块链(比特币、以太坊)、现代TLS、物联网设备、移动安全。 |
核心方案技术原理与代码示例
1. 基于RSA的签名方案
RSA签名直接利用RSA加密算法,将私钥用于“加密”(签名),公钥用于“解密”(验证)。更安全的实践是采用RSA-PSS等填充方案。其签名过程可简述为:签名 = (Hash(M))^d mod n,其中(d, n)为私钥;验证过程为:验证 Hash(M) ?= (签名)^e mod n,其中(e, n)为公钥。
以下为使用Pythoncryptography库实现RSA-PSS签名的示例:
from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.asymmetric import padding, rsa from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat # 1. 密钥生成 private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048) public_key = private_key.public_key() # 2. 签名生成 message = b"Important message for RSA-PSS signing" signature = private_key.sign( message, padding.PSS( mgf=padding.MGF1(hashes.SHA256()), salt_length=padding.PSS.MAX_LENGTH ), hashes.SHA256() ) # 3. 签名验证 try: public_key.verify( signature, message, padding.PSS( mgf=padding.MGF1(hashes.SHA256()), salt_length=padding.PSS.MAX_LENGTH ), hashes.SHA256() ) print("RSA-PSS 签名验证成功!") except Exception: print("RSA-PSS 签名验证失败!")2. 基于离散对数的签名方案(以DSA为例)
DSA是ElGamal签名方案的变体,其安全性依赖于有限域上离散对数的计算难度。签名过程需要引入一个随机数k,若k重复或可预测将导致私钥泄露。
DSA签名的核心步骤如下:
- 全局参数:大素数
p、q(q整除p-1)、生成元g(g^q ≡ 1 mod p)。 - 密钥生成:私钥
x为随机整数(1 < x < q),公钥y = g^x mod p。 - 签名生成:对消息哈希
h,选择随机数k,计算r = (g^k mod p) mod q,s = (k^{-1} * (h + x*r)) mod q,签名对为(r, s)。 - 签名验证:计算
w = s^{-1} mod q,u1 = h*w mod q,u2 = r*w mod q,v = (g^{u1} * y^{u2} mod p) mod q,若v == r则验证通过。
3. 基于椭圆曲线的签名方案(以ECDSA为例)
ECDSA是DSA在椭圆曲线群上的模拟,是目前最主流的方案之一。它依赖于椭圆曲线离散对数问题(ECDLP)的难解性。
ECDSA核心流程:
- 椭圆曲线参数:定义一条椭圆曲线(如secp256k1)及其基点
G,阶为n。 - 密钥生成:私钥
d为随机整数(1 < d < n-1),公钥Q = d * G(椭圆曲线标量乘法)。 - 签名生成:
- 计算消息哈希
e = Hash(M),转换为整数。 - 生成随机数
k(1 < k < n-1)。 - 计算点
(x1, y1) = k * G。 - 计算
r = x1 mod n,若r=0则重选k。 - 计算
s = k^{-1} * (e + d * r) mod n,若s=0则重选k。 - 签名为
(r, s)。
- 计算消息哈希
- 签名验证:
- 检查
r, s是否在[1, n-1]范围内。 - 计算
e = Hash(M)。 - 计算
w = s^{-1} mod n。 - 计算
u1 = e * w mod n,u2 = r * w mod n。 - 计算点
(x1, y1) = u1 * G + u2 * Q。 - 验证
r == x1 mod n是否成立。
- 检查
以下为使用Pythonecdsa库实现ECDSA的示例:
import ecdsa import hashlib # 1. 选择曲线并生成密钥对(此处使用secp256k1,即比特币所用曲线) private_key = ecdsa.SigningKey.generate(curve=ecdsa.SECP256k1) public_key = private_key.get_verifying_key() # 2. 签名生成 message = b"Critical transaction data" signature = private_key.sign(message, hashfunc=hashlib.sha256) # 3. 签名验证 try: public_key.verify(signature, message, hashfunc=hashlib.sha256) print("ECDSA 签名验证成功!") except ecdsa.BadSignatureError: print("ECDSA 签名验证失败!")总结与方案选择建议
在区块链、物联网等现代场景中,基于椭圆曲线的签名方案(尤其是ECDSA和EdDSA)已成为事实标准。其核心优势在于:在同等安全级别下(例如128位安全强度),ECC仅需256位密钥,而RSA需要3072位,这使得ECC在计算速度、存储空间和传输带宽上具有压倒性优势,非常适合资源受限的环境。比特币和以太坊均采用ECDSA(secp256k1曲线)来签署交易,确保了整个网络的安全运行。因此,在新系统设计时,除非有特殊的兼容性要求,否则应优先考虑采用椭圆曲线数字签名方案。
参考来源
- 【区块链】深入理解椭圆曲线密码学(ECC)
- 密码学系列之七:数字签名
- 深入理解ECDSA:椭圆曲线数字签名算法的原理与应用
- 密码编码学之公钥密码学及RSA
- 零知识证明基础:数字签名
- 数字签名算法分析与Hash签名
