DSA签名
基本流程
生成密钥
- 选择一个合适的哈希函数,目前一般选择 SHA1,当前也可以选择强度更高的哈希函数 H。
- ^选择密钥的长度^ L 和 N,这两个值决定了签名的安全程度。在最初的 DSS(Digital Signature Standard )中建议 L 必须为 64 的倍数,并且512≤L≤1024 ,当然,也可以更大。N 必须大小必须不大于哈希函数 H 输出的长度。
- 选择 N 比特的素数 q。
- 选择 L 比特的素数 p,使得 p-1 是 q 的倍数。
- 选择满足 g^k^≡1modp的最小正整数 k 为 q 的 g,即在模 p 的背景下,ord(g)=q 的 g。即 g 在模 p 的意义下,其指数次幂可以生成具有 q 个元素的子群。这里,我们可以通过计算g=h$$\frac{p-1}{q}$$modp 来得到 g,其中1<h<p−1 。
- 选择私钥 x,0<x<q ,计算y≡g^x^modp 。
公钥为 (p,q,g,y),私钥为 (x)。
进行签名
- 选择随机整数数 k 作为临时密钥,0<k<q0<k<q 。
- 计算r≡(g^k^modp)modq
- 计算s≡(H(m)+xr)k^−1^modq
签名结果为 (r,s)。H(m)为明文的哈希值。
验证过程
- 计算辅助值,w=s^−1^modq
- 计算辅助值,u1=H(m)wmodq
- 计算辅助值,u2=rwmodq
- 计算v=(g^u1^y^u2^modp)modq
- 如果 v 与 r 相等,则校验成功。
题型总结
1,已知随机密钥k
已知k时,我们就可以根据s≡(H(m)+xr)k^−1^modq 推出x≡r^−1^(ks−H(m))modq,一般这类题的H都会给出。
2,多个签名使用相同密钥k
举个栗子[]
1 | #!/usr/bin/env python |
显然是一个经典的复用k的情况,但是做了一点小小的升级
注意看这一段
1 | def sign(message, pubkey, privkey): |
原版dsa的sign中k = pow(y, x, g) % q
而此题k = pow(y, x, g) * random.randrange(1, 512) % q
乘了一个随机数。(其实可以直接穷举爆出来的)
那么来一点小小的推导吧
两组数据,则有两个表达式,如下
k1s1 = (H(M1)+xr1) mod q
k2s2 = (H(M2)+xr2) mod q
同时也有
k1 = (y^x^ mod g * random1) mod q
k2 = (y^x^ mod g * random2) mod q
k1,k2表达式,将随机数移到左边
k1 * random1^-1^ = (y^x^ mod g) mod q
k2 * random2^-1^ = (y^x^ mod g) mod q
所以得到:k1 * random1^-1^ = k2 * random2^-1^
此式子缺乏x,需要引入含有x的表达式,ks = (H(M)+xr) mod q,两边同时乘以s1s2
k1 * random1^-1^ * s1s2 = k2 * random2^-1^ * s1s2
式子也等价于
H(M1)random1^-1^ s2 + xr1random1^-1^ * s2 = H(M2)random2^-1^ s1 + xr2random2^-1^ * s1
再化简
H(M1)random1^-1^ s2 * random2 + xr1random1^-1^ * s2 * random2 = H(M2) * s1 + xr2s1
移项
H(M1)random1^-1^ s2 * random2 - H(M2) * s1 = xr2s1 - xr1random1^-1^ * s2 * random2
x = H(M1)random1^-1^ s2 * random2 - H(M2) * s1 / (r2s1 - r1random1^-1^ * s2 * random2)
除法改成乘法的逆即可
1 | from Crypto.Util.number import * |
虽然但是随机数好像要爆蛮久……
3,不同次签名使用的k存在线性关系
找了半天没看到合适的例题,只有拿Dexter佬的水一水捏
1 | import hashlib |
附上丑丑的推导
1 | from Crypto.Util.number import * |
还有的题型遇到了再补上叭……