首页 > 代码库 > 密码学之《数字签名》
密码学之《数字签名》
周六要考密码学了,恰逢身体不舒服,没心情看数字什么的,来整理整理数字签名的一点儿知识点~简简单单的几行文字,看官笑看即可~
什么是数字签名?有毛用?
数字签名主要用于对数字消息进行签名,以防消息的冒名伪造或篡改,也可以用作通信双方的身份鉴别。
为什么数字签名有这样那样的作用?
数字签名有这样几个特性:
1. 可信。任何人都可以验证签名的有效性
2. 不可伪造。除了合法的签名者,任何其他人伪造签名是困难的。
3. 不可复制。对一个消息的签名不能通过复制变成另一个消息的签名,若是复制得到,任何人都能检测出来,从而拒绝签名信息。
4. 不可篡改。一旦签名消息被篡改,任何人都可以发现消息与签名之间的不一致性。
5. 不可抵赖。签名者不能否认自己的签名。
既然数字签名这么刁扎天,那具体怎么实现呢?
数字签名的基础是公钥密码。至于公钥密码,之后再做整理。
这里介绍三种数字签名,RSA签名方案,EIGamal签名方案,DSA签名方案。
RSA签名方案过程:
1. A用保密密钥对消息m加密,密文s就是A对消息的签名
2. A将签名的消息(m,s)发给B
3. B用A的公开密钥对s进行解密,得到m‘。如果m‘=m,则为有效签名。
加密和解密的过程以及密钥的生成的过程都和RSA算法一致(细节见:http://www.cnblogs.com/kuoaidebb/p/4111865.html)
这样的签名方案有几个缺点。首先,对任意y,任何人都可以计算x=y^e mod n,任何人都可以伪造对随机消息x的签名y。其实,如果消息x1和x2的签名分别为y1,y2,任何知道x1,y1,x2,y2的人都可以伪造对消息x1x2的签名y1y2。这是因为在RSA中,Sig(x1,x2)=Sig(x1)Sig(x2).最后,是如果要加密的消息比较长,需要先对消息进行分组,然后对每组消息进行签名。这样做的后果是签名变长,签名速度变慢。解决上述问题的方法之一,是对消息进行签名之间做Hash变换,再对变换后的消息进行签名。
EIGamal签名方案过程:
1. 选取大素数p,g.p,g公开
2. 随机选取整数x作为保密密钥,1<=x<=p-2,计算公开密钥y=g^x mod p
3. 签名:秘密选取整数k(1<=k<=p-2),对消息m的签名如下:
r=g^k mod p
Sig(m)=(r, (m-xr)*k^-1 mod (p-1))
4. 签名验证:对得到的签名(r,o),如果满足如下条件,则为有效签名。
y^r * r^o = g^m mod p
DSA签名过程:
细节比较繁琐,就不仔细列举了,原理跟上面的两种差不多,唯一特殊的一点是在加密之前对明文做了hash处理。
附上python版的实现,其中hash加密用了sha-1,从git上下载了一下稍微改了一下:
dsa.py#coding:utf-8from random import randintimport mathfrom sys import exitfrom sha1 import sha1# n^-1 mod udef ExtendedEuclid(n,u): x1=y2=1 x2=y1=0 if n>u: x3,y3=[n,u] else: x3,y3=[u,n] while 1: if y3==0: return x3+u elif y3==1: return y2+u q=x3/y3 t1,t2,t3=[x1-q*y1,x2-q*y2,x3-q*y3] x1,x2,x3=[y1,y2,y3] y1,y2,y3=[t1,t2,t3]def cal_g(p,q): h=randint(1,p-1) temp=h ** ((p-1)/q) % p if temp > 1: return temp; else: cal_g(p,q)if __name__==‘__main__‘: p=839 q=419 g=cal_g(p,q) message=raw_input(‘请输入要加密的消息内容: ‘) x = int(raw_input(‘请选择密钥,0~%d之间任意整数: ‘ %(q))) y = g ** x % p print "公开参数如下:p:%d,q:%d,g:%d,y(公钥):%d" %(p,q,g,y) print "当前的私钥为:x:%d" %(x) k = randint(0,q) r = g ** k %p % q; s = ( ExtendedEuclid(k,q) * ( (long(sha1(message),16)+x*r)%q ) )%q; print("签名结果为:(r,s):(%d,%d)" %(r,s)) w = ExtendedEuclid(s,q); u1 = long(sha1(message),16)*w % q u2 = r*w % q if (g**u1 * y**u2 %p)%q == r: print "签名可用" else: print "签名不可用"sha1.py#coding:utf-8import structdef _left_rotate(n, b): return ((n << b) | (n >> (32 - b))) & 0xffffffff def sha1(message): h0 = 0x67452301 h1 = 0xEFCDAB89 h2 = 0x98BADCFE h3 = 0x10325476 h4 = 0xC3D2E1F0 original_byte_len = len(message) original_bit_len = original_byte_len * 8 message += b‘\x80‘ #填充一位1 message += b‘\x00‘ * ((56 - (original_byte_len + 1) % 64) % 64) # 填充0到第448位 message += struct.pack(b‘>Q‘, original_bit_len) #最后64位填充前消息长度的前64位 for i in range(0, len(message), 64): # every range for 512 byte w = [0] * 80 for j in range(16): w[j] = struct.unpack(b‘>I‘, message[i + j*4:i + j*4 + 4])[0] for j in range(16, 80): w[j] = _left_rotate(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1) a = h0 b = h1 c = h2 d = h3 e = h4 for i in range(80): if 0 <= i <= 19: f = d ^ (b & (c ^ d)) k = 0x5A827999 elif 20 <= i <= 39: f = b ^ c ^ d k = 0x6ED9EBA1 elif 40 <= i <= 59: f = (b & c) | (b & d) | (c & d) k = 0x8F1BBCDC elif 60 <= i <= 79: f = b ^ c ^ d k = 0xCA62C1D6 a, b, c, d, e = ((_left_rotate(a, 5) + f + e + k + w[i]) & 0xffffffff, a, _left_rotate(b, 30), c, d) h0 = (h0 + a) & 0xffffffff h1 = (h1 + b) & 0xffffffff h2 = (h2 + c) & 0xffffffff h3 = (h3 + d) & 0xffffffff h4 = (h4 + e) & 0xffffffff return ‘%08x%08x%08x%08x%08x‘ % (h0, h1, h2, h3, h4)
参考资料:
《现代密码学》第二版 陈鲁生等著
密码学之《数字签名》