实现RSA公钥密码设计

前言:

  自己动手实现RSA公钥密码,加强理解。

一、实验目的
  通过实际编程了解非对称密码算法RSA的加密和解密过程,加深对非对称密码算法的认识。
 
二、实验原理
  对称密码算法要求通信双方通过交换密钥实现使用同一个密钥,这在密钥的管理、发布和安全性方面存在很多问题,而非对称密码算法解决了这个问题。
  非对称密码算法是指一个加密系统的加密密钥和解密密钥是不同的,或者说不能用其中一个推导出另一个。在非对称密码算法的两个密钥中,一个是用于加密的密钥,它是可以公开的,称为公钥;另一个是用于解密的密钥,是保密的,称为私钥。非对称密码算法解决了对称密码体制中密钥管理的难题,并提供了对信息发送人的身份进行验证的手段,是现代密码学最重要的发明。
  RSA密码体制是目前为止最成功的非对称密码算法,它是在1977年由Rivest、Shamir和Adleman提出的第一个比较完善的非对称密码算法。它的安全性是建立在“大数分解和素性检测”这个数论难题的基础上,即将两个大素数相乘在计算上容易实现,而将该乘积分解为两个大素数因子的计算量相当大。虽然它的安全性还未能得到理论证明,但经过20多年的密码分析和攻击,迄今仍然被实践证明是安全的。
 
RSA算法描述如下
1.公钥
选择两个互异的大素数p和q,n是二者的乘积,即n = pq,使Ф(n)=(p-1)(q-1),Ф(n)为欧拉函数。随机选取正整数e,使其满足gcd(e,Ф(n))=1,即e和Ф(n)互质,则将(n,e)作为公钥。
2.私钥
求出正数d,使其满足e×d=l mod Ф(n),则将(n,d)作为私钥。
3.加密算法
对于明文M,由C=Me mod n,得到密文C。
4.解密算法
对于密文C,由M=Cd mod n,得到明文M。
 
如果窃密者获得了n、e和密文C,为了破解密文必须计算出私钥d,为此需要先分解n。为了提高破解难度,达到更高的安全性,一般商业应用要求n的长度不小于1024位,更重要的场合不小于2048位。

实验代码为:

