RSA是第一个比较完善的公开密钥算法,它既能用于加密,也能用于数字签名。RSA的安全基于大数分解的难度。其公钥和私钥是一对大素数(100到200位十进制数或更大)的函数。从一个公钥和密文恢复出明文的难度,等价于分解两个大素数之积。
RSA的公钥、私钥的组成,以及加密、解密的公式可见于下表:
公钥KU | n: 两素数p和q的乘积 -----e: 与(p-1)(q-1)互质,1 |
---|---|
私钥KR | d: d ≡e-1 mod f(n) ----n: 两素数p和q的乘积 |
加密 | C ≡ m^e mod n |
解密 | m ≡ C^e mod n |
```python
dict = {'a':'31','b':'32','c':'33','d':'34','e':'35','f':'36','g':'37',
'h':'38','i':'39','j':'10','k':'11','l':'12','m':'13','n':'14',
'o':'15','p':'16','q':'17','r':'18','s':'19','t':'20','u':'21',
'v':'22','w':'23','x':'24','y':'25','z':'26','1':'41','2':'42',
'3':'43','4':'44','5':'45','6':'46','7':'47','8':'48','9':'49',
'0':'40',' ':'50'}
素数生成代码:
makeprime.py:
import random
from random import randint
def proBin(w): # w表示希望产生位数,生成目标位数的伪素数
list = []
list.append('1') #最高位定为1
for _ in range(w - 2):
c = random.choice(['0', '1'])
list.append(c)
list.append('1') # 最低位定为1
res = int(''.join(list),2)
return res
#幂模运算
def X_n_mod_P(base, exponent, n):
bin_array = bin(exponent)[2:][::-1]
r = len(bin_array)
base_array = []
pre_base = base
base_array.append(pre_base)
for _ in range(r - 1):
next_base = (pre_base * pre_base) % n
base_array.append(next_base)
pre_base = next_base
a_w_b = __multi(base_array, bin_array, n)
return a_w_b % n
def __multi(array, bin_array, n):
result = 1
for index in range(len(array)):
a = array[index]
if not int(bin_array[index]):
continue
result *= a
result = result % n # 加快连乘的速度
return result
def MillerRabin(a, p): #素性测试
if X_n_mod_P(a, p - 1, p) == 1:
u = (p-1) >> 1
while (u & 1) == 0:
t = X_n_mod_P(a, u, p)
if t == 1:
u = u >> 1
else:
if t == p - 1:
return True
else:
return False
else:
t = X_n_mod_P(a, u, p)
if t == 1 or t == p - 1:
return True
else:
return False
else:
return False
def testMillerRabin(p, k): # k为测试次数,p为待测奇数
while k > 0:
a = randint(2, p - 1)
if not MillerRabin(a, p):
return False
k = k - 1
return True
def makeprime(w): # 产生w位素数
while 1:
d = proBin(w)
for i in range(50): # 伪素数附近50个奇数都没有真素数的话,重新再产生一个伪素数
u = testMillerRabin(d+2*(i), 5)
if u:
b = d + 2*(i)
break
else:
continue
if u:
return b
else:
continue
if __name__ == "__main__": #测试
print(makeprime(67))
RSA生成公钥密钥解密加密过程:
RSA.py:
import time
from makeprime import makeprime
#构造字典
dict = {'a':'31','b':'32','c':'33','d':'34','e':'35','f':'36','g':'37',
'h':'38','i':'39','j':'10','k':'11','l':'12','m':'13','n':'14',
'o':'15','p':'16','q':'17','r':'18','s':'19','t':'20','u':'21',
'v':'22','w':'23','x':'24','y':'25','z':'26','1':'41','2':'42',
'3':'43','4':'44','5':'45','6':'46','7':'47','8':'48','9':'49',
'0':'40',' ':'50'}
#字符与数字之间的映射转换
def transferToNum(str):
m = ""
for d in str:
m += dict[d]
return m
def transferTostr(num):
n = ""
for i in range(0,len(num),2):
n += {value:key for key,value in dict.items()}[num[i]+num[i+1]]
return n
'''
扩展欧几里的算法
计算 ax + by = 1中的x与y的整数解(a与b互质)
'''
def ext_gcd(a, b):
if b == 0:
x1 = 1
y1 = 0
x = x1
y = y1
r = a
return r, x, y
else:
r, x1, y1 = ext_gcd(b, a % b)
x = y1
y = x1 - a // b * y1
return r, x, y
'''
超大整数超大次幂然后对超大的整数取模
(base ^ exponent) mod n
'''
def exp_mode(base, exponent, n):
bin_array = bin(exponent)[2:][::-1]
r = len(bin_array)
base_array = []
pre_base = base
base_array.append(pre_base)
for _ in range(r - 1):
next_base = (pre_base * pre_base) % n
base_array.append(next_base)
pre_base = next_base
a_w_b = __multi(base_array, bin_array, n)
return a_w_b % n
def __multi(array, bin_array, n):
result = 1
for index in range(len(array)):
a = array[index]
if not int(bin_array[index]):
continue
result *= a
result = result % n # 加快连乘的速度
return result
# 生成公钥私钥,p、q为两个超大质数
def gen_key(p, q):
n = p * q
fy = (p - 1) * (q - 1) # 计算与n互质的整数个数 欧拉函数
e = 65537 # 选取e 65537
a = e
b = fy
x = ext_gcd(a, b)[1]
if x < 0:
d = x + fy
else:
d = x
print("公钥:"+"("+str(n)+","+str(e)+")\n私钥:"+"("+str(n)+","+str(d)+")")
return (n, e), (n, d)
# 加密 m是被加密的信息 加密成为c
def encrypt(m, pubkey):
n = pubkey[0]
e = pubkey[1]
c = exp_mode(m, e, n)
return c
# 解密 c是密文,解密为明文m
def decrypt(c, selfkey):
n = selfkey[0]
d = selfkey[1]
m = exp_mode(c, d, n)
return m
if __name__ == "__main__":
print("1.生成>64位的质数p和q(以528位为例):")
p = makeprime(528)
print("p:",p)
q = makeprime(528)
print("q:",q)
print("2.生成公钥私钥")
pubkey, selfkey = gen_key(p, q)
print("3.输入明文(小写英文与数字的组合[因为只构造了这两者的字典])")
plaintext = str(input())
m = int(transferToNum(plain))
print("4.用公钥加密信息")
c = encrypt(m, pubkey)
print("密文:",c)
print("5.用私钥解密")
d = decrypt(c, selfkey)
print("明文:",transferTostr(str(d)))