本篇为资料整理
数字签名算法
常见的数字签名算法主要有RSA、DSA、ECDSA三种。
RSA数字签名算法
RSA是目前计算机密码学中最经典算法,也是目前为止使用最广泛的数字签名算法,RSA数字签名算法的密钥实现与RSA的加密算法是一样的,算法的名称都叫RSA。密钥的产生和转换都是一样的,包括在售的所有SSL数字证书、代码签名证书、文档签名以及邮件签名大多都采用RSA算法进行加密。
RSA数字签名算法主要包括MD和SHA两种算法,例如我们熟知的MD5和SHA-256即是这两种算法中的一类。
DSA数字签名算法
DSA全称Digital Signature Algorithm,DSA只是一种算法,和RSA不同之处在于它不能用作加密和解密,也不能进行密钥交换,只用于签名,所以它比RSA要快很多,其安全性与RSA相比差不多。DSA的一个重要特点是两个素数公开,这样,当使用别人的p和q时,即使不知道私钥,你也能确认它们是否是随机产生的,还是作了手脚。RSA算法却做不到。
DSA的整个签名算法流程如下:
- 发送方使用SHA-1和SHA-2编码将发送内容加密产生数字摘要;
- 发送方用自己的专用密钥对摘要进行再次加密得到数字签名;
- 发送方将原文和加密后的摘要传给接收方;
- 接收方使用发送方提供的密钥对进行解密 ,同时对收到的内容用SHA-1/SHA-2编码加密产生同样的摘要;
- 接收方再将解密后的摘要和4步骤中加密产生的摘要进行比对,如果两者一至,则说明传输过程的信息没有被破坏和篡改,否则传输信息则不安全。
ECDSA椭圆曲线数字签名算法
ECDSA是用于数字签名,是ECC与DSA的结合,整个签名过程与DSA类似,所不一样的是签名中采取的算法为ECC,最后签名出来的值也是分为r,s。而ECC(全称Elliptic Curves Cryptography)是一种椭圆曲线密码编码学。
ECDH每次用一个固定的DH key,导致不能向前保密(forward secrecy),所以一般都是用ECDHE(ephemeral)或其他版本的ECDH算法。ECDH则是基于ECC的DH(Diffie-Hellman)密钥交换算法。
ECC与RSA 相比,有以下的优点:
- 相同密钥长度下,安全性能更高,如160位ECC已经与1024位RSA、DSA有相同的安全强度。
- 计算量小,处理速度快,在私钥的处理速度上(解密和签名),ECC远 比RSA、DSA快得多。
- 存储空间占用小 ECC的密钥尺寸和系统参数与RSA、DSA相比要小得多, 所以占用的存储空间小得多。
- 带宽要求低使得ECC具有广泛得应用前景。
以太坊中使用了第三方库libsecp256k1来实现ECDSA,libsecp256k1可以看作是一个经过优化的secp256k1实现库,率先应用于比特币中,指定的曲线方程为 y^2 = x^3 + 7,形状如下图所示:
<div align="center"><img src="https://en.bitcoin.it/w/images/en/b/bf/Secp256k1.png" width="280"></div>
盲签名
前文说到了数字签名,但如果A想要B来对消息签名,但是又不想让B知道该消息的内容,该如何做呢?这里就需要用到盲签名了。
盲签名具有以下特点:
- 签名者对其所签署的消息是不可见的,即签名者不知道他所签署消息的具体内容。
- 签名消息不可追踪,即当签名消息被公布后,签名者无法知道这是他哪次的签署的。
传统RSA加解密的结局方案为:
-
加密:
-
解密:
而盲签名则按照如下步骤来进行:
-
接收者首先将待签数据进行盲变换,把变换后的盲数据发给签名者。
这里一般用对称加密,所以:
-
经签名者签名后再发给接收者。
-
接收者对签名再作去盲变换,得出的便是签名者对原数据的盲签名。
流程如下:

