前几天搞ctf,遇到一道常规的rsa题目 :
import sympy
from Crypto.Util.number import *
flag = b"DASCTF{xxxxx}"
x=getPrime(1024)
p=sympy.nextprime(11*x)
q=sympy.prevprime(23*x)
n=p*q
m=bytes_to_long(flag)
e=0xe18e
print(e)
c=pow(m,e,n)
print("n=",n)
print("c=",c)
#n= 7099293997597057840121358666833837753498838275854020154482887743106000287292796543920866875062689995360025217485874831332257233130287943206444475190268445255670322843664471682348256156185175655765790452094332875022809494407318056044647005041845654843080303742522260061500210481600297956451426162674923926908156645992521694195572818623774054219194331159529364179241757932761459930262573830738911713799216140111007655256112125121081747854267340976432923900792983659847629430766080521995039114172477341269935779097804051557556063477903826454634581880779164839924381664510909546228996769947966559112620828323435423467787739
#c= 3078278882403267771557339568388950410639470501469121937324913253244013904986826470346335611174822666010160930623609201021876295254455820936788078951586549877513565571795083091146694885452347963070384765951180432581796819616400782006993357703440486783144989291310259039645268226860339316323226395210408787702054635889745582356633806087632054473023928020827581196829103923740718937874920893533975613493768492615364149440810394033176498488161704634307874672531940341631965894022899665283833912182388412943227149695408964841000543086601596551360786212024360389301448828142199899595307482885969343432562999657817232668321784
这道题的钥匙关键是
x=getPrime(1024)
p=sympy.nextprime(11*x)
q=sympy.prevprime(23*x)
n=p*q
从这里可以发现p和q有一定的关系
p=11x+t
q=23x-m
其中t和m是一个很小的量,t代表11x到下一个素数之间的差值,经过测试,通常差值在5000以内。
由于t和m很小,那么相当于
p
=
11
×
x
p=11\times x
p=11×x
q
=
23
×
x
q=23\times x
q=23×x
q
=
11
23
×
p
q=\frac{11}{23}\times p
q=2311×p
n
=
p
×
q
=
p
×
11
23
×
p
=
11
23
p
2
n=p \times q=p \times \frac{11}{23}\times p= \frac{11}{23} p^2
n=p×q=p×2311×p=2311p2
p
=
23
11
×
n
p=\sqrt{\frac{23}{11}\times n}
p=1123×n
有这个关系那么就证明,p在 23 11 × n \sqrt{\frac{23}{11}\times n} 1123×n左右浮动,于是可以写出以下代码:
import sympy
from Crypto.Util.number import *
import gmpy2
n= 7099293997597057840121358666833837753498838275854020154482887743106000287292796543920866875062689995360025217485874831332257233130287943206444475190268445255670322843664471682348256156185175655765790452094332875022809494407318056044647005041845654843080303742522260061500210481600297956451426162674923926908156645992521694195572818623774054219194331159529364179241757932761459930262573830738911713799216140111007655256112125121081747854267340976432923900792983659847629430766080521995039114172477341269935779097804051557556063477903826454634581880779164839924381664510909546228996769947966559112620828323435423467787739
pp = n*11//23
p= gmpy2.iroot(pp,2)
floating_rng=1000
for i in range(p[0]-floating_rng, p[0]+floating_rng):
q = divmod(n,i)
if q[1]==0:
print("p等于:",i,"\nq等于:",q[0])
事实证明,真实的p值在平方根上下1000之内浮动,类似的,可以解决其他类似这种知道p和q某种关系的rsa问题。
求出p,q后,解题过程 :
import libnum
import gmpy2
from Crypto.Util.number import *
p=1842637924441450658998064063974279963201497691391749603710761739729251804071657434195607292881514041836386466090902459885504202102210726839134119973707983797822067691969510912653597933390722892316816352503877596316419304279111171622418905923075098131685080061845058416898784321859891210483357866757221330352431
q=3852788387468487741541406679218949013966767900182749171395229092161162863058920089681724339661347542021535338190068779760599695304622428845462250854116693395446141537754431908275704769816966047571525100689925883207058545310868813392330439657338841548068803765676031235333821763888863440101566448674190054370069
c=3078278882403267771557339568388950410639470501469121937324913253244013904986826470346335611174822666010160930623609201021876295254455820936788078951586549877513565571795083091146694885452347963070384765951180432581796819616400782006993357703440486783144989291310259039645268226860339316323226395210408787702054635889745582356633806087632054473023928020827581196829103923740718937874920893533975613493768492615364149440810394033176498488161704634307874672531940341631965894022899665283833912182388412943227149695408964841000543086601596551360786212024360389301448828142199899595307482885969343432562999657817232668321784
#phi=(p-1)*(q-1)
e=0xe18e
#d = libnum.invmod(e,phi)
# 当e约去公约数后与phi互素
def decrypt(p, q, e, c):
n = p * q
phi = (p - 1) * (q - 1)
t = gmpy2.gcd(e, phi)
d = gmpy2.invert(e // t, phi)
m = pow(c, d, n)
print(m)
msg = gmpy2.iroot(m, t)
print(msg)
if msg[1]:
print(long_to_bytes(msg[0]))
decrypt(p,q,e,c)
输出结果:
788405031745507770194690962903400949406743404033876736594470380622736446808280639069799390802178272301446577152339579723271862025
(mpz(28078551097688565920863135908056268375491504812717619527898702205), True)
b'DASCTF{RSA_1s_Re@lly_e4sy!}'
这道题 还藏了一个小陷阱,就是题目中的e和phi不互素,所以不能直接求逆元,所以需要去除公约数(假如为g)后求逆元,但是这样做了后,最后结果需要开g次方才能得到 真实的结果 (至于为什么是开g次方,需要数学推导)。