之前是不想写这个wp的,但是这两天突然想起来这道题发现没有留exp,怕下次遇到,浅记一下
from sage.all import *
from secret import flag
from Crypto.Util.number import bytes_to_long
def leak(a, b):
p = random_prime(pow(2, 64))
q = random_prime(pow(2, 64))
n = p*q
e = 65537
print(n)
print((pow(a, e) + pow(b, e) + 0xdeadbeef) % n)
def gen_key():
a = randrange(0, pow(2,256))
b = randrange(0, pow(2,256))
p = pow(a, 4)
q = pow(b, 4)
rp = randrange(0, pow(2,24))
rq = randrange(0, pow(2,24))
pp = next_prime(p+rp)
qq = next_prime(q+rq)
if pp % pow(2, 4) == (pp-p) % pow(2, 4) and qq % pow(2, 4) == (qq-q) % pow(2, 4):
n = pp*qq
rp = pp-p
rq = qq-q
return n, rp, rq
n, rp, rq = gen_key()
e = 65537
c = pow(bytes_to_long(flag), e, n)
print("n =", n)
print("e =", e)
print("c =", c)
print("=======leak=======")
leak(rp, rq)
'''
n = 3183573836769699313763043722513486503160533089470716348487649113450828830224151824106050562868640291712433283679799855890306945562430572137128269318944453041825476154913676849658599642113896525291798525533722805116041675462675732995881671359593602584751304602244415149859346875340361740775463623467503186824385780851920136368593725535779854726168687179051303851797111239451264183276544616736820298054063232641359775128753071340474714720534858295660426278356630743758247422916519687362426114443660989774519751234591819547129288719863041972824405872212208118093577184659446552017086531002340663509215501866212294702743
e = 65537
c = 48433948078708266558408900822131846839473472350405274958254566291017137879542806238459456400958349315245447486509633749276746053786868315163583443030289607980449076267295483248068122553237802668045588106193692102901936355277693449867608379899254200590252441986645643511838233803828204450622023993363140246583650322952060860867801081687288233255776380790653361695125971596448862744165007007840033270102756536056501059098523990991260352123691349393725158028931174218091973919457078350257978338294099849690514328273829474324145569140386584429042884336459789499705672633475010234403132893629856284982320249119974872840
=======leak=======
122146249659110799196678177080657779971
90846368443479079691227824315092288065
'''
首先对于leak(rp,rq),可以通过某种手段,来找到rp和rq
n很小可以直接分解
首先是打表爆破:
from tqdm import tqdm
def de_leak():
n=122146249659110799196678177080657779971
p=8949458376079230661
q=13648451618657980711
e=65537
c=90846368443479079691227824315092288065
c=c-(0xdeadbeef%n)
dict={}
for rp in tqdm(range(1,2**24)):
tmp=(c-pow(rp,e,n))%n
dict[tmp]=rp
for rq in tqdm(range(1,2**24)):
tmp=pow(rq,e,n)
if tmp in dict.keys():
print(rq,dict[tmp])
break
de_leak()
得到
rp=405771
rq=11974933
网上学到了一种新方法 中间相遇攻击
假设有两个函数,加密函数E和解密函数D,k1,k2分别是两次加密使用的密钥.
那么,当用户知道一对明文和密文时
攻击者可以枚举所有的 k1,将 P 所有加密后的结果存储起来,并按照密文的大小进行排序。(设第一次加密后的密文为P1)
攻击者进一步枚举所有的 k2,将密文 C 进行解密得到 C1。比对P1和C1,如果搜索到,则我们在一定程度上可以认为我们找到了正确的 k1 和 k2
因为是两面逼近的方式获得密码所以称为中间相遇攻击。
哇塞这个不就是打表爆破吗,还以为能学到新东西!!?
知道rp和rq后,可以参考论文 A New Attack on Special-Structed RSA Primes
伪代码:
复现:
from math import ceil, floor
import gmpy2
from tqdm import tqdm
from Crypto.Util.number import long_to_bytes
rp=405771
rq=11974933
n = 3183573836769699313763043722513486503160533089470716348487649113450828830224151824106050562868640291712433283679799855890306945562430572137128269318944453041825476154913676849658599642113896525291798525533722805116041675462675732995881671359593602584751304602244415149859346875340361740775463623467503186824385780851920136368593725535779854726168687179051303851797111239451264183276544616736820298054063232641359775128753071340474714720534858295660426278356630743758247422916519687362426114443660989774519751234591819547129288719863041972824405872212208118093577184659446552017086531002340663509215501866212294702743
e = 65537
c = 48433948078708266558408900822131846839473472350405274958254566291017137879542806238459456400958349315245447486509633749276746053786868315163583443030289607980449076267295483248068122553237802668045588106193692102901936355277693449867608379899254200590252441986645643511838233803828204450622023993363140246583650322952060860867801081687288233255776380790653361695125971596448862744165007007840033270102756536056501059098523990991260352123691349393725158028931174218091973919457078350257978338294099849690514328273829474324145569140386584429042884336459789499705672633475010234403132893629856284982320249119974872840
#rp,rq=rq,rp
begin=ceil((rp*rq)^0.5)
end=floor(rq/2+2*rp+1)
for i in tqdm(range(begin,end)):
sigma=(isqrt(n)-i)^2
z=(n-rp*rq)%sigma
delta=z^2-4*sigma*rp*rq
if delta<0:
continue
if isqrt(delta)**2==delta:
x1=(z+int(isqrt(delta)))/2
p=int(n//((x1//rq+rp)))
if n%p==0:
q=n//p
break
x2=(z-int(isqrt(delta)))/2
p=int(n//((x2//rp)+rq))
if n%p==0:
q=n//p
break
phi=(p-1)*(q-1)
d=gmpy2.invert(e,phi)
m=pow(c,d,n)
print(long_to_bytes(int(m)))
下面给出不用论文的wp:
每次复现论文都不知道如何确定一个数的精度,相比之下我感觉这个方法要常规许多,也许更加符合ctf的解题思路
显然p和q要比rp和rq大许多,我们直接对n开四次方就得到了a*b
已知:
p
p
=
p
+
r
p
pp=p+rp
pp=p+rp
q
q
=
q
+
r
q
qq=q+rq
qq=q+rq
n
=
p
p
∗
q
q
=
p
q
+
p
∗
r
q
+
q
∗
r
p
+
r
p
∗
r
q
=
(
a
b
)
4
+
a
4
∗
r
q
+
b
4
∗
r
p
+
r
p
∗
r
q
n=pp*qq=pq+p*rq+q*rp+rp*rq=(ab)^4+a^4*rq+b^4*rp+rp*rq
n=pp∗qq=pq+p∗rq+q∗rp+rp∗rq=(ab)4+a4∗rq+b4∗rp+rp∗rq
所以:
n
−
(
n
4
)
4
−
r
p
∗
r
q
=
a
4
∗
r
p
+
b
4
∗
r
q
=
p
∗
r
q
+
q
∗
r
p
n-(\sqrt[4]{n})^4-rp*rq=a^4*rp+b^4*rq=p*rq+q*rp
n−(4n)4−rp∗rq=a4∗rp+b4∗rq=p∗rq+q∗rp
两边同时乘p
(
n
−
(
n
4
)
4
−
r
p
∗
r
q
)
∗
p
=
p
2
∗
r
q
+
n
∗
r
p
(n-(\sqrt[4]{n})^4-rp*rq)*p=p^2*rq+n*rp
(n−(4n)4−rp∗rq)∗p=p2∗rq+n∗rp
左边的值已知,整理得到
r
p
∗
p
2
−
t
∗
p
+
n
∗
r
p
=
0
rp*p^2-t*p+n*rp=0
rp∗p2−t∗p+n∗rp=0
求解二次方程即可得到p
import gmpy2
rp,rq=405771,11974933
n = 3183573836769699313763043722513486503160533089470716348487649113450828830224151824106050562868640291712433283679799855890306945562430572137128269318944453041825476154913676849658599642113896525291798525533722805116041675462675732995881671359593602584751304602244415149859346875340361740775463623467503186824385780851920136368593725535779854726168687179051303851797111239451264183276544616736820298054063232641359775128753071340474714720534858295660426278356630743758247422916519687362426114443660989774519751234591819547129288719863041972824405872212208118093577184659446552017086531002340663509215501866212294702743
ab=int(gmpy2.iroot(n,4)[0])
a_4,b_4=var('a_4 b_4')
r=solve([a_4*b_4-ab^4,(a_4+rp)*(b_4+rq)-n],[a_4,b_4])[1]
print(r)
# [a_4 == 70102828721558534948345339875672972694466981761923685698221464095350842567073878119031031001553580576396374042398681177813432211192009435021654721839600881033401700453496031215200878726773965083072958368869100670943702515680428810181896567941226764174676649752402094845184768854288495448882912408034163036416, b_4 == 45412915496099851216618901310768894310584095399914513550903694354875119254073464201324397609041971419465018896956786021330038801780511592201795793118669826074313642092350150811064582048553811833181582093091649655549475320526152216592300774144665572210409104781712067015180667377938234003697976545066894141456]
from Crypto.Util.number import *
n = 3183573836769699313763043722513486503160533089470716348487649113450828830224151824106050562868640291712433283679799855890306945562430572137128269318944453041825476154913676849658599642113896525291798525533722805116041675462675732995881671359593602584751304602244415149859346875340361740775463623467503186824385780851920136368593725535779854726168687179051303851797111239451264183276544616736820298054063232641359775128753071340474714720534858295660426278356630743758247422916519687362426114443660989774519751234591819547129288719863041972824405872212208118093577184659446552017086531002340663509215501866212294702743
e = 65537
c = 48433948078708266558408900822131846839473472350405274958254566291017137879542806238459456400958349315245447486509633749276746053786868315163583443030289607980449076267295483248068122553237802668045588106193692102901936355277693449867608379899254200590252441986645643511838233803828204450622023993363140246583650322952060860867801081687288233255776380790653361695125971596448862744165007007840033270102756536056501059098523990991260352123691349393725158028931174218091973919457078350257978338294099849690514328273829474324145569140386584429042884336459789499705672633475010234403132893629856284982320249119974872840
a_4=70102828721558534948345339875672972694466981761923685698221464095350842567073878119031031001553580576396374042398681177813432211192009435021654721839600881033401700453496031215200878726773965083072958368869100670943702515680428810181896567941226764174676649752402094845184768854288495448882912408034163036416
p=a_4+rp
q=n//p
print(long_to_bytes(int(pow(c,gmpy2.invert(e,(p-1)*(q-1)),n))))