数字签名算法实现

一、实验目的
  掌握利用Hash算法对要传送信息提取消息摘要的方法,理解数字签名的作用及数字签名算法的工作原理,了解多种非对称加密算法都可以用来设计数字签名算法。综合运用前面实验掌握的知识和技术,利用C语言或Java语言设计并实现数字签名程序。
二、实验原理
  以往的文件或书信可以通过亲笔签名来证明其真实性,而通过计算机网络传输的信息则通过数字签名技术实现其真实性的验证。
数字签名目前采用较多的是非对称加密技术,其实现原理简单的说,就是由发送方利用Hash算法对要传送的信息进行计算得到一个固定位数的消息摘要值,用发送者的私有密钥加密此消息的Hash值所产生的密文即数字签名。然后将数字签名和消息一同发给接收方。接收方收到消息和数字签名后,用同样的Hash算法对消息进行计算得出新的Hash值,然后用发送者的公开密钥对数字签名解密,将解密后的结果与新的Hash值相比较,如相等则说明报文确实来自发送方。
  下面我们以DSA(Digital Signature Algorithm)为例,介绍数字签名算法。DSA源于ElGamal和Schnorr签名算法,被美国NIST采纳作为DSS(DigitalSignature Standard)数字签名标准。
DSS数字签名算法的具体实现过程见图5-1。
在这里插入图片描述
首先介绍DSS算法的主要参数:
1.全局公开密钥分量
 (1)素数P,2511<p<2512;
 (2)q是(p-1)的一个素因子,2159<q<2160:
 (3)g=h(p-1)/q mod p,其中h是整数,l<h<(p-1)。
2.私钥
 私钥x是随机或伪随机整数,其中0<x<q。
3.公钥
 y=gx mod p,(p,q,g,y)为公钥。
4.用户的随机选择数
 k为随机或伪随机整数,其中0<k<q。
基于以上参数,DSS的签名过程如下:
 r=-(gk mod p)mod q
 s=[k-1 (H(M)+xr)]mod q
则形成了对信息M的数字签名(r’,s’),数字签名和信息M一同发送给接收方。接收方接收到信息M’和数字签名(r’,s’)后,对数字签名的验证过程如下:
 w=(s’)-1 mod q
 ul=[H(M’)w]mod q,u2=(r’)w mod q
 V=[(gu1yu2)mod p]mod q
如果v=r’,则说明信息确实来自发送方。

实验代码:
DSA:数字签名和验证

