我正在参与掘金创作者训练营第6期,点击了解活动详情
前言:
这是上学期密码学课程的期末课设,我用的是python进行实现,记录一下。
任务:
实现DSA签名算法
要求:
一.密钥p生成规则
写一个质数p选择方法,找到大于自己的电话号码的最小质数作为p。或者利用网上工具找到这个质数p。
二.哈希函数
代码实现MD5或者sha系列算法并运用到DSA签名和验证过程中。
三.密钥生成
1. p:由要求一返回;
2. q:p-1的素因子;
3. g:g=h^((p-1)/q)modp,h满足h<p-1,h^((p-1)/q) modp>1;
4. x:生成随机数x,x<q,x为私钥;
5. y:y=g^x mod p,( p, q, g, y )为公钥;
四.签名过程
1. 计算e=h(M),哈希函数使用MD5或者sha系列
2. 生成随机数k
3. r = ( g^k mod p ) mod q
4. s = ( k^(-1) (H(m) + xr)) mod q
五.验证过程
1. w = s^(-1)mod q
2. u1 = ( H( m ) * w ) mod q
3. u2 = ( r * w ) mod q
4. v = (( g^u1 * y^u2 ) mod p ) mod q
5. v=r 返回true 否则返回false
六.输入输出内容
输入消息为“姓名:,学号:”,输出公私钥P,h,g,x,y,r,v的值和验证结果。输出对消息进行哈希函数加密的结果,并在网上找工具进行哈希加密结果验证。
实现:
我使用python来实现DSA算法。
1.首先我们用网上工具找到p,我这里p=17879681719;
def getP():
p = 17879681719
return p
2.找到q,q为p-1的素因子,利用网上质因分解工具,取q=41;
def getQ():
q = 41
return q
3.在计算出g之前,我们先要得到h,因为要求h要有自己的特色,所以我取我名字拼音首字母的ASCII码之和作为h,h=347;
def getH():
h = ord('x') + ord('y') + ord('j')
return h
注:这里ord方法就是得到字符ASCII码的数值。
4.计算出g,g=h^((p-1)/q)modp,g=2635837319;
def getG(p,q,h):
g = pow(h,(p-1)//q,p)
return g
注:这里pow方法是python中快速计算幂取模的方法,基本上可以很快计算出结果。
5.生成私钥x,我这里取x为大于3小于q的随机数;
def getX(q):
x = random.randrange(3,q)
return x
注:random.randrange()用于生成随机数,可以指定范围。
6.计算公钥y,y=g^x mod p;
def getY(g,x,p):
#y=g^x mod p
y = pow(g,x,p)
return y
7.封装MD5,方便后面调用;
def md5(str):
m = hashlib.md5()
m.update(str.encode('utf-8'))
return m.hexdigest()
8.扩展欧几里得求逆元;
def exgcd(a, b):
if b == 0:
return 1, 0, a
else:
x, y, q = exgcd(b, a % b)
x, y = y, (x - (a // b) * y)
return x, y, q
def modReverse(a,p):
x, y, q = exgcd(a,p)
if q != 1:
raise Exception("无解")
else:
return (x + p) % p #防止负数
注:写个方法扩展欧几里得求逆元方法,方便后面签名和验证过程中的调用。
9.签名过程;
def signature(mess,g,p,q,x):
e = int(md5(mess),16)
k = random.randrange(3,q)
#r = ( g^k mod p ) mod q
r = pow(pow(g,k,p),1,q)
#s = ( k^(-1) (H(m) + xr)) mod q
s = (modReverse(k,q) * (e + x * r))
return md5(mess),e,r,s
注:在完成这个课设的过程中很多同学将签名过程中的k^(-1)以及验证签名过程中的s^(-1)当成了求k和s的倒数,导致最后验证失败,这里的k^(-1)和s^(-1)其实是求k和s的逆元。
10.验证过程;
def verify(r,s,p,q,e,g,y):
#w = s^(-1)mod q
w = modReverse(s,q) % q
#u1 = ( H( m ) * w ) mod q
u1 = (e * w) % q
#u2 = ( r * w ) mod q
u2 = (r * w) % q
#v = (( g^u1 * y^u2 ) mod p ) mod q
vm1 = pow(g,u1,p)
vm2 = pow(y,u2,p)
v = ((vm1 * vm2) % p) % q
if v == r:
return v,True
else:
return v,False
11.根据需求调用这些方法;
if __name__ == '__main__':
#输入信息
mess = input('请输入姓名和学号:')
#密钥生成
p = getP()
print("p:",p)
q = getQ()
print("q:",q)
h = getH()
print("h:",h)
g = getG(p,q,h)
print("g:",g)
x = getX(q)
print("私钥x:",x)
y = getY(g,x,p)
print("公钥y",y)
mess_hash,e,r,s = signature(mess,g,p,q,x)
print("对消息进行md5加密的结果:",mess_hash)
print("r:",r)
print("s:",s)
v,res = verify(r,s,p,q,e,g,y)
print("v:",v)
print("签名验证结果:",res)
结果
这就是我们密码学期末课设的DSA签名算法的实现,和DSA签名算法又不完全一样,有一些小的改变,很多过程都是要求不是很高都简化了,可以用网上计算工具和调包的方式,所以代码量不是很多,相对来说比较简单,希望能给大家一定帮助。