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位
python源代码:
'''
args = {
name:RSA加解密
author:Lsy
date:2020-11-30
}
'''
import random
import math
def pow_mod(a, q, n):
'''
args={
幂模运算,快速计算(a^q) mod (n)
a:底数
q:指数
n:模数
返回结果d
}
'''
d = 1
while q:
if q & 1: # 如果q & 1=1,那么其二进制形式的最后一位等于1
d = (d * a) % n
q >>= 1 # 每一轮右移一位,就能得出其二进制每位是0还是1
a = (a * a) % n
return d
# 素数检测算法
def MillerRabin(n, a):
'''
判断一个数是否是素数,使用Miller-Rabin概率检测法
n:待检验的数
a:小于n的数
如果n暂时测试为素数,则返回true
'''
binstr = bin(n - 1)[2:]
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 GetBigPrime(num): # num代表位数
'''
args={
获取大素数
num:输入十进制的位数
返回大素数p
}
'''
while 1:
p = random.randrange(10 ** (num - 1) + 1, 10 ** num, 2)
for i in range(50):
for j in range(8): # 进行8轮Miller-Rabin概率检测法,就能够大概率判断此数为素数
a = random.randint(2, p)
if MillerRabin(p, a) == False:
break
elif j == 7:
return p
p = p + 2 # 如果生成的数不是素数,则向后加2依次判断,直至50次后重新生成另一个数
if p > 10 ** num:
break
def gcd(a, b):
'''
args = {
欧几里得算法求最大公约数
返回最大公约数
}
'''
while a != 0:
a, b = b % a, a
return b
# 求逆元函数
def GetInverse(a, b):
'''
args = {
求某个数的逆元
a:需要求逆元的密钥
a与b大者为模数,另一个为密钥
y2:返回该秘钥的逆元
}
'''
if a < b:
a, b = b, a
x1 = 1
x2 = 0
x3 = a
y1 = 0
y2 = 1
y3 = b
while 1:
q = x3 // y3
temp1 = y1
temp2 = y2
temp3 = y3
y1 = x1 - q * temp1
y2 = x2 - q * temp2
y3 = x3 - q * temp3
x1 = temp1
x2 = temp2
x3 = temp3
if y3 == 1:
break
if y2 < 0:
y2 = (y2 + a) % a
return y2
def GetKey(num):
'''
args = {
生成密钥
num:生成素数的位数,十进制位数
返回值:
p:第一个大素数
q:第二个大素数
n:p*q
-n:欧拉函数值
e:公钥
d:私钥
}
'''
p = GetBigPrime(num)
while 1:
q = GetBigPrime(num)
if p != q:
break
n = p * q
_n = (p - 1) * (q - 1)
while 1:
e = random.randint(2, _n) # e的值随机生成
if gcd(e, _n) == 1:
break
# e = 65537
d = GetInverse(_n, e)
return p, q, n, _n, e, d
def Encrypt(m, e, n):
'''
args = {
加密函数
m:需要加密的数字字符串
e:公钥
n:公钥
返回密文,列表形式
}
'''
c = []
l = math.floor(math.log(n, 10))
# l = 8
print("分组长度:" + str(l))
for i in range(math.ceil(len(m) / l)):
c.append(str(pow_mod(int(m[i * l:l * (i + 1)].ljust(l, '0')), e, n)))
return c
def Decrypt(c, d, n):
'''
args = {
解密函数
c:需要解密的密文,列表形式
d:私钥
n:私钥
返回解密后的数字字符串
}
'''
m = ''
l = math.floor(math.log(n, 10))
for cc in c:
x = str(pow_mod(int(cc), d, n)).zfill(l)
m += x
return m
def Change(plaintext):
'''
args = {
将字符串转换成数字字符串
plaintext:需要转换的字符串
返回数字字符串
其中:" ":"00","a":"01","b":"02","c":"03"......"z":"26"
}
'''
m = ''
plaintext = plaintext.lower()
for i in plaintext:
if i == " ":
m += "00"
else:
m += str(ord(i) - 96).zfill(2)
return m
def InverseChange(m):
'''
args = {
逆置换,将数字字符串转换成字符串
m:数字字符串
返回转换后的字符串
}
'''
plaintext = ''
for i in range(len(m) // 2):
if m[i * 2:(i + 1) * 2] == "00":
# plaintext+=" "
continue
else:
plaintext += chr(int(m[i * 2:(i + 1) * 2]) + 96)
return plaintext
if __name__ == "__main__":
num = int(input("请输入产生素数的长度:"))
p, q, n, _n, e, d = GetKey(num)
print("产生的第一个素数p为:" + str(p))
print("产生的第二个素数q为:" + str(q))
print("n=" + str(n))
print("_n=" + str(_n))
print("公钥为:(" + str(e) + "," + str(n) + ")")
print("私钥为:(" + str(d) + "," + str(n) + ")")
plaintext = input("请输入需要加密的明文:")
ciphertext = Encrypt(Change(plaintext), e, n)
print("加密后的密文:" + str(ciphertext))
cipher = []
cipher.append(input("请输入需要解密的密文:"))
plaintext = Decrypt(cipher, d, n)
print("解密后的明文" + InverseChange(plaintext))