#-*- coding: UTF-8 -*-
"""
    DSA:数字签名和验证
    @author WQ
    @time 2020/12/20
"""
import random
from Crypto.Hash import SHA
import math
class DSA():
    """
    签名和验证
    """
    def __init__(self):
        pass
    
    def Globalpublickey(self):
        """
            p:满足2^(L-1)<p<2^L的大素数 其中512<=L<=1024 且L为64的倍数
            q:p-1的素因子,满足2^159<2^160,即q长160比特
            g:g=h^((p-1)/q)mod p,h是满足1<h<p-1且h^((p-1)/q)mod p>1的任意整数
        """
        n=160#q的长度
        while True:
            Q=random.randrange(2**(n-1)+1,2**n-1,2)
            if self.MillerRabin(Q):
                self.q=Q
                break 
        while True:
            i=random.randint(0,8)#满足L是64的倍数
            L=512+i*64
            k=random.randint((2**(L-160)-2**(L-163)),(2**(L-160)+2**(L-163)))
            p=k*self.q+1
            if self.MillerRabin(p):
                self.p=p
                break
        while True:
            h=random.randint(2,self.p-2)
            #print("shdjsa",(self.p-1)//self.q,k)
            g=self.modExp(h,(self.p-1)//self.q,self.p)
            if g>1:
                self.g=g
                break
    
    def UserKey(self):
        x=random.randint(1,self.q-1)
        self.x = x #Usersecret
        self.y=self.modExp(self.g,self.x,self.p) #Publickey
    
    def MillerRabin(self,n):#素数检测算法
        """
        判断一个数是否是素数,使用Miller-Rabin概率检测法
        n:待检验的数
        a:小于n的数
        如果n暂时测试为素数,则返回true
        """
        if n<2:
            return False
        if n<=3:
            return True
        binstr = bin(n-1)[2:]
        for i in range(8):
            a = random.randint(2, n)
            d = 1
            for i in binstr:
                x = d
                d = d*d%n
                if d==1 and x!=1 and x!=n-1:
                    return False
                if i=='1':
                    d = d*a%n
            if d!=1:
                return False
        return True

    def modExp(self,a,b,n):
        """
        快速幂取模,a^b%n
        args{
            a:底数
            b:指数
            n:取模数
        }
        """
        ans=1
        while b:
            if b&1:
                ans=self.modMul(ans,a,n)
            a=self.modMul(a,a,n)
            b>>=1
        return ans
        
    def modMul(self,a,b,n):
        """
        快速积取模,a*b%n
        args{
            a:乘数
            b:乘数
            n:取模数
        }
        """
        ans=0
        while b:
            if b&1:
                ans=(ans+a)%n
            a=(a+a)%n
            b>>=1
        return ans

    def Inverse(self, a,mod):
        #求秘钥a的逆元 欧几里得算法   
        x1,x2,x3 = 1,0,mod
        y1,y2,y3 = 0,1,a
        while(1):
            if(y3==0):
                g=x3
                break
            if(y3==1):
                g=y3
                break
            q=math.floor(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
        if y2<0:
            y2+=mod
        return y2   #逆元求得为y2,y3为gcd(a,26),最大公因数 

    def signature(self):
        self.k=random.randint(1,self.q-1)
        self.k_Reverse=self.Inverse(self.k,self.q)
        print("用户为待签消息选取的秘密数k:",self.k)
        print("秘钥数k的逆元:",self.k_Reverse)
        choice=int(input("请选择待签数据类型-对字符串签名[0],对文件签名[1]:"))
        if choice==0:
            message=input("请输入待签消息:")
            self.data=message
            Hash=SHA.new(message.encode("utf8")).hexdigest()
            self.Hash=int(Hash,16)
            self.r=self.modExp(self.g,self.k,self.p)%self.q
            self.s=self.modMul(self.k_Reverse,self.Hash+self.x*self.r,self.q)
            print("用户对消息的签名为:(r,s)\nr:{}\ns:{}".format(self.r,self.s))
            
        elif choice==1:
            filename=input("请输入文件:")
            with open(filename,'rb') as fp:
                if not fp:
                    print("请输入正确文件名!")
                    exit(0)
                data=fp.read()
            self.data=data
            Hash=SHA.new(data).hexdigest()
            self.Hash=int(Hash,16)
            self.r=self.modExp(self.g,self.k,self.p)%self.q
            self.s=self.modMul(self.k_Reverse,self.Hash+self.x*self.r,self.q)
            print("用户对消息的签名为:(r,s)\nr:{}\ns:{}".format(self.r,self.s))
        
        return choice
    
    def verification(self,message,flag=0):
        if flag==0:
            Hash=SHA.new(message.encode("utf8")).hexdigest()
        elif flag==1:
            Hash=SHA.new(message).hexdigest()
        #print("验证",message,Hash)
        #print("签名",self.data,hex(self.Hash).replace("0x",""))
        Hash=int(Hash,16)
        print("接受到的消息的哈希值:",Hash)
        w=self.Inverse(self.s,self.q)
        u1=self.modMul(Hash,w,self.q)
        u2=self.modMul(self.r,w,self.q)
        v=self.modMul(self.modExp(self.g,u1,self.p),self.modExp(self.y,u2,self.p),self.p)%self.q
        #v1=hex(v).replace("0x","")
        #print("v:",v1,len(v1))
        #print("r:",hex(self.r).replace("0x",""))
        #print(len(str(bin(self.q).replace("0b",""))),len(str(bin(self.p).replace("0b",""))))
        #print(v,self.r)
        if v==self.r:
            print("签名有效!")
        else:
            print("签名无效!")
              
if __name__ == "__main__":
    test=DSA()
    test.Globalpublickey()
    test.UserKey()
    print("全局公开钥\nP:{}\nQ:{}\nG:{}".format(test.p,test.q,test.g))
    print("用户密钥\n秘密钥x:{}\n公开钥y:{}".format(test.x,test.y))
    opntion=test.signature()
    print("消息哈希值为",test.Hash)
    test.verification(test.data,opntion)
    while True:
        flag=input("是否继续验证?[y][n]:")
        if flag.lower()=='y':
            #opntion=int(input("验证签名的消息类型-[0]字符串[1]文件:"))
            #test.signature()
            if opntion==0:
                message=input("验证消息:")
                test.verification(message)
            elif opntion==1:
                filename=input("请输入文件:")
                with open(filename,'rb') as fp:
                    if not fp:
                        print("请输入正确文件名!")
                        continue
                    data=fp.read()
                test.verification(data,opntion)
        elif flag.lower()=='n':
            break

运行结果为:
在这里插入图片描述

  • 8
    点赞
  • 68
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值