前言:
自己动手实现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耗时较长。