#-*- coding: UTF-8 -*-
import time
import random
import numpy
import math
"""
    RSA: 公钥密码设计
    @author WQ
    @time 2020/12/7
"""
class RSA():
    """
    RSA:公钥密码设计模块
    """
    def __init__(self):
        pass
    
    def gcd(self,a,b):
        """
        判断是否互质
        """
        if(a<b):
            return self.gcd(b,a)
        while(a%b!=0):
            temp = b
            b = a%b
            a = temp
        return b 
        
    def check(self,n):
        #用1000以内的素数判断
        primes=[2,3,5,7,11,13,17,19,23,29,
                31,37,41,43,47,53,59,61,67,
                71,73,79,83,89,97,
                101,103,107,109,113,127,131,
                137,139,149,151,157,163,167,
                173,179,181,191,193,197,199,
                211,223,227,229,233,239,241,
                251,257,263,269,271,277,281,
                283,293,
                307,311,313,317,331,337,347,
                349,353,359,367,373,379,383,
                389,397,
                401,409,419,421,431,433,439,
                443,449,457,461,463,467,479,
                487,491,499,
                503,509,521,523,541,547,557,
                563,569,571,577,587,593,599,
                601,607,613,617,619,631,641,
                643,647,653,659,661,673,677,
                683,691,
                701,709,719,727,733,739,743,
                751,757,761,769,773,787,797,
                809,811,821,823,827,829,839,
                853,857,859,863,877,881,883,887,
                907,911,919,929,937,941,947,
                953,967,971,977,983,991,997]
        for i in range(len(primes)):
            if n%primes[i]!=0:
                continue
            else:
                return 0
        return 1
    
    def randomGeneratePrime(self,max):
        """
        随机生成伪大素数,待素性检测
        返回伪大素数
        args{
            max:生成伪大素数的位数
        }
        """
        
        prime=[]
        prime.append(1) #最高位为1
        for i in range(max-2):
            x=random.randint(0,1)
            prime.append(x)
        prime.append(1)#最低位为1,保证生成的是奇数,减少判断
        b=prime[0]
        for j in range(max-1):
            b = b << 1
            b = b + prime[j+1]
        primeNum=numpy.long(b)

        #print(primeNum)
        #self.prime=primeNum
        """
        min=max
        primeNum=random.randrange(2**min,2**(max+1))
        if self.check(primeNum):
            return primeNum
        else:
            for i in range(primeNum-50,primeNum+50):
                if self.check(i):
                    return i
                    break
                if i==primeNum+49:
                    primeNum=primeNum+50
        """
        return primeNum

    def Fermat(self,a,n,p):
        """
            利用费马定理过滤一遍 a(n-1)=1 mod n
            返回1则是伪素数
            args{
                a :正整数
                n :a的指数
                p :待检测的伪素数
            }
        """
        if n == 0:
            return 1
        res = self.Fermat((a * a) % p, n >> 1, p)
        if n & 1 == 1:#判断最后一位是否为1
            res = (res * (a)) % p # a是较小数,a%p的结果就是本身
        return res

    def MillerRabin(self,p,num=10):
        """
            概率检测算法(素性检测)
            args{
                num:测试次数
                p:待检测的大数
            }
        """ 
        """
        u=p-1
        t=0
        while u&1==0:#p-1=u*2^t
            t+=1
            u>>=1
        #print(u,t)
        for i in range(num):#随机生成a的次数,即测试次数
            a=random.randint(1,p-1)%(p-1)+1
            x=self.modExp(a,u,p)
            for j in range(t):
                y=self.modMul(x,x,p)
                if y==1 and x!=1 and x!=(p-1):
                    return False
                x=y
            if x!=1:
                return False
        return True
        """
        n=p
        if n<2:
            return False
        if n<=3:
            return True
        binstr = bin(n-1)[2:]
        for i in range(num):
            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 checkPrime(self):
        """
        判断伪素数是否是素数
        """
        num=int(input("请输入Miller-Rabin测试次数:"))
        max=int(input("请输入生成素数的位数[二进制]:"))
        print("生成素数中.....")
        self.primes=[]
        while True:
            flag=self.randomGeneratePrime(max)#生成大数的位数
            a=random.randint(1,flag-1)%(flag-1)+1
            #if self.Fermat(a,flag-1,flag)==1:
            if self.MillerRabin(flag,num):
                print("第一个素数:",flag)
                break
        self.primes.append(flag)
        for i in range(flag-50,flag+50,2):
            if self.MillerRabin(i,num):
                print("第二个素数:",i)
                break
            if i==flag+48:
                flag=flag+50
        self.primes.append(i)    

    def getEncrypt(self):
        """
        获取加密整数e
        """
        self.Euler=(self.primes[0]-1)*(self.primes[1]-1)#欧拉函数数值
        self.n=self.primes[0]*self.primes[1]
        while True:
            e=random.randint(2,self.Euler-1)
            if self.gcd(self.Euler,e)==1:
                print("加密e为:",e)
                break
        self.e=e

    def getDecrypt(self):
        """
        获取解密整数d
        """
        '''
        while True:
            d=random.randint(2,self.Euler-1)
            if self.modMul(d,self.e,self.Euler)==1:
                print("解密d为:",d)
                break
        '''
        print("求解密d中......")
        def EX_GCD(a,b,arr): #扩展欧几里得
            if b == 0:
                arr[0] = 1
                arr[1] = 0
                return a
            g = EX_GCD(b, a % b, arr)
            t = arr[0]
            arr[0] = arr[1]
            arr[1] = t - int(a / b) * arr[1]
            return g
        def ModReverse(a,n): #ax=1(mod n) 求a模n的乘法逆x
            arr = [0,1,]
            gcd = EX_GCD(a,n,arr)
            if gcd == 1:
                return (arr[0] % n + n) % n
            else:
                return -1
        self.d=ModReverse(self.e,self.Euler)
        print("解密d为:",self.d)

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

    def Encrypt(self,plains):
        """
        args{
            plain:明文字符串
        }
        """
        self.cipher=[]
        for i in plains:
            p=ord(i)
            c=self.modExp(p,self.e,self.n)
            self.cipher.append(c)
    
    def Decrypt(self,ciphers):
        """
        args{
            ciphers:密文
        }
        """
        self.plain=''
        for i in ciphers:
            p=self.modExp(i,self.d,self.n)
            #print(p)
            try:
                self.plain+=chr(p)
            except:
                print("素数生成有问题")
        
if __name__ == "__main__":
    test=RSA()
    #a=test.Fermat(2,14,15)
    start=time.time()
    test.checkPrime()
    end1=time.time()#生成素数
    test.getEncrypt()
    end2=time.time()#e
    test.getDecrypt()
    end3=time.time()#d
    test.Encrypt("Please wait for me")
    end4=time.time()#加密
    test.Decrypt(test.cipher)
    end5=time.time()#解密
    print("生成素数的时间为:{}s".format(end1-start))
    print("生成素数的为:{} {}".format(test.primes[0],test.primes[1]))
    print("欧拉函数值为:{}\n取模值n为:{}".format(test.Euler,test.n))
    print("公钥({},{}),求公钥耗时:{}s".format(test.e,test.n,end2-end1))
    print("私钥({},{}),求私钥耗时:{}s".format(test.d,test.n,end3-end2))
    print("密文为:{},加密耗时:{}s".format(test.cipher,end4-end3))
    print("明文为:{},解密耗时:{}s".format(test.plain,end5-end4))
    print("总耗时为:{}s".format(end5-start))


#8943511469690708878495871358393120874584858158494120398337103045514885735186193593497005721567421916104588339960615263476876332733329016140284907989985227
#8834603692731858011407808343161681717604563645297801351838933705414675843090248154015519362747932270922501975371797309454973789060216497349484403527624709
#e77743410707974079725214406228001980857751787403734221971320133965255661632642182270085894225853173761669275150071789205655028159642130891060408320054794324979796041166990189003073273185616816332341761876104683755346671679258088918659834013462851473306473364858449424324936779060849682458882352211968430591315

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

小结:
  通过此次实验了解了RSA公钥密码的设计,理解了RSA密码的原理-(基于大数分解的)。加密较短数据时RSA比DES耗时短,加密长数据时RSA耗时较长。

  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值