一、基本原理
1.两个素数:p,q
2.n=p*q
3.欧拉函数:phi(n)=(p-1)*(q-1)
4.取数e,使得1<e<phi,且gcd(e,phi)=1,即互质
5.取数d,使得1<d<phi,且gcd(d,phi)=1,即互质
6.(e,n):公钥;(d,n):私钥
7.满足(e * d) % phi = 1,e是d的乘法逆元
二、加密,解密
1.m=c^d(mod n)
2.c=m^e(mod n)
三、有关理论
1.乘法逆元(原文链接:http://t.csdnimg.cn/rqxL4)
2.费马小定理(原文链接:费马小定理(通俗易懂) - 乾奕的文章 - 知乎
https://zhuanlan.zhihu.com/p/616185983)
3.射影定理,欧几里得定理
gcd(a, b) = gcd(b, a%b)
四、解密工具推荐
参考这篇:http://t.csdnimg.cn/FInqX
五、rsa一些题型及其脚本
1.已知p,q,e,求d
import gmpy2
p=#填入p的内容
q=#填入q的内容
n=p*q
phi_n=(p-1)*(q-1)
print(phi_n)
e=#填入e的值
d=gmpy2.invert(e,phi_n) # e*d mod phi_n = 1 e*d=1+k*phi_n
print(d)
2.已知p,q,e,c,求m
import gmpy2
p = #填入p的内容
q = #填入q的内容
n=p*q
phi_n=(p-1)*(q-1)
e = #填入e的内容
d=gmpy2.invert(e,phi_n)
c = #填入c的内容
m=gmpy2.powmod(c,d,n)
print(m)
3.已知dp,dq,p,q,c ,求m(dp,dq泄露)
import gmpy2
from Crypto.Util.number import long_to_bytes
p = #填入p的内容
q = #填入q的内容
dp =#填入dp的内容
dq = #填入dq的内容
c = #填入c的内容
I = gmpy2.invert(q, p) # q*I mod p = 1
mp = pow(c, dp, p)
mq = pow(c, dq, q)
m = (((mp-mq) * I) % p) * q + mq
print(long_to_bytes(m))
4.已知c1,c2,n,e1,e2,求m(一个n,多个e,共模攻击)
参考文章:http://t.csdnimg.cn/eC3Vk
-
e1, e2互质,即
gcd(e1, e2) = 1
import gmpy2
c1 = #填入c1值
n = #填入n值
e1 = #填入e1值
c2 = #填入c2值
e2 = #填入e2值
s = gmpy2.gcdext(e1, e2) # 拓展欧几里得算法,计算s1和s2
m1 = gmpy2.powmod(c1, s[1], n)
m2 = gmpy2.powmod(c2, s[2], n)
m = (m1 * m2) % n
print(bytes.fromhex(hex(m)[2:])) # 16进制转文本
-
e1、e2不互质
#设gcd(e1, e2) = a,得到s1 * e1 + s2 * e2 = a
即最后求得的m还需要开a次根
//
a, s1, s2 = gcdext(e1, e2)
m1 = gmpy2.powmod(c1, s[1], n)
m2 = gmpy2.powmod(c2, s[2], n)
m = (m1 * m2) % n
while True:
if iroot(m, a)[1]:
m = iroot(m, a)[0]
print(long_to_bytes(m))
break
m += n
//
5.已知e,n,dp,c,求m(dp泄露)
import gmpy2
e = #填入e的内容
n = #填入n的内容
dp = #填入dp的内容
c = #填入c的内容
for i in range(1, e): # 在范围(1,e)之间进行遍历
if (dp * e - 1) % i == 0:
if n % (((dp * e - 1) // i) + 1) == 0: # 存在p,使得n能被p整除
p = ((dp * e - 1) // i) + 1
q = n // (((dp * e - 1) // i) + 1)
phi = (q - 1) * (p - 1) # 欧拉定理
d = gp.invert(e, phi) # 求模逆
m = pow(c, d, n) # 快速求幂取模运算
print(bytes.fromhex(hex(m)[2:])) # 16进制转文本
6.公钥解析
提取p,q
脚本解密
-
简单版
import rsa
e = #填入e的内容
n = #填入n的内容
p = #填入p的内容
q = #填入q的内容
d = #填入d的内容
key = rsa.PrivateKey(n, e, d, q, p)
with open("#复制key文件路径","rb+") as f:
f = f.read()
print(rsa.decrypt(f, key))
-
复杂版(PKCS1 OAEP)
import gmpy2
from Crypto.Cipher import PKCS1_OAEP
# PKCS1 OAEP 是一种基于 RSA 和 OAEP 填充的非对称密码
from Crypto.PublicKey import RSA
e =
n =
p =
q =
phi_n = (p - 1) * (q - 1)
d = int(gmpy2.invert(e, phi_n))
rsakey = RSA.importKey(open(.key的地址,"r").read())
privatekey = RSA.construct((n, e, d, p, q))
rsa = PKCS1_OAEP.new(privatekey)
m = rsa.decrypt(open(.flag的地址,"rb").read())
print(m)
7.n+e+c+p+q= m + n分解,(Roll按行加密)(参考文章:http://t.csdnimg.cn/HtX39)
import libnum
from Crypto.Util.number import long_to_bytes
list1=[#插入flag滚动里的内容]
flag=""
n=#填入n的内容
q=#填入q的内容
p=#填入p的内容
e=#填入e的内容
for i in list1:
c=i
d = libnum.invmod(e, (p - 1) * (q - 1)) #invmod(a, n) - 求a对于n的模逆,这里逆向加密过程中计算ψ(n)=(p-1)(q-1),对ψ(n)保密,也就是对应根据ed=1modψ(n),求出d
m = pow(c, d, n) # pow(x, y[, z])--函数是计算 x 的 y 次方,如果 z 在存在,则再对结果进行取模,其结果等效于 pow(x,y) %z,对应前面解密算法中M=D(C)=C^d(mod n)
#print(m) #明文的十进制格式
string = long_to_bytes(m) # m明文,用长字节划范围
flag+=string.decode()
print(flag)
8.费马分解法
-
p,q已知素数
'''生成两个挨得近的素数p,q'''
p = getPrime(512)
q = gmpy2.next_prime(p)
#这是其特征代码
'''开始破解'''
temp=gmpy2.iroot(n,2)[0]
#iroot函数,这个函数专门用来进行大数开根号,gmpy2.iroot(n,t)。n就是大整数,t是你要开几次幂。
p=gmpy2.next_prime(temp)
q=n//p
print(p)
print(q)
-
p,q不确定是否为素数
'''生成两个挨得近的素数p,q'''
p = getPrime(512)
q = gmpy2.next_prime(p)
n=p*q
print('开始破解')
'''开始破解'''
a=gmpy2.iroot(n,2)[0]
while 1:
B2=pow(a,2)-n
if gmpy2.is_square(B2):
b=gmpy2.iroot(B2,2)[0]
p=a+b
q=a-b
print(p)
print(q)
break
a+=1
9.n,c有多个且不同(n不互素)
import gmpy2
from Crypto.Util.number import *
from Crypto.Util.number import long_to_bytes
e=
c=
n1=
n2=
#输入对应内容的值
p = gmpy2.gcd(n1,n2)
q = n1//p
phi_n = (p-1)*(q-1)
d = inverse(e,phi_n)
m = gmpy2.powmod(c,d,n1)
print(long_to_bytes(m))
10.低加密指数攻击(e特别小,一般是3)
import gmpy2
import libnum
def de(c, e, n):
k = 0
while True:
mm = c + n*k
result, flag = gmpy2.iroot(mm, e)
if True == flag:
return result
k += 1
e= 3
n=
c=
m=de(c,e,n)
print(m)
print(libnum.n2s(int(m)).decode())
11.低解密指数攻击-维纳攻击
import gmpy2
def transform(x,y): #使用辗转相处将分数 x/y 转为连分数的形式
res=[]
while y:
res.append(x//y)
x,y=y,x%y
return res
def continued_fraction(sub_res):
numerator,denominator=1,0
for i in sub_res[::-1]: #从sublist的后面往前循环
denominator,numerator=numerator,i*numerator+denominator
return denominator,numerator #得到渐进分数的分母和分子,并返回
#求解每个渐进分数
def sub_fraction(x,y):
res=transform(x,y)
res=list(map(continued_fraction,(res[0:i] for i in range(1,len(res))))) #将连分数的结果逐一截取以求渐进分数
return res
def get_pq(a,b,c): #由p+q和pq的值通过维达定理来求解p和q
par=gmpy2.isqrt(b*b-4*a*c) #由上述可得,开根号一定是整数,因为有解
x1,x2=(-b+par)//(2*a),(-b-par)//(2*a)
return x1,x2
def wienerAttack(e,n):
for (d,k) in sub_fraction(e,n): #用一个for循环来注意试探e/n的连续函数的渐进分数,直到找到一个满足条件的渐进分数
if k==0: #可能会出现连分数的第一个为0的情况,排除
continue
if (e*d-1)%k!=0: #ed=1 (mod φ(n)) 因此如果找到了d的话,(ed-1)会整除φ(n),也就是存在k使得(e*d-1)//k=φ(n)
continue
phi=(e*d-1)//k #这个结果就是 φ(n)
px,qy=get_pq(1,n-phi+1,n)
if px*qy==n:
p,q=abs(int(px)),abs(int(qy)) #可能会得到两个负数,负负得正未尝不会出现
d=gmpy2.invert(e,(p-1)*(q-1)) #求ed=1 (mod φ(n))的结果,也就是e关于 φ(n)的乘法逆元d
return d
print("该方法不适用")
e =
n =
c =
d=wienerAttack(e,n)
print("d=",d)
m = gmpy2.powmod(c,d,n)
print(long_to_bytes(m))
12.已知高位攻击(coppersmith)
需要使用到sagemath
-
已知p高位
n=
p4= #已知P的高位
e=
pbits= #P原本的位数
kbits=pbits - p4.nbits()
print p4.nbits()
p4 = p4 << kbits
PR.<x> = PolynomialRing(Zmod(n))
f = x + p4
roots = f.small_roots(X=2^kbits,beta=0.4)
# 经过以上一些函数处理后,n和p已经被转化为10进制
if roots:
p= p4 + int(roots([0]))
print ("n",n)
print ("p",p)
print ("q",n/p)