密码学课设——DSA算法(python实现)

691 阅读4分钟

我正在参与掘金创作者训练营第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)

结果

微信截图_20220828231007.png

这就是我们密码学期末课设的DSA签名算法的实现,和DSA签名算法又不完全一样,有一些小的改变,很多过程都是要求不是很高都简化了,可以用网上计算工具和调包的方式,所以代码量不是很多,相对来说比较简单,希望能给大家一定帮助。