2022 ACTF impossible RSA
from Crypto.Util.number import *
from Crypto.PublicKey import RSA
e = 65537
flag = b'ACTF{...}'
while True:
p = getPrime(1024)
q = inverse(e, p)
if not isPrime(q):
continue
n = p * q;
public = RSA.construct((n, e))
with open("public.pem", "wb") as file:
file.write(public.exportKey('PEM'))
with open("flag", "wb") as file:
file.write(long_to_bytes(pow(bytes_to_long(flag), e, n)))
break
n , c , e 已知 q ∗ e ≡ 1 ( m o d p ) q ∗ e = 1 + k ∗ p p ∗ q ∗ e = p + k ∗ p ∗ p n ∗ e = p + k ∗ p ∗ p n ∗ e k = p k + p ∗ p n ∗ e k = p ∗ ( 1 k + p ) n,c,e已知\\q*e\equiv 1\pmod p\\q*e=1+k*p\\p*q*e=p+k*p*p\\n*e=p+k*p*p\\ \frac{n*e}{k}=\frac{p}{k}+p*p\\ \sqrt{\frac{n*e}{k}}=\sqrt{p*(\frac{1}{k}+p)} n,c,e已知q∗e≡1(modp)q∗e=1+k∗pp∗q∗e=p+k∗p∗pn∗e=p+k∗p∗pkn∗e=kp+p∗pkn∗e=p∗(k1+p)
爆破k求解
yihzilic = bytes_to_long(open("flag","rb").read())
n = 15987576139341888788648863000534417640300610310400667285095951525208145689364599119023071414036901060746667790322978452082156680245315967027826237720608915093109552001033660867808508307569531484090109429319369422352192782126107818889717133951923616077943884651989622345435505428708807799081267551724239052569147921746342232280621533501263115148844736900422712305937266228809533549134349607212400851092005281865296850991469375578815615235030857047620950536534729591359236290249610371406300791107442098796128895918697534590865459421439398361818591924211607651747970679849262467894774012617335352887745475509155575074809
e = 65537
for k in range(2,10000000):
q = gmpy2.iroot(n*e//k,2)[0]
p = n//q
if p == 1:
continue
if p*q == n:
d = gmpy2.invert(e,(p-1)*(q-1))
print(long_to_bytes(pow(c,d,n)))
b'ACTF{F1nD1nG_5pEcia1_n_i5
q ∗ e ≡ 1 ( m o d p ) − > n ∗ e k = p ∗ ( 1 k + p ) q*e\equiv 1\pmod p->\sqrt{\frac{n*e}{k}}=\sqrt{p*(\frac{1}{k}+p)} q∗e≡1(modp)−>kn∗e=p∗(k1+p)
2022 ACTF RSA LEAK
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
p p = n e x t p r i m e ( p + r p ) q q = n e x t p r i m e ( q + r q ) n = p p ∗ q q r p 、 r q = 24 b i t l e a k 2 = r p e + r q e + 0 x d e a d b e e f ( m o d l e a k 1 ) l e a k 1 已知 pp=nextprime(p+rp)\\qq=nextprime(q+rq)\\n=pp*qq\\rp、rq =24bit\\leak2=rp^e + rq^e + 0xdeadbeef \pmod {leak_1}\\leak_1已知 pp=nextprime(p+rp)qq=nextprime(q+rq)n=pp∗qqrp、rq=24bitleak2=rpe+rqe+0xdeadbeef(modleak1)leak1已知
题解:
leak→爆破出rp,rq
-
中间相遇攻击
假设 E 和 D 分别是加密函数和解密函数,k1 和 k2 分别是两次加密使用的密钥,则我们有
P ⟶ 加密 ( k 1 ) t ⟶ 加密 ( k 2 ) C P\stackrel{加密(k_1)}{\longrightarrow}t\stackrel{加密(k_2)}{\longrightarrow}C P⟶加密(k1)t⟶加密(k2)C
E k 1 ( P ) = D k 2 ( C ) E_{k_1}(P)=D_{k_2}(C) Ek1(P)=Dk2(C)
则我们可以推出
P ⟶ 加密 ( k 1 ) t C ⟶ 解密 ( k 2 ) t P\stackrel{加密(k_1)}{\longrightarrow}t\\ C\stackrel{解密(k_2)}{\longrightarrow}t P⟶加密(k1)tC⟶解密(k2)t
那么,当用户知道一对明文和密文时
- 攻击者可以枚举所有的 k1,将 P 所有加密后的结果存储起来,并按照密文的大小进行排序。
- 攻击者进一步枚举所有的k2,将密文 C 进行解密得到 C1,在第一步加密后的结果中搜索 C1,如果搜索到,则我们在一定程度上可以认为我们找到了正确的 k1 和 k2。
- 如果觉得第二步中得到的结果不保险,则我们还可以再找一些明密文对进行验证。
假设 k1 和 k2 的密钥长度都为 n,则原先我们暴力枚举需要 O ( n 2 ) O(n^2) O(n2),现在我们只需要 O ( n l o g 2 n ) O(n log_2n) O(nlog2n)
l e a k 2 = r p e + r q e + 0 x d e a d b e e f ( m o d l e a k 1 ) l e a k 2 = r p e + r q e + 0 x d e a d b e e f ( m o d n 1 ) r q e = l e a k 2 − 0 x d e a d b e e f − r p e ( m o d n 1 ) leak2=rp^e + rq^e + 0xdeadbeef \pmod {leak_1}\\leak2=rp^e + rq^e + 0xdeadbeef \pmod {n_1}\\rq^e=leak2- 0xdeadbeef-rp^e \pmod {n_1} leak2=rpe+rqe+0xdeadbeef(modleak1)leak2=rpe+rqe+0xdeadbeef(modn1)rqe=leak2−0xdeadbeef−rpe(modn1)
输入的rp,rq都只有24位,这里就可以进行爆破,爆破的条件是长度要小于24位
中间相遇爆破:(复杂度降低了)
代码1
代码2
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
求p,q
p p = n e x t p r i m e ( p + r p ) q q = n e x t p r i m e ( q + r q ) n = p p ∗ q q = ( p + r p + k 1 ) ∗ ( q + r q + k 2 ) = ( a 4 + r p + k 1 ) ∗ ( b 4 + r q + k 2 ) = ( a b ) 4 + a 4 ∗ ( r q + k 2 ) + b 4 ∗ ( r p + k 1 ) + r p ∗ q q + k 2 + r q ∗ k 1 + k 1 ∗ k 2 ( a b ) 4 特别大 = ( a ∗ b ) 4 + O ( t ) pp=nextprime(p+rp)\\qq=nextprime(q+rq)\\n=pp*qq=(p+rp+k_1)*(q+rq+k_2)\\=(a^4+rp+k_1)*(b^4+rq+k_2)\\=(ab)^4+a^4*(rq+k_2)+b^4*(rp+k_1)+rp*qq+k_2+rq*k_1+k1*k_2\\(ab)^4特别大\\=(a*b)^4+O(t) pp=nextprime(p+rp)qq=nextprime(q+rq)n=pp∗qq=(p+rp+k1)∗(q+rq+k2)=(a4+rp+k1)∗(b4+rq+k2)=(ab)4+a4∗(rq+k2)+b4∗(rp+k1)+rp∗qq+k2+rq∗k1+k1∗k2(ab)4特别大=(a∗b)4+O(t)
t = (gmpy2.iroot(n,4)[0])**4
记 p*q=t,求pp,qq
pp=nextprime(p+rp)
qq=nextprime(q+rq)
n = p p ∗ q q = ( p + r p + k 1 ) ∗ ( q + r q + k 2 ) = p ∗ q + p ∗ r q + p ∗ k 2 + r p ∗ q + r p ∗ r q + r p + k 2 + k 1 ∗ q + k 1 ∗ r q + k 1 ∗ k 2 n=pp*qq=(p+rp+k_1)*(q+rq+k_2)\\ =p*q+p*rq+p*k_2+rp*q+rp*rq+rp+k_2+k_1*q+k_1*rq+k_1*k_2 n=pp∗qq=(p+rp+k1)∗(q+rq+k2)=p∗q+p∗rq+p∗k2+rp∗q+rp∗rq+rp+k2+k1∗q+k1∗rq+k1∗k2
两边同时乘以p,消掉q
n ∗ p = p ∗ t + p 2 ∗ r q + p 2 ∗ k 2 + r p ∗ t + p ∗ r p ∗ r q + r p ∗ k 2 ∗ p + k 1 ∗ t + k 1 ∗ r q ∗ p + k 1 ∗ k 2 ∗ p \\n*p=p*t+p^2*rq+p^2*k_2+rp*t+p*rp*rq+rp*k_2*p+k_1*t+k_1*rq*p+k_1*k_2*p n∗p=p∗t+p2∗rq+p2∗k2+rp∗t+p∗rp∗rq+rp∗k2∗p+k1∗t+k1∗rq∗p+k1∗k2∗p
k1,k2爆破,利用求根公式求解关于p的一元二次方程
from Crypto.Util.number import inverse
from tqdm import tqdm
n1=122146249659110799196678177080657779971
e = 65537
#分解n1
p1 = 8949458376079230661
q1 = 13648451618657980711
phi=(p1-1)*(q1-1)
d1=inverse(e,phi)
c1=90846368443479079691227824315092288065
c=(c1-0xdeadbeef)%n1
#爆破
for rp in tqdm(range(2**24)):
t=(c-pow(rp,e,n1))%n1
# print(t)
rq=pow(t,d1,n1)
if( len(bin(rq))<=26):
print(rp)
print(rq)
break'''
# #爆破2,太复杂
# for i in tqdm(range(2**24)):
# for j in range(2**24):
# if (pow(i,e,n1)+pow(j,e,n1)+0xdeadbeef)%n1==c1:
# rp=i
# rq=j
# print(i)
# print(j)
# break
#
import gmpy2
from Crypto.Util.number import *
n = 3183573836769699313763043722513486503160533089470716348487649113450828830224151824106050562868640291712433283679799855890306945562430572137128269318944453041825476154913676849658599642113896525291798525533722805116041675462675732995881671359593602584751304602244415149859346875340361740775463623467503186824385780851920136368593725535779854726168687179051303851797111239451264183276544616736820298054063232641359775128753071340474714720534858295660426278356630743758247422916519687362426114443660989774519751234591819547129288719863041972824405872212208118093577184659446552017086531002340663509215501866212294702743
e = 65537
flag = 48433948078708266558408900822131846839473472350405274958254566291017137879542806238459456400958349315245447486509633749276746053786868315163583443030289607980449076267295483248068122553237802668045588106193692102901936355277693449867608379899254200590252441986645643511838233803828204450622023993363140246583650322952060860867801081687288233255776380790653361695125971596448862744165007007840033270102756536056501059098523990991260352123691349393725158028931174218091973919457078350257978338294099849690514328273829474324145569140386584429042884336459789499705672633475010234403132893629856284982320249119974872840
rp = 405771
rq = 11974933
t = pow(gmpy2.iroot(n, 4)[0], 4)
for k1 in range(1000):
for k2 in range(1000):
a = rq + k2
b = t + rp*rq + rp*k2 + k1*rq + k1*k2 - n
c = (rp + k1) * t
delta = pow(b,2) - 4*a*c
roots = gmpy2.iroot(delta, 2)
if roots[1]:
p = (-b + roots[0])//(2*a)
pp = p+rp+k1
if isPrime(pp):
print(f"{k1 = }")
print(f"{k2 = }")
qq = n//pp
phi = (pp-1)*(qq-1)
d = gmpy2.invert(e, phi)
m = pow(flag, d, n)
print(long_to_bytes(int(m)))
exit()
#ACTF{lsb_attack_in_RSA|a32d7f}
GKCTF 2021 RRRRsa
from Crypto.Util.number import *
from gmpy2 import gcd
flag = b'xxxxxxxxxxxxx'
p = getPrime(512)
q = getPrime(512)
m = bytes_to_long(flag)
n = p*q
e = 65537
c = pow(m,e,n)
print('c={}'.format(c))
p1 = getPrime(512)
q1 = getPrime(512)
n1 = p1*q1
e1 = 65537
assert gcd(e1,(p1-1)*(q1-1)) == 1
c1 = pow(p,e1,n1)
print('n1={}'.format(n1))
print('c1={}'.format(c1))
hint1 = pow(2020 * p1 + q1, 202020, n1)
hint2 = pow(2021 * p1 + 212121, q1, n1)
print('hint1={}'.format(hint1))
print('hint2={}'.format(hint2))
p2 = getPrime(512)
q2 = getPrime(512)
n2 = p2*q2
e2 = 65537
assert gcd(e1,(p2-1)*(q2-1)) == 1
c2 = pow(q,e2,n2)
hint3 = pow(2020 * p2 + 2021 * q2, 202020, n2)
hint4 = pow(2021 * p2 + 2020 * q2, 212121, n2)
print('n2={}'.format(n2))
print('c2={}'.format(c2))
print('hint3={}'.format(hint3))
print('hint4={}'.format(hint4))
题解
{ h i n t 1 = ( 2020 ∗ p 1 + q 1 ) 202020 ( m o d n 1 ) h i n t 2 = ( 2021 ∗ p 1 + 212121 ) q 1 ( m o d n 1 ) h i n t 3 = ( 2020 ∗ p 2 + 2021 ∗ q 2 ) 202020 ( m o d n 2 ) h i n t 4 = ( 2021 ∗ p 2 + 2020 ∗ q 2 ) 212121 ( m o d n 2 ) \begin{cases}hint1=(2020∗p1+q1)^{202020} \pmod {n_1}\\hint2=(2021∗p1+212121)^{q1} \pmod {n_1}\\hint3=(2020∗p2+2021∗q2) ^{202020} \pmod {n_2}\\hint4=(2021∗p2+2020∗q2)^{212121 }\pmod {n_2}\\\end{cases} ⎩ ⎨ ⎧hint1=(2020∗p1+q1)202020(modn1)hint2=(2021∗p1+212121)q1(modn1)hint3=(2020∗p2+2021∗q2)202020(modn2)hint4=(2021∗p2+2020∗q2)212121(modn2)
c1 = pow(p,e1,n1),求p
利用二项式定理展开hint1,可将含p*q的项消除。
而hint2的化简可利用费马定理:
p 为素数,则对任意 a 有 a p = a ( m o d p ) p 为 素 数 , 则 对 任 意 a 有\\ a^p = a \pmod p p为素数,则对任意a有ap=a(modp)
可得
{ h i n t 1 = ( 2020 ∗ p 1 ) 202020 + q 1 202020 ( m o d n 1 ) h i n t 2 = 2021 ∗ p 1 + 212121 ( m o d q 1 ) \begin{cases}hint1=(2020∗p1)^{202020}+q1^{202020}\pmod {n_1}\\hint2=2021∗p1+212121\pmod {q_1}\end{cases} \\ {hint1=(2020∗p1)202020+q1202020(modn1)hint2=2021∗p1+212121(modq1)
模q1
{ h i n t 1 = ( 2020 ∗ p 1 ) 202020 ( m o d q 1 ) h i n t 2 − 212121 = 2021 ∗ p 1 ( m o d q 1 ) { h i n t 1 ∗ 202 0 − 202020 = p 1 202020 ( m o d q 1 ) ( h i n t 2 − 212121 ) 202020 ∗ 202 1 − 202020 = p 1 202020 ( m o d q 1 ) \begin{cases}hint1=(2020∗p1)^{202020}\pmod {q_1}\\hint2-212121=2021∗p1\pmod {q_1}\end{cases}\\ \begin{cases}hint1*2020^{-202020}=p1^{202020}\pmod {q_1}\\ (hint2-212121)^{202020}*2021^{-202020}=p1^{202020}\pmod {q_1}\\ \end{cases}\\ {hint1=(2020∗p1)202020(modq1)hint2−212121=2021∗p1(modq1){hint1∗2020−202020=p1202020(modq1)(hint2−212121)202020∗2021−202020=p1202020(modq1)
消元,消p1
( h i n t 2 − 212121 ) 202020 ∗ 202 1 − 202020 − ( 2020 ∗ p 1 ) 202020 = k ∗ q 1 q 1 = g c d ( k ∗ q 1 , n ) (hint2-212121)^{202020}*2021^{-202020}-(2020∗p1)^{202020}=k*q1\\q1=gcd(k*q1,n) (hint2−212121)202020∗2021−202020−(2020∗p1)202020=k∗q1q1=gcd(k∗q1,n)
c2= pow(q,e2,n2),求q
202 1 202020 ∗ h i n t 3 = ( 2021 ∗ 2020 ∗ p 2 ) 202020 + ( 202 1 2 ∗ q 2 ) 202020 ( m o d n 2 ) 202 0 212121 ∗ h i n t 4 = ( 2021 ∗ 2020 ∗ p 2 ) 212121 + ( 20202 ∗ q 2 ) 212121 ( m o d n 2 ) 2021^{202020} ∗hint3=(2021∗2020∗p2) ^{202020} +(2021^ 2 ∗q2)^{202020}\pmod {n_2}\\2020^{212121} ∗hint4=(2021∗2020∗p2)^{212121} +(2020 2 ∗q2)^{212121} \pmod {n_2}\\ 2021202020∗hint3=(2021∗2020∗p2)202020+(20212∗q2)202020(modn2)2020212121∗hint4=(2021∗2020∗p2)212121+(20202∗q2)212121(modn2)
{ ① ( 202 1 202020 ∗ h i n t 3 ) 212121 = ( 2021 ∗ 2020 ∗ p 2 ) 202020 ∗ 212121 + ( 202 1 2 ∗ q 2 ) 202020 ∗ 212121 ( m o d n 2 ) ② ( 202 0 212121 ∗ h i n t 4 ) 202020 = ( 2021 ∗ 2020 ∗ p 2 ) 202020 ∗ 212121 + ( 202 0 2 ∗ q 2 ) 202020 ∗ 212121 ( m o d n 2 ) \begin{cases}① ( 2021^{202020} ∗ h i n t 3 )^{ 212121} = ( 2021 ∗ 2020 ∗ p 2 )^{ 202020 ∗ 212121} + ( 202 1^2 ∗ q 2 ) ^{202020 ∗ 212121} \pmod{n_2} \\② ( 2020^{212121} ∗ h i n t 4 )^{ 202020} = ( 2021 ∗ 2020 ∗ p 2 )^{ 202020 ∗ 212121} + ( 2020^2 ∗ q 2 ) ^{202020 ∗ 212121} \pmod{n_2} \end{cases} {①(2021202020∗hint3)212121=(2021∗2020∗p2)202020∗212121+(20212∗q2)202020∗212121(modn2)②(2020212121∗hint4)202020=(2021∗2020∗p2)202020∗212121+(20202∗q2)202020∗212121(modn2)
② − ① = k 1 ∗ q 2 ( m o d n 2 ) ② − ① = k 1 ∗ q 2 + k 2 ∗ n 2 = k ∗ q 2 q 2 = g c d ( ② − ① , n 2 ) ②−①=k1∗q2\pmod {n_2}\\②−①=k1∗q2+k2∗n2=k∗q2\\q2=gcd(②−①,n2) ②−①=k1∗q2(modn2)②−①=k1∗q2+k2∗n2=k∗q2q2=gcd(②−①,n2)
from gmpy2 import gcd
from Crypto.Util.number import *
import gmpy2
c=13492392717469817866883431475453770951837476241371989714683737558395769731416522300851917887957945766132864151382877462142018129852703437240533684604508379950293643294877725773675505912622208813435625177696614781601216465807569201380151669942605208425645258372134465547452376467465833013387018542999562042758
n1=75003557379080252219517825998990183226659117019770735080523409561757225883651040882547519748107588719498261922816865626714101556207649929655822889945870341168644508079317582220034374613066751916750036253423990673764234066999306874078424803774652754587494762629397701664706287999727238636073466137405374927829
c1=68111901092027813007099627893896838517426971082877204047110404787823279211508183783468891474661365139933325981191524511345219830693064573462115529345012970089065201176142417462299650761299758078141504126185921304526414911455395289228444974516503526507906721378965227166653195076209418852399008741560796631569
hint1=23552090716381769484990784116875558895715552896983313406764042416318710076256166472426553520240265023978449945974218435787929202289208329156594838420190890104226497263852461928474756025539394996288951828172126419569993301524866753797584032740426259804002564701319538183190684075289055345581960776903740881951
hint2=52723229698530767897979433914470831153268827008372307239630387100752226850798023362444499211944996778363894528759290565718266340188582253307004810850030833752132728256929572703630431232622151200855160886614350000115704689605102500273815157636476901150408355565958834764444192860513855376978491299658773170270
n2=114535923043375970380117920548097404729043079895540320742847840364455024050473125998926311644172960176471193602850427607899191810616953021324742137492746159921284982146320175356395325890407704697018412456350862990849606200323084717352630282539156670636025924425865741196506478163922312894384285889848355244489
c2=67054203666901691181215262587447180910225473339143260100831118313521471029889304176235434129632237116993910316978096018724911531011857469325115308802162172965564951703583450817489247675458024801774590728726471567407812572210421642171456850352167810755440990035255967091145950569246426544351461548548423025004
hint3=25590923416756813543880554963887576960707333607377889401033718419301278802157204881039116350321872162118977797069089653428121479486603744700519830597186045931412652681572060953439655868476311798368015878628002547540835719870081007505735499581449077950263721606955524302365518362434928190394924399683131242077
hint4=104100726926923869566862741238876132366916970864374562947844669556403268955625670105641264367038885706425427864941392601593437305258297198111819227915453081797889565662276003122901139755153002219126366611021736066016741562232998047253335141676203376521742965365133597943669838076210444485458296240951668402513
e=65537
# q1 = gcd(n1,pow(hint2-212121,202020,n1)*pow(2020,202020,n1)-hint1*pow(2021,202020,n1))
# print(q1)
i1=inverse(pow(2021,202020,n1),n1)
i2=inverse(pow(2020,202020,n1),n1)
q1= gcd(n1,pow(hint2-212121,202020,n1)*i1-hint1*i2)
print(q1)
p1 = n1//q1
q2 = gcd(n2,pow(hint3,212121,n2)*pow(2021,202020*212121,n2)-pow(hint4,202020,n2)*pow(2020,202020*212121,n2))
p2 = n2//q2
d2 = gmpy2.invert(e,(q2-1)*(p2-1))
q = pow(c2,d2,n2)
d1 = gmpy2.invert(e,(q1-1)*(p1-1))
p = pow(c1,d1,n1)
d = gmpy2.invert(e,(q-1)*(p-1))
m = pow(c,d,p*q)
print(long_to_bytes(m))
#b'GKCTF{f64310b5-d5e6-45cb-ae69-c86600cdf8d8}
东华杯fermat’s revenge
这道题和上面这道可以说结构很像
from Crypto.Util.number import *
f = open('flag.txt', 'rb')
m = bytes_to_long(f.read())
f.close()
e = 65537
p = getPrime(1024)
q = getPrime(1024)
n = p * q
c = pow(m, e, n)
hint = pow(1010 * p + 1011, q, n)
f = open('cipher.txt', 'w')
f.write(f'n={n}\\n')
f.write(f'c={c}\\n')
f.write(f'hint={hint}\\n')
f.close()
这里只有一个hint
p = getPrime(1024)
q = getPrime(1024)
h i n t ≡ ( 1010 ∗ p + 1011 ) q ( m o d n ) h i n t ≡ ( 1010 ∗ p + 1011 ) q ( m o d p ) h i n t ≡ ( 1011 ) q ( m o d p ) ( 1011 ) n ≡ ( 1011 ) q ∗ p ≡ ( ( 1011 ) q ) p ≡ ( 1011 ) q ( m o d p ) h i n t ≡ ( 1011 ) n ( m o d p ) h i n t − ( 1011 ) n ≡ 0 ( m o d p ) h i n t − ( 1011 ) n = k ∗ p n = q ∗ p p = g c d ( n , h i n t − ( 1011 ) n ) hint \equiv (1010 * p + 1011)^ q \pmod n\\ hint \equiv(1010 * p + 1011)^ q \pmod p\\ hint \equiv( 1011)^ q \pmod p\\( 1011)^ n\equiv ( 1011)^ {q* p}\equiv (( 1011)^ {q})^ {p}\equiv( 1011)^ {q}\pmod p\\hint\equiv (1011)^ n\pmod p\\hint-( 1011)^ n\equiv 0 \pmod p\\hint-( 1011)^ n=k* p\\n=q*p\\p=gcd(n,hint-( 1011)^ n) hint≡(1010∗p+1011)q(modn)hint≡(1010∗p+1011)q(modp)hint≡(1011)q(modp)(1011)n≡(1011)q∗p≡((1011)q)p≡(1011)q(modp)hint≡(1011)n(modp)hint−(1011)n≡0(modp)hint−(1011)n=k∗pn=q∗pp=gcd(n,hint−(1011)n)
h i n t = 101 1 q ( m o d p ) ↔ h i n t ≡ ( 1011 ) n ( m o d p ) hint=1011^{q}(mod\ p)\leftrightarrow hint\equiv (1011)^ n\pmod p\\ hint=1011q(mod p)↔hint≡(1011)n(modp)
from Crypto.Util.number import *
e = 65537
# hint = pow(1010 * p + 1011, q, n)
n=17329555687339057933030881774167606066714011664369940819755094697939414110116183129515036417930928381309923593306884879686961969722610261114896200690291299753284120079351636102685226435454462581742248968732979816910255384339882675593423385529925794918175056364069416358095759362865710837992174966213332948216626442765218056059227797575954980861175262821459941222980957749720949816909119263643425681517545937122980872133309062049836920463547302193585676588711888598357927574729648088370609421283416559346827315399049239357814820660913395553316721927867556418628117971385375472454118148999848258824753064992040468588511
c=2834445728359401954509180010018035151637121735110411504246937217024301211768483790406570069340718976013805438660602396212488675995602673107853878297024467687865600759709655334014269938893756460638324659859693599161639448736859952750381592192404889795107146077421499823006298655812398359841137631684363428490100792619658995661630533920917942659455792050032138051272224911869438429703875012535681896010735974555495618216882831524578648074539796556404193333636537331833807459066576022732553707927018332334884641370339471969967359580724737784159811992637384360752274204462169330081579501038904830207691558009918736480389
hint=2528640120640884291705022551567142949735065756834488816429783990402901687493207894594113717734719036126087363828359113769238235697788243950392064194097056579105620723640796253143555383311882778423540515270957452851097267592400001145658904042191937942341842865936546187498072576943297002184798413336701918670376291021190387536660070933700475110660304652647893127663882847145502396993549034428649569475467365756381857116208029508389607872560487325166953770793357700419069480517845456083758105937644350450559733949764193599564499133714282286339445501435278957250603141596679797055178139335763901195697988437542180256184
h2 = pow(1011, n, n)
q = GCD(hint-h2, n)
print(q)
p = n // q
d = inverse(e, (p-1)*(q-1))
m = pow(c, d, n)
print(long_to_bytes(m))
#b'flag{1d2f28834ecbd1983b62d30f4723476e}'
2022 zer0pts CTF Anti-Fermat
from Crypto.Util.number import isPrime, getStrongPrime
from gmpy import next_prime
from secret import flag
# Anti-Fermat Key Generation
p = getStrongPrime(1024)
q = next_prime(p ^ ((1<<1024)-1))
n = p * q
e = 65537
# Encryption
m = int.from_bytes(flag, 'big')
assert m < n
c = pow(m, e, n)
print('n = {}'.format(hex(n)))
print('c = {}'.format(hex(c)))
#n = 0x1ffc7dc6b9667b0dcd00d6ae92fb34ed0f3d84285364c73fbf6a572c9081931be0b0610464152de7e0468ca7452c738611656f1f9217a944e64ca2b3a89d889ffc06e6503cfec3ccb491e9b6176ec468687bf4763c6591f89e750bf1e4f9d6855752c19de4289d1a7cea33b077bdcda3c84f6f3762dc9d96d2853f94cc688b3c9d8e67386a147524a2b23b1092f0be1aa286f2aa13aafba62604435acbaa79f4e53dea93ae8a22655287f4d2fa95269877991c57da6fdeeb3d46270cd69b6bfa537bfd14c926cf39b94d0f06228313d21ec6be2311f526e6515069dbb1b06fe3cf1f62c0962da2bc98fa4808c201e4efe7a252f9f823e710d6ad2fb974949751
#c = 0x60160bfed79384048d0d46b807322e65c037fa90fac9fd08b512a3931b6dca2a745443a9b90de2fa47aaf8a250287e34563e6b1a6761dc0ccb99cb9d67ae1c9f49699651eafb71a74b097fc0def77cf287010f1e7bd614dccfb411cdccbb84c60830e515c05481769bd95e656d839337d430db66abcd3a869c6348616b78d06eb903f8abd121c851696bd4cb2a1a40a07eea17c4e33c6a1beafb79d881d595472ab6ce3c61d6d62c4ef6fa8903149435c844a3fab9286d212da72b2548f087e37105f4657d5a946afd12b1822ceb99c3b407bb40e21163c1466d116d67c16a2a3a79e5cc9d1f6a1054d6be6731e3cd19abbd9e9b23309f87bfe51a822410a62
题解
q = next_prime(p ^ ((1<<1024)-1))
如果a>b,,且a为0b1111111111(二进制全为1),那么a^b=a-b
所以((1<<1024)-1)^p=(1<<1024-1)-p
设p((1<<1024)-1)的下一个素数与p((1<<1024)-1)相差r(nextprime影响的是非常低位的数据)
则
q = ( 1 < < 1024 − 1 ) − p + r q=(1<<1024-1)-p+r q=(1<<1024−1)−p+r
得到
p + q = 1 < < 1024 − 1 + r n = p ∗ q = ( p + q 2 ) 2 − ( p − q 2 ) 2 ( p − q ) 2 = ( p + q ) 2 − 4 ∗ n ( p − q ) = ( p + q ) 2 − 4 ∗ n p+q=1<<1024-1+r\\n=p*q=(\frac{p+q}{2})^2-(\frac{p-q}{2})^2\\(p-q)^2=(p+q)^2-4*n\\(p-q)=\sqrt{(p+q)^2-4*n}\\ p+q=1<<1024−1+rn=p∗q=(2p+q)2−(2p−q)2(p−q)2=(p+q)2−4∗n(p−q)=(p+q)2−4∗n
得到t=p-q
p = ( p + q ) + ( p − q ) 2 p ≈ ( 1 < < 1024 ) + ( 1 < < 1024 ) 2 − 4 ∗ n 2 p=\frac{(p+q)+(p-q)}{2}\\ p\approx \frac{(1<<1024)+\sqrt{(1<<1024)^2-4*n}}{2} p=2(p+q)+(p−q)p≈2(1<<1024)+(1<<1024)2−4∗n
爆破P,条件n%p==0
import gmpy2
from Crypto.Util.number import long_to_bytes, inverse
from ecdsa.numbertheory import next_prime
n = 0x1ffc7dc6b9667b0dcd00d6ae92fb34ed0f3d84285364c73fbf6a572c9081931be0b0610464152de7e0468ca7452c738611656f1f9217a944e64ca2b3a89d889ffc06e6503cfec3ccb491e9b6176ec468687bf4763c6591f89e750bf1e4f9d6855752c19de4289d1a7cea33b077bdcda3c84f6f3762dc9d96d2853f94cc688b3c9d8e67386a147524a2b23b1092f0be1aa286f2aa13aafba62604435acbaa79f4e53dea93ae8a22655287f4d2fa95269877991c57da6fdeeb3d46270cd69b6bfa537bfd14c926cf39b94d0f06228313d21ec6be2311f526e6515069dbb1b06fe3cf1f62c0962da2bc98fa4808c201e4efe7a252f9f823e710d6ad2fb974949751
c = 0x60160bfed79384048d0d46b807322e65c037fa90fac9fd08b512a3931b6dca2a745443a9b90de2fa47aaf8a250287e34563e6b1a6761dc0ccb99cb9d67ae1c9f49699651eafb71a74b097fc0def77cf287010f1e7bd614dccfb411cdccbb84c60830e515c05481769bd95e656d839337d430db66abcd3a869c6348616b78d06eb903f8abd121c851696bd4cb2a1a40a07eea17c4e33c6a1beafb79d881d595472ab6ce3c61d6d62c4ef6fa8903149435c844a3fab9286d212da72b2548f087e37105f4657d5a946afd12b1822ceb99c3b407bb40e21163c1466d116d67c16a2a3a79e5cc9d1f6a1054d6be6731e3cd19abbd9e9b23309f87bfe51a822410a62
n=int(n)
c=int(c)
# q = next_prime(p ^ ((1<<1024)-1))
t=1<<1024
p=(t+int(gmpy2.iroot(t**2-4*n,2)[0]))//2
while(n%p!=0):
p=next_prime(p)
q=n//p
print(p)
phi=(p-1)*(q-1)
e=65537
d=inverse(e,phi)
m=pow(c,d,n)
print(long_to_bytes(m))
#153456316755201256456077648680293404551531181234956990242779099773886170192558263224753907666532907469313954439789378399786631549347700474488574017322863270205683350905558827922567834954626909259763623105532668671134932118937640401627676913585506492102157561689678418157863742997375967679975824876706628973287
# b'Good job! Here is the flag:\n+-----------------------------------------------------------+\n| zer0pts{F3rm4t,y0ur_m3th0d_n0_l0ng3r_w0rks.y0u_4r3_f1r3d} |\n+-----------------------------------------------------------+'
# zer0pts{F3rm4t,y0ur_m3th0d_n0_l0ng3r_w0rks.y0u_4r3_f1r3d}
*2022 ctf crypto Ezrsa
from Crypto.Util.number import getStrongPrime
from gmpy import next_prime
from random import getrandbits
from flag import flag
p=getStrongPrime(1024)
q=next_prime(p^((1<<900)-1)^getrandbits(300))
n=p*q
e=65537
m=int(flag.encode('hex'),16)
assert m<n
c=pow(m,e,n)
print(hex(n))
#0xe78ab40c343d4985c1de167e80ba2657c7ee8c2e26d88e0026b68fe400224a3bd7e2a7103c3b01ea4d171f5cf68c8f00a64304630e07341cde0bc74ef5c88dcbb9822765df53182e3f57153b5f93ff857d496c6561c3ddbe0ce6ff64ba11d4edfc18a0350c3d0e1f8bd11b3560a111d3a3178ed4a28579c4f1e0dc17cb02c3ac38a66a230ba9a2f741f9168641c8ce28a3a8c33d523553864f014752a04737e555213f253a72f158893f80e631de2f55d1d0b2b654fc7fa4d5b3d95617e8253573967de68f6178f78bb7c4788a3a1e9778cbfc7c7fa8beffe24276b9ad85b11eed01b872b74cdc44959059c67c18b0b7a1d57512319a5e84a9a0735fa536f1b3
print(hex(c))
#0xd7f6c90512bc9494370c3955ff3136bb245a6d1095e43d8636f66f11db525f2063b14b2a4363a96e6eb1bea1e9b2cc62b0cae7659f18f2b8e41fca557281a1e859e8e6b35bd114655b6bf5e454753653309a794fa52ff2e79433ca4bbeb1ab9a78ec49f49ebee2636abd9dd9b80306ae1b87a86c8012211bda88e6e14c58805feb6721a01481d1a7031eb3333375a81858ff3b58d8837c188ffcb982a631e1a7a603b947a6984bd78516c71cfc737aaba479688d56df2c0952deaf496a4eb3f603a46a90efbe9e82a6aef8cfb23e5fcb938c9049b227b7f15c878bd99b61b6c56db7dfff43cd457429d5dcdb5fe314f1cdf317d0c5202bad6a9770076e9b25b1
p = k 1 ∗ ( 2 900 ) + k 2 q = k 1 ∗ ( 2 900 ) + ( 2 900 − k 2 ) + k 3 n = p ∗ q = k 1 2 ∗ ( 2 1800 ) + 2 k 1 k 2 ∗ ( 2 900 ) + k 1 ∗ ( 2 1800 ) + L ( 可忽略不计 ) p = k1 * (2^{900}) + k2\\q = k1 * (2^{900}) + (2^{900} - k2) +k3\\n = p*q = k1^2 * (2^{1800}) + 2k1k2 * (2^{900}) + k1 * (2^{1800}) + L(可忽略不计) p=k1∗(2900)+k2q=k1∗(2900)+(2900−k2)+k3n=p∗q=k12∗(21800)+2k1k2∗(2900)+k1∗(21800)+L(可忽略不计)
对N开方得到p的高位,异或关系得到p中间几位,coppersmith得到p的低位。
p的高位
🤭方法一:
p,q很接近,直接对n开方求的P的高位
将n的前248位开方
import gmpy2
n = 0xe78ab40c343d4985c1de167e80ba2657c7ee8c2e26d88e0026b68fe400224a3bd7e2a7103c3b01ea4d171f5cf68c8f00a64304630e07341cde0bc74ef5c88dcbb9822765df53182e3f57153b5f93ff857d496c6561c3ddbe0ce6ff64ba11d4edfc18a0350c3d0e1f8bd11b3560a111d3a3178ed4a28579c4f1e0dc17cb02c3ac38a66a230ba9a2f741f9168641c8ce28a3a8c33d523553864f014752a04737e555213f253a72f158893f80e631de2f55d1d0b2b654fc7fa4d5b3d95617e8253573967de68f6178f78bb7c4788a3a1e9778cbfc7c7fa8beffe24276b9ad85b11eed01b872b74cdc44959059c67c18b0b7a1d57512319a5e84a9a0735fa536f1b3
top_bits = int(gmpy2.iroot(n>>(2048-248),2)[0])
print(top_bits)
对n开方,取高124位
tph=int(gmpy2.iroot(n,2)[0])
ph=tph>>900
print(ph)
🤭方法二:
p = p h ∗ 2 900 + p l q = q h ∗ 2 900 + q l p h = q h = x n = p ∗ q = ( p h ∗ 2 900 + p l ) ∗ ( q h ∗ 2 900 + q l ) = x 2 ∗ 2 1800 + x ∗ 2 900 ∗ ( q l + p l ) + p l ∗ q l = x 2 ∗ 2 1800 + x ∗ 2 1800 + s m a l l ( 可忽略) n 1800 = x 2 + x p=ph*2^{900}+pl\\q=qh*2^{900}+ql\\ph=qh=x\\n=p*q=(ph*2^{900}+pl)*(qh*2^{900}+ql)\\=x^2*2^{1800}+x*2^{900}*(ql+pl)+pl*ql\\=x^2*2^{1800}+x*2^{1800}+small(可忽略)\\ \frac{n}{1800}=x^2+x p=ph∗2900+plq=qh∗2900+qlph=qh=xn=p∗q=(ph∗2900+pl)∗(qh∗2900+ql)=x2∗21800+x∗2900∗(ql+pl)+pl∗ql=x2∗21800+x∗21800+small(可忽略)1800n=x2+x
n=0xe78ab40c343d4985c1de167e80ba2657c7ee8c2e26d88e0026b68fe400224a3bd7e2a7103c3b01ea4d171f5cf68c8f00a64304630e07341cde0bc74ef5c88dcbb9822765df53182e3f57153b5f93ff857d496c6561c3ddbe0ce6ff64ba11d4edfc18a0350c3d0e1f8bd11b3560a111d3a3178ed4a28579c4f1e0dc17cb02c3ac38a66a230ba9a2f741f9168641c8ce28a3a8c33d523553864f014752a04737e555213f253a72f158893f80e631de2f55d1d0b2b654fc7fa4d5b3d95617e8253573967de68f6178f78bb7c4788a3a1e9778cbfc7c7fa8beffe24276b9ad85b11eed01b872b74cdc44959059c67c18b0b7a1d57512319a5e84a9a0735fa536f1b3
x=sympy.Symbol('x')
f1=x**2+x-n//2**1800
result=sympy.solve([f1],[x])
print(result)
#x=20226195070633070235386534147535171929
p的中间几位
方法一:
-
测试
p = '101011' q = '010100' print(int(p, 2)*int(q, 2)) # 860 # p和q赋值如下 p = '111111' q = '000001' # 第一位异或后 p = '011111' q = '100001' print(int(p, 2)*int(q, 2)) # 1023 ''' 大于原先值,那么该位不用改,即 p = '111111' q = '000001' ''' # 第二位异或后 p = '101111' q = '010001' print(int(p, 2)*int(q, 2)) # 799 ''' 小于原先值,那么该位要改,进行异或,即 p = '101111' q = '010001' '''
因为异或随机数是在最后300位上,所以125-900位的p,q之和为一个定值,而这一段上p,q的每一位是相反的,因此可以将这一段设为极端情况——p全为1,q全为0。根据基本不等式,p、q的差值越大,积就越大,而最后300位还要继续将q增大。根据这几点可以爆破125-924位,当p*q<n 时,表示这个位置的数正确
pm=tph>>900
print(pm)
p = (1<<900)-1
q = 1<<300-1
p+=pm*(1<<900)
q+=pm*(1<<900)
#in the rest place, '1' either belong to p or q
for i in range(898, 301, -1):
cur = 1<<i
if (p^^cur) * (q^^cur) < n:
p^^= cur
q^^= cur
方法二:
设 p = h b + y 设p=hb+y\\ 设p=hb+y
根据异或的性质,由于异或1,可以得出p,q 的中间600bit的二进制是相反的,所以中间位p+q是固定的(二进制和为1)
q = h b + 2 900 − 1 − y + z ( 300 b i t 随机数) p + q = 2 h b + 2 900 − 1 + z q=hb+2^{900}-1-y+z(300bit随机数)\\p+q=2hb+2^{900}-1+z q=hb+2900−1−y+z(300bit随机数)p+q=2hb+2900−1+z
{ p + q = 2 h b + 2 900 − 1 + z p − q = 2 ∗ y − 2 900 + 1 − z p − q = ( p + q ) 2 − 4 ∗ n y = ( p − q ) + 2 900 + ( z − 1 ) ( 可忽略) 2 \begin{cases}p+q=2hb+2^{900}-1+z\\p-q=2*y-2^{900}+1-z \\p-q=\sqrt{(p+q)^2-4*n} \end{cases}\\y=\frac{(p-q)+2^{900}+(z-1)(可忽略)}{2} ⎩ ⎨ ⎧p+q=2hb+2900−1+zp−q=2∗y−2900+1−zp−q=(p+q)2−4∗ny=2(p−q)+2900+(z−1)(可忽略)
from Crypto.Util.number import *
import gmpy2
n=0xe78ab40c343d4985c1de167e80ba2657c7ee8c2e26d88e0026b68fe400224a3bd7e2a7103c3b01ea4d171f5cf68c8f00a64304630e07341cde0bc74ef5c88dcbb9822765df53182e3f57153b5f93ff857d496c6561c3ddbe0ce6ff64ba11d4edfc18a0350c3d0e1f8bd11b3560a111d3a3178ed4a28579c4f1e0dc17cb02c3ac38a66a230ba9a2f741f9168641c8ce28a3a8c33d523553864f014752a04737e555213f253a72f158893f80e631de2f55d1d0b2b654fc7fa4d5b3d95617e8253573967de68f6178f78bb7c4788a3a1e9778cbfc7c7fa8beffe24276b9ad85b11eed01b872b74cdc44959059c67c18b0b7a1d57512319a5e84a9a0735fa536f1b3
c=0xd7f6c90512bc9494370c3955ff3136bb245a6d1095e43d8636f66f11db525f2063b14b2a4363a96e6eb1bea1e9b2cc62b0cae7659f18f2b8e41fca557281a1e859e8e6b35bd114655b6bf5e454753653309a794fa52ff2e79433ca4bbeb1ab9a78ec49f49ebee2636abd9dd9b80306ae1b87a86c8012211bda88e6e14c58805feb6721a01481d1a7031eb3333375a81858ff3b58d8837c188ffcb982a631e1a7a603b947a6984bd78516c71cfc737aaba479688d56df2c0952deaf496a4eb3f603a46a90efbe9e82a6aef8cfb23e5fcb938c9049b227b7f15c878bd99b61b6c56db7dfff43cd457429d5dcdb5fe314f1cdf317d0c5202bad6a9770076e9b25b1
prefix=gmpy2.iroot(n,2)[0]
prefix=(prefix>>900)<<900
hb=gmpy2.iroot(n,2)[0]
hb=(hb>>900)<<900
paq=2*hb+2**900
psq=gmpy2.iroot(paq**2-4*n,2)[0]
y=(psq+2**900)//2
p=hb+y
print(p)
# 170966211863977623201944075700366958395158791305775637137148430402719914596268969449870561801896130406088025694634815584789789278534177858182071449441084789053688828370314062664371506437683672869879650195774368524468044540434185235653504063937932618450991608706715382905688880285112977572901480973791888259637
方法三:
二分法逼近p,q
from Crypto.Util.number import *
import gmpy2
n=0xe78ab40c343d4985c1de167e80ba2657c7ee8c2e26d88e0026b68fe400224a3bd7e2a7103c3b01ea4d171f5cf68c8f00a64304630e07341cde0bc74ef5c88dcbb9822765df53182e3f57153b5f93ff857d496c6561c3ddbe0ce6ff64ba11d4edfc18a0350c3d0e1f8bd11b3560a111d3a3178ed4a28579c4f1e0dc17cb02c3ac38a66a230ba9a2f741f9168641c8ce28a3a8c33d523553864f014752a04737e555213f253a72f158893f80e631de2f55d1d0b2b654fc7fa4d5b3d95617e8253573967de68f6178f78bb7c4788a3a1e9778cbfc7c7fa8beffe24276b9ad85b11eed01b872b74cdc44959059c67c18b0b7a1d57512319a5e84a9a0735fa536f1b3
c=0xd7f6c90512bc9494370c3955ff3136bb245a6d1095e43d8636f66f11db525f2063b14b2a4363a96e6eb1bea1e9b2cc62b0cae7659f18f2b8e41fca557281a1e859e8e6b35bd114655b6bf5e454753653309a794fa52ff2e79433ca4bbeb1ab9a78ec49f49ebee2636abd9dd9b80306ae1b87a86c8012211bda88e6e14c58805feb6721a01481d1a7031eb3333375a81858ff3b58d8837c188ffcb982a631e1a7a603b947a6984bd78516c71cfc737aaba479688d56df2c0952deaf496a4eb3f603a46a90efbe9e82a6aef8cfb23e5fcb938c9049b227b7f15c878bd99b61b6c56db7dfff43cd457429d5dcdb5fe314f1cdf317d0c5202bad6a9770076e9b25b1
hb=gmpy2.iroot(n,2)[0]
hb=(hb>>900)<<900
paq=2*hb+2**900
l=1
r=int(gmpy2.iroot(n,2)[0])
while abs(r-l)>1:
m=(r+l)//2
x=m+n//m
if x>paq:
l=m
else:
r=m
print(r)
p的低位
coppersmith攻击
已知p的高(124+600)bit
# PR.<x> = PolynomialRing(Zmod(n))
# f=x+q
# roots=f.small_roots(X=2**450,beta=0.4)
# q=q+roots[0]
# p=n//int(q)
p=170966211863977623201944075700366958395158791305775637137148430402719914596268969449870561801896130406088025694634815584789789278534177858182071449441084789053688828370314062664371527964357773254659131885022323526864655742577256932209187678896131068422973326545184343697783650940422950445390573562429093050687
q=170966211863977623201944075700366958393004619503764097699771516857862770135235397782599591014026733542308689997522855822788108026355476250633633402693487971215224188430679737025882802309022607681575250753960315394407312741086850962379910401529197519289967419289495492616818534528352393107250012092986104141453
phi=(p-1)*(q-1)
d=inverse(e,phi)
m=pow(c,d,n)
print(long_to_bytes(m))
# *CTF{St.Diana_pls_take_me_with_you!}'
-
拓展
def adlit(x): l = len(bin(x)[2:]) return (2 ** l - 1) ^ x a=616161 print(bin(a)) print(bin(adlit(a))) #0b10010110011011100001 #0b01101001100100011110
补上bin(adlit(a))函数前的那个0,不难看出两个二进制数是相反的,adlit函数就是对一个数的二进制数进行取反。跟*CTF中间的600位一样。
p+adlit(p)=2^(nbit)-1
羊城杯 2020 RRRRRRRSA
from Crypto.Util.number import *
from secret import flag
import random
m1 = bytes_to_long(flag[:len(flag) // 2])
m2 = bytes_to_long(flag[len(flag) // 2:])
def gen(pbits, qbits):
p1, q1 = getPrime(pbits), getPrime(qbits)
n1 = p1**4*q1
q2 = getPrime(qbits)
bound = p1 // (8*q1*q2) + 1
p2 = random.randrange(p1, p1 + bound)
while not isPrime(p2):
p2 = random.randrange(p1, p1 + bound)
n2 = p2**4*q2
return (n1, n2), (p1, q1), (p2, q2)
e = 0x10001
pbits = int(360)
qbits = int(128)
pk, sk1, sk2 = gen(pbits, qbits)
c1 = pow(m1, e, pk[0])
c2 = pow(m2, e, pk[1])
print(f'pk = {pk}')
print(f'c1, c2 = {c1, c2}')
"""
pk = (1150398070565459492080597718626032792435556703413923483458704675295997646493249759818468321328556510074044954676615760446708253531839417036997811506222349194302791943489195718713797322878586379546657275419261647635859989280700191441312691274285176619391539387875252135478424580680264554294179123254566796890998243909286508189826458854346825493157697201495100628216832191035903848391447704849808577310612723700318670466035077202673373956324725108350230357879374234418393233, 1242678737076048096780023147702514112272319497423818488193557934695583793070332178723043194823444815153743889740338870676093799728875725651036060313223096288606947708155579060628807516053981975820338028456770109640111153719903207363617099371353910243497871090334898522942934052035102902892149792570965804205461900841595290667647854346905445201396273291648968142608158533514391348407631818144116768794595226974831093526512117505486679153727123796834305088741279455621586989)
c1, c2 = (361624030197288323178211941746074961985876772079713896964822566468795093475887773853629454653096485450671233584616088768705417987527877166166213574572987732852155320225332020636386698169212072312758052524652761304795529199864805108000796457423822443871436659548626629448170698048984709740274043050729249408577243328282313593461300703078854044587993248807613713896590402657788194264718603549894361488507629356532718775278399264279359256975688280723740017979438505001819438, 33322989148902718763644384246610630825314206644879155585369541624158380990667828419255828083639294898100922608833810585530801931417726134558845725168047585271855248605561256531342703212030641555260907310067120102069499927711242804407691706542428236208695153618955781372741765233319988193384708525251620506966304554054884590718068210659709406626033891748214407992041364462525367373648910810036622684929049996166651416565651803952838857960054689875755131784246099270581394)
"""
n 1 = p 1 4 ∗ q 1 n 2 = p 2 4 ∗ q 2 n1=p1^4*q1\\n2=p2^4*q2\\ n1=p14∗q1n2=p24∗q2
p2 = random.randrange(p1, p1 + bound) , 说明p1,p2相差很小
n 1 n 2 = p 1 4 ∗ q 1 p 2 4 ∗ q 2 ≈ q 1 q 2 \frac{n1}{n2}=\frac{p1^4*q1}{p2^4*q2}\approx\frac{q1}{q2}\\ n2n1=p24∗q2p14∗q1≈q2q1
连分数展开 n 1 n 2 \frac{n1}{n2} n2n1,可以找到q1,q2
import gmpy2
N1=1150398070565459492080597718626032792435556703413923483458704675295997646493249759818468321328556510074044954676615760446708253531839417036997811506222349194302791943489195718713797322878586379546657275419261647635859989280700191441312691274285176619391539387875252135478424580680264554294179123254566796890998243909286508189826458854346825493157697201495100628216832191035903848391447704849808577310612723700318670466035077202673373956324725108350230357879374234418393233
c1=361624030197288323178211941746074961985876772079713896964822566468795093475887773853629454653096485450671233584616088768705417987527877166166213574572987732852155320225332020636386698169212072312758052524652761304795529199864805108000796457423822443871436659548626629448170698048984709740274043050729249408577243328282313593461300703078854044587993248807613713896590402657788194264718603549894361488507629356532718775278399264279359256975688280723740017979438505001819438
E1=0x10001
N2=1242678737076048096780023147702514112272319497423818488193557934695583793070332178723043194823444815153743889740338870676093799728875725651036060313223096288606947708155579060628807516053981975820338028456770109640111153719903207363617099371353910243497871090334898522942934052035102902892149792570965804205461900841595290667647854346905445201396273291648968142608158533514391348407631818144116768794595226974831093526512117505486679153727123796834305088741279455621586989
c2=33322989148902718763644384246610630825314206644879155585369541624158380990667828419255828083639294898100922608833810585530801931417726134558845725168047585271855248605561256531342703212030641555260907310067120102069499927711242804407691706542428236208695153618955781372741765233319988193384708525251620506966304554054884590718068210659709406626033891748214407992041364462525367373648910810036622684929049996166651416565651803952838857960054689875755131784246099270581394
E2=0x10001
def continuedFra(x, y):
cF = []
while y:
cF += [x // y]
x, y = y, x % y
return cF
def Simplify(ctnf):
numerator = 0
denominator = 1
for x in ctnf[::-1]:
numerator, denominator = denominator, x * denominator + numerator
return (numerator, denominator)
def getit(c):
cf=[]
for i in range(1,len(c)):
cf.append(Simplify(c[:i]))
return cf
#求渐进分数
def wienerAttack(e, n):
cf=continuedFra(e,n)
for (p2,p1) in getit(cf):
if p1 == 0:
continue
if N1%p1==0 and p1!=1:
return p1,p2
print('not find!')
q1,q2 = wienerAttack(N1,N2)
p1 = gmpy2.iroot(N1//q1,4)[0]
p2 = gmpy2.iroot(N2//q2,4)[0]
phi1=p1**3*(p1-1)*(q1-1)
phi2=p2**3*(p2-1)*(q2-1)
d1=gmpy2.invert(E1,phi1)
d2=gmpy2.invert(E2,phi2)
from Crypto.Util import number
m1=number.long_to_bytes(gmpy2.powmod(c1,d1,N1))
m2=number.long_to_bytes(gmpy2.powmod(c2,d2,N2))
print((m1+m2))
🍹总结
-
q = inverse(e, p)
-
数据小的数要进行爆破;
-
通过对等式两边同时进行加减乘除等变化,使得等式除了可爆破的变量外,只有一个变量的方程
-
利用求根公式求解方程的根
-
中间相遇爆破可缩短爆破时间
-
二分法逼近
-
当a=bt+c,bt特别大时,可以直接开方求出b
-
通过自己生成几个样例来测试数据,有些小数可以直接忽略
-
给一个hint,它和p和q之间有直接关系。尝试mod p或者mod q看一下,利用已知的条件,在同余式中消去另一个因数(消元),建议把题目给的条件组合组合,在我们规定的mod p或者mod q的条件下,看看都是什么结果。
h i n t = 101 1 q ( m o d p ) ↔ h i n t ≡ ( 1011 ) n ( m o d p ) hint=1011^{q}(mod\ p)\leftrightarrow hint\equiv (1011)^ n\pmod p\\ hint=1011q(mod p)↔hint≡(1011)n(modp)
📎 参考