目录
- 引言
- 一、什么是ECDSA
- 二、ECDSA的基本原理
- 三、椭圆曲线
- 四、ECDSA签名生成过程
- 1、 生成私钥和公钥
- 2、签名
- 3、签名对的保存
- 五、ECDSA签名验证过程
- 六、ECDSA的安全性
- 七、篡改的消息如何被检测到
- 八、 为什么B能够知道篡改?
- 九、python代码示例
- 总结
引言
在数字通信和网络安全中,确保消息的完整性和来源的真实性至关重要。为了实现这一点,数字签名技术应运而生。ECDSA(椭圆曲线数字签名算法)
是一种基于椭圆曲线密码学的数字签名算法,与传统的RSA和DSA算法相比,提供了更高的安全性和更小的密钥长度,使得其在现代加密应用中得到了广泛应用,尤其是在SSL/TLS加密协议和区块链技术(如比特币)中。
一、什么是ECDSA
ECDSA(Elliptic Curve Digital Signature Algorithm,椭圆曲线数字签名算法)是一种基于椭圆曲线密码学(Elliptic Curve Cryptography, ECC)的数字签名算法。它与传统的数字签名算法(如RSA、DSA)相比,具有更高的安全性和较小的密钥尺寸,因此在很多现代加密协议中得到了广泛的应用,例如SSL/TLS、比特币等。
二、ECDSA的基本原理
ECDSA是基于椭圆曲线数学原理来生成和验证数字签名的。它结合了公钥密码学和散列函数,用于验证消息的完整性和来源的真实性。通过数字签名,接收方(比如B)可以验证以下两点:
消息内容未被篡改:即消息是否在传输过程中被修改。
消息来源的真实性:即该消息是否真的是由声称的发送方(比如A)发送的。
它依赖于私钥和公钥的非对称加密机制,ECDSA的过程可以分为签名和验证两个步骤。
三、椭圆曲线
椭圆曲线密码学依赖于椭圆曲线方程:
其中 a 和 b 是常数,定义了曲线的形状。
椭圆曲线的“点”可以通过以下方式进行运算:
点加法
:曲线上的两个点相加得到另一个点。
标量乘法
:将一个点与一个整数相乘,得到另一个点。这个运算是椭圆曲线密码学中的核心运算。
椭圆曲线密码学的安全性基于离散对数问题(Elliptic Curve Discrete Logarithm Problem,ECDLP),即给定椭圆曲线上的一个点 P 和一个点 Q,很难从 P 和 Q 计算岀标量 k(即 Q = kP)。
四、ECDSA签名生成过程
ECDSA的签名过程主要分为以下步骤:
1、 生成私钥和公钥
私钥(Private Key):
一个随机选择的数值 d,范围在 1 ≤ d ≤ n−1,其中n 是椭圆曲线的阶(生成元的个数)。
公钥(Public Key):
使用私钥 d 生成公钥 Q = dP,其中 P 是曲线上的一个生成元。
2、签名
①计算消息的哈希值:
使用一个安全的哈希函数(如SHA-256)对消息
M 进行哈希,得到消息的摘要 h=Hash(M)。
②选择一个随机数 k:
从 [1,n−1] 范围内随机选择一个整数 k,该值应该是私密的,不能泄露。这个随机数对于每个签名都是不同的,否则会泄漏私钥信息。
③计算签名值:
计算椭圆曲线点 R = kP,并取 r 为 R 点的横坐标的模 n 结果,即
计算
其中 k 的负一次方是 k 模 n 的乘法逆元。
④签名结果:
签名对 ( r , s) 就是最终的数字签名。
3、签名对的保存
签名对 ( r , s)
会与原始消息
一起发送给接收方。
接收方收到消息和签名后,使用发送方的公钥
进行签名验证。
五、ECDSA签名验证过程
①计算消息的哈希值
使用与签名方相同的哈希函数对收到的消息进行哈希,得到消息摘要 h=Hash(M)。
②验证签名
检查 r 和 s 是否满足 0 < r < n 和 0 < s < n,否则签名无效。
计算值
其中 P 是曲线的生成元,Q 是发送方的公钥。
最后验证
即验证r是否等于计算得到的椭圆曲线P1的横坐标。
如果验证成功,表示签名有效,消息未被篡改且来源真实。
如果验证失败,则表示签名无效,可能是消息篡改、签名被篡改,或者公钥错误。
六、ECDSA的安全性
ECDSA的安全性依赖于椭圆曲线的离散对数问题。它的主要安全性来源于以下几个方面:
离散对数难题:
给定椭圆曲线上的点 P 和点 Q = kP,从 Q 和 P 计算出标量 k 是计算上非常困难的。这个问题是ECDSA的核心,破解这个问题需要指数级的时间和计算资源。
签名的私密性:
在生成签名时,必须确保随机数 k 的私密性。如果
k 被重用或者泄露,攻击者可以通过已知的签名对恢复出私钥。
签名的唯一性:
每次签名生成时都使用不同的随机数 k,如果随机数重复或被泄漏,攻击者可以计算出私钥,从而破解整个签名系统。
七、篡改的消息如何被检测到
假设A发送的原始消息是 "Thisisatestmessage."
,并且A用私钥对它进行签名。签名基于原始消息的哈希值,并且这个签名是唯一的,绑定着消息的内容。
如果C(恶意篡改者)对消息进行篡改,改变了消息的内容(比如改成了 "Thisisatamperedmessage."
),那么当B收到这个篡改后的消息时:
B会使用A的公钥验证签名:B拿到篡改后的消息和签名,使用A的公钥进行签名验证。
签名验证失败:签名验证失败的原因是:B计算的哈希值与签名中包含的哈希值不匹配。即使签名没有被篡改(因为它是基于原始消息的哈希值生成的),但由于消息内容改变,哈希值发生了变化,因此无法通过验证。
B知道消息被篡改:由于签名验证失败,B可以得出结论,消息在传输过程中被篡改了。数字签名无法被伪造,因此B知道这条消息不再是A发来的原始消息。
八、 为什么B能够知道篡改?
数字签名依赖于消息内容。任何对消息内容的修改(即使是一个字符的改变)都会导致消息的哈希值变化。
因为数字签名是基于原始消息的哈希值
和私钥
生成的,签名本身不会随着消息内容的改变而改变
。
在验证签名时,B使用A的公钥解密签名,得到原始消息的哈希值,但B计算的是篡改后消息的哈希值,二者不同,导致签名验证失败。
这就是B能够知道消息被篡改的原因,数字签名为消息提供了一种完整性保护,确保消息内容没有被修改。
数字签名被篡改的情况
如果签名本身被篡改(比如修改了签名中的 r 或 s),B 的验证过程也会失败。因为签名的生成是基于消息内容的哈希值以及私钥的组合,一旦签名被篡改,公钥就无法验证通过。签名和消息内容是绑定的,任何对签名的篡改都会导致验证失败。
九、python代码示例
from ecdsa import SigningKey, VerifyingKey, SECP256k1
from ecdsa.util import sigencode_der, sigdecode_der
# 生成密钥对
privkey = SigningKey.generate(curve=SECP256k1) # 生成私钥
pubkey = privkey.get_verifying_key() # 获取公钥
# 原始消息
original_message = b"Thisisatestmessage."
# 1. 正常的消息和签名
print("1: 正常的消息和签名")
# 使用私钥对消息进行签名
signature = privkey.sign(original_message, sigencode=sigencode_der)
# 使用公钥验证签名
try:
pubkey.verify(signature, original_message, sigdecode=sigdecode_der)
print("签名验证成功!") # 实际结果:成功
except Exception as e:
print("签名验证失败:", e) # 实际结果:失败
# 2. 被篡改的消息和原始签名
print("\n2: 被篡改的消息和原始签名")
# 篡改消息:假设这条消息被修改成和原始消息相同
tampered_message = b"Thisisatestmessage " # 在原始消息后添加一个空格
# 使用公钥验证篡改后的消息和原始签名
try:
pubkey.verify(signature, tampered_message, sigdecode=sigdecode_der)
print("签名验证成功!") # 如果签名验证成功,输出成功
except Exception as e:
print("签名验证失败") # 如果验证失败,输出失败
# 3. 正常的消息和被篡改的签名
print("\n3: 正常的消息和被篡改的签名")
# 使用sigdecode_der解码签名为(r, s),需要提供曲线阶
r, s = sigdecode_der(signature, pubkey.curve.order) # 传入曲线阶作为order参数
tampered_signature = (r, (s + 1) % pubkey.curve.order) # 篡改签名中的s值
# 通过提取r和s来正确地使用sigencode_der
tampered_signature_der = sigencode_der(tampered_signature[0], tampered_signature[1], pubkey.curve.order)
# 使用公钥验证篡改后的签名
try:
pubkey.verify(tampered_signature_der, original_message, sigdecode=sigdecode_der)
print("签名验证成功!") # 如果签名验证成功,输出成功
except Exception as e:
print("签名验证失败") # 如果验证失败,输出失败
总结
ECDSA(椭圆曲线数字签名算法)提供了一种高效、安全的方式来验证消息的完整性和来源的真实性。通过椭圆曲线的数学原理,ECDSA能够确保签名的安全性,而其较小的密钥尺寸也使得它比传统的RSA和DSA更加高效。通过本篇代码示例,我们可以清楚地看到,ECDSA在实际应用中的工作原理,如何生成签名、如何验证签名以及如何处理消息篡改的情况。数字签名的作用不仅仅是保证消息未被篡改,还能确保消息来源的可靠性。无论是在通信加密、区块链应用,还是其他需要确保数据完整性和可信度的场景,ECDSA都提供了强有力的保障。