在这个过程中,B无法得知MSG是什么,B也不知道自己什么时候对MSG做了签名,即若B进行了多次签名,当公布出某一具体的MSG-signature时,B并不知道这个签名是自己在那一次进行签署的。
背景:
一般的签名,签名者对自己发出的签名,必须是记得的,比如,在何时何地对谁发的,他自己可以记下来。但是,如果把签名看作是电子现金的话,就涉及到一个匿名性的问题用实际钞票的时候,钞票上有没有写你的名字?当然没有。那我也不希望,银行通过追踪自己发出签名,来获得用户的消费情况。于是就设计出盲签名。
多重签名
多重签名技术(multisig)就是多个用户同时对一个数字资产进行签名才有效。
如果一个地址只能由一个私钥签名和支付,表现形式就是1/1;而多重签名的表现形式是m/n,也就是说一共n个私钥可以给一个账户签名,而当m个地址签名时,就可以支付一笔交易。所以,m一定是小于等于n的。
群签名
在一个群签名方案中,一个群体中的任意一个成员可以以匿名的方式代表整个群体对消息进行签名。与其他数字签名一样,群签名是可以公开验证的,而且可以只用单个群公钥来验证。
流程:
- 初始化:群管理者建立群资源,生成对应的群公钥(Group Public Key)和群私钥(Group Private Key)群公钥对整个系统中的所有用户公开,比如群成员、验证者等。
- 成员加入:在用户加入群的时候,群管理者颁发群证书(Group Certificate)给群成员。
- 签名:群成员利用获得的群证书签署文件,生成群签名.
- 验证:同时验证者利用群公钥仅可以验证所得群签名的正确性,但不能确定群中的正式签署者。
- 打开:群管理者利用群私钥可以对群用户生成的群签名进行追踪,并暴露签署者身份。
环签名
是一种简化的群签名,只有环成员没有管理者,不需要环成员间的合作。环签名方案中签名者首先选定一个临时的签名者集合,集合中包括签名者。然后签名者利用自己的私钥和签名集合中其他人的公钥就可以独立的产生签名,而无需他人的帮助。签名者集合中的成员可能并不知道自己被包含在其中。
环签名满足的性质
- 无条件匿名性: 攻击者无法确定签名是由环中哪个成员生成,即使在获得环成员私钥的情况下,概率也不超过1/n。
- 正确性: 签名必需能被所有其他人验证。
- 不可伪造性: 环中其他成员不能伪造真实签名者签名,外部攻击者即使在获得某个有效环签名的基础上,也不能为消息m伪造一个签名。
环签名实现
- 密钥生成: 为环中每个成员产生一个密钥对(公钥PKi,私钥SKi)。
- 签名: 签名者用自己的私钥和任意n个环成员(包括自己)的公钥为消息m生成签名a。
- 签名验证: 验证者根据环签名和消息m,验证签名是否为环中成员所签,如果有效就接收,否则丢弃。
环签名和群签名的比较
- 匿名性:都是一种个体代表群体签名的体制,验证者能验证签名为群体中某个成员所签,但并不能知道为哪个成员,以达到签名者匿名的作用。
- 可追踪性:群签名中,群管理员的存在保证了签名的可追踪性。群管理员可以撤销签名,揭露真正的签名者。环签名本身无法揭示签名者,除非签名者本身想暴露或者在签名中添加额外的信息。提出了一个可验证的环签名方案,方案中真实签名者希望验证者知道自己的身份,此时真实签名者可以通过透露自己掌握的秘密信息来证实自己的身份。
- 管理系统:群签名由群管理员管理,环签名不需要管理,签名者只有选择一个可能的签名者集合,获得其公钥,然后公布这个集合即可,所有成员平等。
算法实现
import os, hashlib, random, Crypto.PublicKey.RSA
class ring:
def __init__(self, k, L=1024):
self.k = k
self.l = L
self.n = len(k)
self.q = 1 << (L - 1)
def sign(self, m, z):
self.permut(m)
s = [None] * self.n
u = random.randint(0, self.q)
c = v = self.E(u)
for i in (range(z+1, self.n) + range(z)):
s[i] = random.randint(0, self.q)
e = self.g(s[i], self.k[i].e, self.k[i].n)
v = self.E(v^e)
if (i+1) % self.n == 0:
c = v
s[z] = self.g(v^u, self.k[z].d, self.k[z].n)
return [c] + s
def verify(self, m, X):
self.permut(m)
def _f(i):
return self.g(X[i+1], self.k[i].e, self.k[i].n)
y = map(_f, range(len(X)-1))
def _g(x, i):
return self.E(x^y[i])
r = reduce(_g, range(self.n), X[0])
return r == X[0]
def permut(self, m):
self.p = int(hashlib.sha1('%s' % m).hexdigest(),16)
def E(self, x):
msg = '%s%s' % (x, self.p)
return int(hashlib.sha1(msg).hexdigest(), 16)
def g(self, x, e, n):
q, r = divmod(x, n)
if ((q + 1) * n) <= ((1 << self.l) - 1):
rslt = q * n + pow(r, e, n)
else:
rslt = x
return rslt
签名并验证两个由4个用户组成的环签名消息:
size = 4
msg1, msg2 = 'hello', 'world!'
def _rn(_):
return Crypto.PublicKey.RSA.generate(1024, os.urandom)
key = map(_rn, range(size))
r = ring(key)
for i in range(size):
s1 = r.sign(msg1, i)
s2 = r.sign(msg2, i)
assert r.verify(msg1, s1) and r.verify(msg2, s2) and not r.verify(msg1, s2)
网友评论