problem
from gmpy2 import *
from Crypto.Util.number import *
flag = '****************************'
flag = {"asfajgfbiagbwe"}
p = getPrime(2048)
q = getPrime(2048)
m1 = bytes_to_long(bytes(flag.encode()))
e1e2 = 3087
n = p*q
print()
flag1 = pow(m1,e1,n)
flag2 = pow(m1,e2,n)
print('flag1= '+str(flag1))
print('flag2= '+str(flag2))
print('n= '+str(n))
#flag1= 463634070971821449698012827631572665302589213868521491855038966879005784397309389922926838028598122795187584361359142761652619958273094398420314927073008031088375892957173280915904309949716842152249806486027920136603248454946737961650252641668562626310035983343018705370077783879047584582817271215517599531278507300104564011142229942160380563527291388260832749808727470291331902902518196932928128107067117198707209620169906575791373793854773799564060536121390593687449884988936522369331738199522700261116496965863870682295858957952661531894477603953742494526632841396338388879198270913523572980574440793543571757278020533565628285714358815083303489096524318164071888139412436112963845619981511061231001617406815056986634680975142352197476024575809514978857034477688443230263761729039797859697947454810551009108031457294164840611157524719173343259485881089252938664456637673337362424443150013961181619441267926981848009107466576314685961478748352388452114042115892243272514245081604607798243817586737546663059737344687130881861357423084448027959893402445303299089606081931041217035955143939567456782107203447898345284731038150377722447329202078375870541529539840051415759436083384408203659613313535094343772238691393447475364806171594
#flag2= 130959534275704453216282334815034647265875632781798750901627773826812657339274362406246297925411291822193191483409847323315110393729020700526946712786793380991675008128561863631081095222226285788412970362518398757423705216112313533155390315204875516645459370629706277876211656753247984282379731850770447978537855070379324935282789327428625259945250066774049650951465043700088958965762054418615838049340724639373351248933494355591934236360506778496741051064156771092798005112534162050165095430065000827916096893408569751085550379620558282942254606978819033885539221416335848319082054806148859427713144286777516251724474319613960327799643723278205969253636514684757409059003348229151341200451785288395596484563480261212963114071064979559812327582474674812225260616757099890896900340007990585501470484762752362734968297532533654846190900571017635959385883945858334995884341767905619567505341752047589731815868489295690574109758825021386698440670611361127170896689015108432408490763723594673299472336065575301681055583084547847733168801030191262122130369687497236959760366874106043801542493392227424890925595734150487586757484304609945827925762382889592743709682485229267604771944535469557860120878491329984792448597107256325783346904408
#n= 609305637099654478882754880905638123124918364116173050874864700996165096776233155524277418132679727857702738043786588380577485490575591029930152718828075976000078971987922107645530323356525126496562423491563365836491753476840795804040219013880969539154444387313029522565456897962200817021423704204077133003361140660038327458057898764857872645377236870759691588009666047187685654297678987435769051762120388537868493789773766688347724903911796741124237476823452505450704989455260077833828660552130714794889208291939055406292476845194489525212129635173284301782141617878483740788532998492403101324795726865866661786740345862631916793208037250277376942046905892342213663197755010315060990871143919384283302925469309777769989798197913048813940747488087191697903624669415774198027063997058701217124640082074789591591494106726857376728759663074734040755438623372683762856958888826373151815914621262862750497078245369680378038995425628467728412953392359090775734440671874387905724083226246587924716226512631671786591611586774947156657178654343092123117255372954798131265566301316033414311712092913492774989048057650627801991277862963173961355088082419091848569675686058581383542877982979697235829206442087786927939745804017455244315305118437
共模攻击,但只知道两个e的乘积,可分解得到:
e_fac = [3, 3, 7, 7, 7]
在多种组合方式中肯定存在不互素的情况,对应进行开方即可:
e1e2 = 3087
e_fac = [3, 3, 7, 7, 7]
fac = [3, 7, 3*3, 3*7, 7*7, 3*3*7, 3*7*7, 7*7*7, 3*3*7*7, 3*7*7*7, 3*3*7*7*7]
c1= ...
c2= ...
n= ...
for e1 in fac:
e2 = e1e2 // e1
s = gcdext(e1, e2)
m1 = pow(c1, s[1], n)
m2 = pow(c2, s[2], n)
m = (m1 * m2) % n
m = iroot(m, gcd(e1,e2))[0]
print(long_to_bytes(m))
考点
共模攻击e不互素
Chal
题目给了一个文件夹,包含了100个.pem文件和100个msgi文件(没有后缀),公钥私钥类型。
读取方法:
n = []
e = []
c = []
file_list1 = glob.glob(r'C:\Users\lenovo\Desktop\text\*.pem')
for file_path in file_list1:
public_key = RSA.importKey(open(file_path, 'rb').read())
n.append(public_key.n)
e.append(public_key.e)
file_list2 = glob.glob(rb'C:\Users\lenovo\Desktop\text\msg*')
for file_path in file_list2:
with open(file_path, 'rb') as f:
msg = bytes_to_long(f.read())
c.append(msg)
一共一百组数据,e均为65537,找下n的公因数,找到一组,但正常解RSA解不出,这属于PKCS1_OAEP模式下的RSA加密,需手动构造私钥去解密密文:
n = [...]
e = 65537
c = [...]
for i in range(len(n)):
for j in range(i+1,len(n)):
if gcd(n[i],n[j]) != 1:
p = gcd(n[i],n[j])
q = n[j] // p
phi = (p-1)*(q-1)
d = invert(e, phi)
privkey = RSA.construct((int(p * q), int(e), int(d), int(p), int(q)))
key = PKCS1_OAEP.new(privkey)
flag = key.decrypt(long_to_bytes(c[j]))
print(flag)
2021第五空间signin
from Crypto.Util.number import *
from secret import flag
p = getPrime(512)
q = getPrime(512)
n = p * q
e = 0x10001
x = (p ^ q) & ((1 << 400) - 1)
m = bytes_to_long(flag)
c = pow(m,e,n)
print("c = " + str(c))
print("e = " + str(e))
print("n = " + str(n))
print("x = " + str(x))
'''
c = 86415476382906786465939442398992406348852252355326334785583474583480585659663836032856765037225261433532613020730103955916772373674295180495452293421279237222544308971840820110279355118064931506637793547489441433938707518241461449059717326341918746156620038847745542794560335988858156929013492541794032580255
e = 65537
n = 166337085427556441543394334802135957169988266794453522153008810336368247289697353242192853337017363111987395194428553050681210209730724596529629525357502302165396675392000087988956194589350195512264427901330860811469484473725396354231555692283910488095918243519370430703255279433498479943391876108577325840381
x = 2509898544460604898497702985357222191225421344430742181152035006910161802193623236888758239071502008180363546424715261788
'''
x = (p ^ q) & ((1 << 400) - 1)
知道pq异或的低400位,可从低位开始爆破出p的低400位,然后构造copper筛选正确的p:
c = 86415476382906786465939442398992406348852252355326334785583474583480585659663836032856765037225261433532613020730103955916772373674295180495452293421279237222544308971840820110279355118064931506637793547489441433938707518241461449059717326341918746156620038847745542794560335988858156929013492541794032580255
e = 65537
n = 166337085427556441543394334802135957169988266794453522153008810336368247289697353242192853337017363111987395194428553050681210209730724596529629525357502302165396675392000087988956194589350195512264427901330860811469484473725396354231555692283910488095918243519370430703255279433498479943391876108577325840381
x = 2509898544460604898497702985357222191225421344430742181152035006910161802193623236888758239071502008180363546424715261788
def findp(p,rp):
l = len(p)
if l == 400:
rp.append(int(p,2))
else:
pp = int(p,2)
qq = (x^^pp)%2**l
if pp*qq%2**l == n%2**l:#p、q低位相乘与n的低位比较
findp('1'+p,rp)
findp('0'+p,rp)
rp=[]
findp('1',rp)
#从最低位开始爆破,通过输出bin(n),知道n的最低位为1,那么p和q的最低位至少有一个为1
for i in range(len(rp)):
PR.<x>=PolynomialRing(Zmod(n))
f=pow(2,400)*x+rp[i]
f=f.monic()
root=f.small_roots(X=2^112,beta=0.4)
if root:
p=rp[i]+pow(2,400)*int(root[0])
q=n//p
if p*q==n:
print(p)
p出了就不说了。
2021第五空间ecc
print 'Try to solve the 3 ECC'
from secret import flag
from Crypto.Util.number import *
assert(flag[:5]=='flag{')
flag = flag[5:-1]
num1 = bytes_to_long(flag[:7])
num2 = bytes_to_long(flag[7:14])
num3 = bytes_to_long(flag[14:])
def ECC1(num):
p = 146808027458411567
A = 46056180
B = 2316783294673
E = EllipticCurve(GF(p),[A,B])
P = E.random_point()
Q = num*P
print E
print 'P:',P
print 'Q:',Q
def ECC2(num):
p = 1256438680873352167711863680253958927079458741172412327087203
#import random
#A = random.randrange(389718923781273978681723687163812)
#B = random.randrange(816378675675716537126387613131232121431231)
A = 377999945830334462584412960368612
B = 604811648267717218711247799143415167229480
E = EllipticCurve(GF(p),[A,B])
P = E.random_point()
Q = num*P
print E
print 'P:',P
print 'Q:',Q
factors, exponents = zip(*factor(E.order()))
primes = [factors[i] ^ exponents[i] for i in range(len(factors))][:-1]
print primes
dlogs = []
for fac in primes:
t = int(int(P.order()) / int(fac))
dlog = discrete_log(t*Q,t*P,operation="+")
dlogs += [dlog]
print("factor: "+str(fac)+", Discrete Log: "+str(dlog)) #calculates discrete logarithm for each prime order
print num
print crt(dlogs,primes)
def ECC3(num):
p = 0xd3ceec4c84af8fa5f3e9af91e00cabacaaaecec3da619400e29a25abececfdc9bd678e2708a58acb1bd15370acc39c596807dab6229dca11fd3a217510258d1b
A = 0x95fc77eb3119991a0022168c83eee7178e6c3eeaf75e0fdf1853b8ef4cb97a9058c271ee193b8b27938a07052f918c35eccb027b0b168b4e2566b247b91dc07
B = 0x926b0e42376d112ca971569a8d3b3eda12172dfb4929aea13da7f10fb81f3b96bf1e28b4a396a1fcf38d80b463582e45d06a548e0dc0d567fc668bd119c346b2
E = EllipticCurve(GF(p),[A,B])
P = E.random_point()
Q = num*P
print E
print 'P:',P
print 'Q:',Q
ECC1(num1)
print '=============='
ECC2(num2)
print '=============='
ECC3(num3)
#Try to solve the 3 ECC
Elliptic Curve defined by y^2 = x^3 + 46056180*x + 2316783294673 over Finite Field of size 146808027458411567
P: (119851377153561800 : 50725039619018388 : 1)
Q: (22306318711744209 : 111808951703508717 : 1)
==============
Elliptic Curve defined by y^2 = x^3 + 377999945830334462584412960368612*x + 604811648267717218711247799143415167229480 over Finite Field of size 1256438680873352167711863680253958927079458741172412327087203
P: (550637390822762334900354060650869238926454800955557622817950 : 700751312208881169841494663466728684704743091638451132521079 : 1)
Q: (1152079922659509908913443110457333432642379532625238229329830 : 819973744403969324837069647827669815566569448190043645544592 : 1)
==============
Elliptic Curve defined by y^2 = x^3 + 490963434153515882934487973185142842357175523008183292296815140698999054658777820556076794490414610737654365807063916602037816955706321036900113929329671*x + 7668542654793784988436499086739239442915170287346121645884096222948338279165302213440060079141960679678526016348025029558335977042712382611197995002316466 over Finite Field of size 11093300438765357787693823122068501933326829181518693650897090781749379503427651954028543076247583697669597230934286751428880673539155279232304301123931419
P: (10121571443191913072732572831490534620810835306892634555532657696255506898960536955568544782337611042739846570602400973952350443413585203452769205144937861 : 8425218582467077730409837945083571362745388328043930511865174847436798990397124804357982565055918658197831123970115905304092351218676660067914209199149610 : 1)
Q: (964864009142237137341389653756165935542611153576641370639729304570649749004810980672415306977194223081235401355646820597987366171212332294914445469010927 : 5162185780511783278449342529269970453734248460302908455520831950343371147566682530583160574217543701164101226640565768860451999819324219344705421407572537 : 1)
ECC1:
直接离散对数求解:
p = 146808027458411567
A = 46056180
B = 2316783294673
E = EllipticCurve(GF(p),[A,B])
P = E(119851377153561800,50725039619018388)
Q = E(22306318711744209,111808951703508717)
num1 = P.discrete_log(Q)
print(num1)
#13566003730592612
ECC2:
阶部分光滑,直接用后面给的hellman算法代码:
A = 377999945830334462584412960368612
B = 604811648267717218711247799143415167229480
E = EllipticCurve(GF(p),[A,B])
P = E(550637390822762334900354060650869238926454800955557622817950,700751312208881169841494663466728684704743091638451132521079)
Q = E(1152079922659509908913443110457333432642379532625238229329830,819973744403969324837069647827669815566569448190043645544592)
factors, exponents = zip(*factor(E.order()))
primes = [factors[i] ^ exponents[i] for i in range(len(factors))][:-1]
print(primes)
dlogs = []
for fac in primes:
t = int(int(P.order()) // int(fac))
dlog = discrete_log(t*Q,t*P,operation="+")
dlogs += [dlog]
print("factor: "+str(fac)+", Discrete Log: "+str(dlog)) #calculates discrete logarithm for each prime order
print(crt(dlogs,primes))
#16093767336603949
ECC3:
阶数与p相等,smart’s attack,套用攻击脚本:
p = 0xd3ceec4c84af8fa5f3e9af91e00cabacaaaecec3da619400e29a25abececfdc9bd678e2708a58acb1bd15370acc39c596807dab6229dca11fd3a217510258d1b
A = 0x95fc77eb3119991a0022168c83eee7178e6c3eeaf75e0fdf1853b8ef4cb97a9058c271ee193b8b27938a07052f918c35eccb027b0b168b4e2566b247b91dc07
B = 0x926b0e42376d112ca971569a8d3b3eda12172dfb4929aea13da7f10fb81f3b96bf1e28b4a396a1fcf38d80b463582e45d06a548e0dc0d567fc668bd119c346b2
E = EllipticCurve(GF(p),[A,B])
P = E(10121571443191913072732572831490534620810835306892634555532657696255506898960536955568544782337611042739846570602400973952350443413585203452769205144937861,8425218582467077730409837945083571362745388328043930511865174847436798990397124804357982565055918658197831123970115905304092351218676660067914209199149610)
Q = E(964864009142237137341389653756165935542611153576641370639729304570649749004810980672415306977194223081235401355646820597987366171212332294914445469010927,5162185780511783278449342529269970453734248460302908455520831950343371147566682530583160574217543701164101226640565768860451999819324219344705421407572537)
def SmartAttack(P,Q,p):
E = P.curve()
Eqp = EllipticCurve(Qp(p, 2), [ ZZ(t) + randint(0,p)*p for t in E.a_invariants() ])
P_Qps = Eqp.lift_x(ZZ(P.xy()[0]), all=True)
for P_Qp in P_Qps:
if GF(p)(P_Qp.xy()[1]) == P.xy()[1]:
break
Q_Qps = Eqp.lift_x(ZZ(Q.xy()[0]), all=True)
for Q_Qp in Q_Qps:
if GF(p)(Q_Qp.xy()[1]) == Q.xy()[1]:
break
p_times_P = p*P_Qp
p_times_Q = p*Q_Qp
x_P,y_P = p_times_P.xy()
x_Q,y_Q = p_times_Q.xy()
phi_P = -(x_P/y_P)
phi_Q = -(x_Q/y_Q)
k = phi_Q/phi_P
return ZZ(k)
num3 = SmartAttack(P,Q,p)
print(num3)
#19597596255129283097357413993866074145935170485891892
2021第五空间secrets
import random, hashlib
from Crypto.Util.number import *
from Crypto.Cipher import AES
from secret import flag
assert(flag[:5] == b"flag{" and flag[-1:] == b"}")
flag = flag[5:-1]
p = getPrime(512)
secrets = [getPrime(32) for i in range(3)]
a = [getPrime(511) for i in range(3)]
e = [[random.randint(0,2) for i in range(3)] for j in range(3)]
c = 0
for i in range(3):
tmp = 1
for j in range(3):
tmp *= secrets[j] ** e[i][j]
c += a[i] * tmp
c %= p
key = hashlib.sha256(str(secrets).encode()).digest()
cipher = AES.new(key, AES.MODE_ECB)
enc_flag = cipher.encrypt(flag).hex()
print(p)
print(a)
print(e)
print(c)
print(enc_flag)
'''
7920896218820943056702891053785968782942077704655549145065876361907786355057528237061821280280635146678227702121299090049267547565989625947956850127609879
[5159988341992193282580685525745512910538614629527934692498086718630359717994948104271635300443062627349528208661883545208904466234606731357843882012950859, 6335284643679900918720817621948758994408045076082703123014899812263624185305268879304513104269749790342063146501376008458665966651095670658606928517201721, 6076126683981038494289949541335915228950649182831013867715530414744306299113418155691977393469353865827225836608438360416489035800225275307683760086087019]
[[1, 2, 2], [1, 0, 2], [2, 0, 0]]
2262305826865903827781721021939132022253239409560318732728105425007767005455109451147816015758855318893496902119172860305961200859254558917933621119030425
99ff236d4f1e020e6c83cc154e20f71eb510913056d47344b44a87f98664efd3
'''
$c \equiv a_1 s_1s_2^2 s_3^2 + a_2 s_1 s_3^2 +a_3 s_1^2 \pmod p$
格基规约。要让某个线性组合变成一个小值,因为secret就32位,考虑构造成格中的最短向量,变形为:
$c a_3^{-1} = a_3^{-1} a_1 s_1s_2^2 s_3^2 + a_3^{-1} a_2 s_1 s_3^2 + s_1^2 +k p$
$a_3^{-1}c = a_3^{-1} a_1 s_1s_2^2 s_3^2 + a_3^{-1} a_2 s_1 s_3^2+s_1^2 + k p$
造格如下:
$M = \begin{bmatrix}
a_3^{-1}c &&&\
-a_3^{-1}a_1&1&& \
-a_3^{-1}a_2&&1& \
-p&&&1 \
\end{bmatrix} $
(不太能理解怎么造的)
原文:希望最后规约得到的$v = \begin{pmatrix} s_1^2,&s_1s_2^2 s_3^2,& s_1 s_3^2,&k \end{pmatrix}$考虑分量的大小,配一个平衡矩阵:
$LL = \begin{pmatrix}
2^{96}&&&\
&1&&&\
&&&2^{64}&\
&&&&1
\end{pmatrix}$
p = ...
a = [...]
c = ...
enc_flag = ...
LL=diagonal_matrix(ZZ,[2**96,1,2**64,1])
a3_ni = inverse_mod(a[2],p)
M = matrix(ZZ,4,4)
for i in range(3):
M[i+1,i+1] = 1
M[0,0] = a3_ni*c%p
M[1,0] = -a3_ni*a[0]%p
M[2,0] = -a3_ni*a[1]%p
M[3,0] = -p
L = M*LL
v = vector(ZZ,L.LLL()[0])
print(v)
s1 = isqrt(abs(v[0]//2^96))
s3 = isqrt(abs(v[2]//(2^64*s1)))
s2 = isqrt(abs(v[1]//(s1*s3^2)))
print([s1,s2,s3])
#[2328484063, 3354920123, 2829061799]
最后AES解密:
secrets=[2328484063, 3354920123, 2829061799]
key = hashlib.sha256(str(secrets).encode()).digest()
cipher = AES.new(key, AES.MODE_ECB)
c=long_to_bytes(0x99ff236d4f1e020e6c83cc154e20f71eb510913056d47344b44a87f98664efd3)
m=cipher.decrypt(c)
print(m)
找了很多wp,造的格各有各的特色,很懵。
另一种参考writeup-for-2021-第五空间 · K1rit0’s Blog
但求不出正确结果,数据不太一样,但应该没影响吧。如下:
$0 = a_1 s_1s_2^2 s_3^2 + a_2 s_1 s_3^2 + a_3s_1^2-c+k p$
造格如下:
$M = \begin{bmatrix}
1&&&&a_1\cdot R \
&1&&&a_2\cdot R \
&&1&&a_3\cdot R \
&&&1&-c\cdot R \
&&&&p\cdot R \
\end{bmatrix} $
存在向量:
$v = \begin{pmatrix}s_1s_2^2 s_3^2,& s_1 s_3^2,& s_1^2,&1,& k \end{pmatrix}$
使得$v\cdot M = \begin{pmatrix}s_1s_2^2 s_3^2,& s_1 s_3^2,& s_1^2,&1,&0 \end{pmatrix}$
$R = 2^i$,是为了调格子的det, 调到能找到目标向量为止, 找到等式右边的向量就能得到结果。
还有另一种造法:https://www.anquanke.com/post/id/253524
记录一下吧,佛了,一道题折腾了几个小时。
2021第五空间data_protection
part1和part2是基础RSA不贴了,主要看part3、4、5:
part3:
def encrypt3(msg):
q = getPrime(33)
key = [[] for i in range(34)]
for i in range(len(key)):
for j in range(len(msg)):
tmp = random.getrandbits(32)
assert(tmp<q)
key[i].append(tmp)
cipher = []
for l in key:
tmp = 0
for x,y in zip(l,msg):
tmp = (tmp+x*y)%q
cipher.append(tmp)
print (q)
print (key)
print (cipher)
msg3 = [x for x in mail]
encrypt3(msg3)
矩阵运算$c = key\cdot m \pmod q$
则m = key.solve_right(c):
key = [...]
q = ...
c = ...
key = Matrix(GF(q),key)
c = vector(GF(q),c)
m = key.solve_right(c)
m=list(m)
print(bytes(m))
part4:
def encrypt4(msg):
key = long_to_bytes(random.getrandbits(128))
a = AES.new(key,AES.MODE_ECB)
cipher = a.encrypt(msg)
print (bytes_to_long(cipher))
msg4 = address
encrypt4(msg4)
part5:
def encrypt5(msg):
q = getPrime(512)
g = random.randrange(q-1)
x = random.randrange(q-1)
h = pow(g,x,q)
y = random.randrange(q-1)
s = pow(h,y,q)
c1 = pow(g,y,q)
c2 = (msg*s)%q
print (q,g,h)
print (c1,c2)
msg5 = bytes_to_long(school)
encrypt5(msg5)
2021第五空间crypto - hash_hash - 博客园 (cnblogs.com)
SUSCTFlarge case
from Crypto.Util.number import *
from secret import e,message
def pad(s):
if len(s)<3*L:
s+=bytes(3*L-len(s))
return s
L=128
p=127846753573603084140032502367311687577517286192893830888210505400863747960458410091624928485398237221748639465569360357083610343901195273740653100259873512668015324620239720302434418836556626441491996755736644886234427063508445212117628827393696641594389475794455769831224080974098671804484986257952189021223
q=145855456487495382044171198958191111759614682359121667762539436558951453420409098978730659224765186993202647878416602503196995715156477020462357271957894750950465766809623184979464111968346235929375202282811814079958258215558862385475337911665725569669510022344713444067774094112542265293776098223712339100693
r=165967627827619421909025667485886197280531070386062799707570138462960892786375448755168117226002965841166040777799690060003514218907279202146293715568618421507166624010447447835500614000601643150187327886055136468260391127675012777934049855029499330117864969171026445847229725440665179150874362143944727374907
n=p*q*r
assert isPrime(GCD(e,p-1)) and isPrime(GCD(e,q-1)) and isPrime(GCD(e,r-1)) and e==GCD(e,p-1)*GCD(e,q-1)*GCD(e,r-1)
assert len(message)>L and len(message)<2*L
assert b'SUSCTF' in message
m=bytes_to_long(pad(message))
c=pow(m,e,n)
print(c)
'''
2832775557487418816663494645849097066925967799754895979829784499040437385450603537732862576495758207240632734290947928291961063611897822688909447511260639429367768479378599532712621774918733304857247099714044615691877995534173849302353620399896455615474093581673774297730056975663792651743809514320379189748228186812362112753688073161375690508818356712739795492736743994105438575736577194329751372142329306630950863097761601196849158280502041616545429586870751042908365507050717385205371671658706357669408813112610215766159761927196639404951251535622349916877296956767883165696947955379829079278948514755758174884809479690995427980775293393456403529481055942899970158049070109142310832516606657100119207595631431023336544432679282722485978175459551109374822024850128128796213791820270973849303929674648894135672365776376696816104314090776423931007123128977218361110636927878232444348690591774581974226318856099862175526133892
'''
求解题目关键:
- 求解e
- 解出e后,解决e与欧拉函数不互素
求解e
设$ep$是$e$与$p-1$的最大公因数,利用费马小定理:
$ a^{p-1}\equiv a^{\frac{ep\cdot(p-1)}{ep}} \equiv (a^{ep}\pmod p)^{\frac{p-1}{ep}}\equiv 1\pmod p $
又$c \equiv m^e \pmod n \equiv m^{ep\cdot eq\cdot er} \pmod {pqr}$
可得:$c \pmod p \equiv (m^{ep} \pmod p)^{\frac{p-1}{ep}\cdot eq\cdot er} \pmod p = 1 \pmod p$
用$c \pmod p$替代$m^{ep} \pmod p$,检验$c^{\frac{p-1}{ep}} \equiv 1 \pmod p$
由此依次计算出$ep、eq、er$
p_list = [2, 7, 757, 1709, 85015583, 339028665499, 149105250954771885483776047, 1642463892686572578602085475101104723805585678675707586553009837707279291648160744722745420570786735582631019452016654157586623543454908938807521637550223579103317696104438456966780396624343550451096013730928292041667133825444056448136643704677066463120079]
q_list = [2, 2, 3, 3, 66553, 81768440203, 84405986771, 38037107558208320033, 16137718604846030589135490851713, 14369576056311038198362075935199486201201115381094289671031774994452214307042971166730146897009438957078052300683916910041250723573953110349566216311685009675744215421971185909678546052934704709232060199286321405045769976194110037]
r_list = [2, 5156273, 10012111, 11607389, 68872137169799749, 9691125310820433463, 12030248809636768339, 31518759824860728158228953, 547187028373506113438510511293209786101461141918516130626947626757753454448192055890412658699775890681515562519111190252566146302544199621791901997687741038739625529014337424946054655263007302018300326403871]
for ep in p_list:
if pow(c%p,(p-1)//ep,p) == 1 and ep != 2:
print(ep)#757
break
for eq in q_list:
if pow(c%q,(q-1)//eq,q) == 1 and eq != 2:
print(eq)#66553
break
for er in r_list:
if pow(c%r,(r-1)//er,r) == 1 and er != 2:
print(er)#5156273
break
#等于2的情况无根,可用iroot验证
e = 757*66553*5156273
#259776235785533
解决e与$\phi(n)不互素$
e还是很大,采取AMM应该会很慢。
根据论文,有下面的方法:
首先
令$\phi = \frac{\phi(n)}{e} ,g = 1$
循环$g = g + 1 ,gE \equiv g^{\phi} \pmod n$
直到出现$gE \neq 1$的$gE$,代码实现:
phi = phi_n//e
g = 1
gE = pow(g,phi,n)
while gE == 1:
g += 1
gE = pow(g,phi,n)
接着
计算$d \equiv e^{-1} \pmod \phi,a \equiv c^d \pmod n$
判断a转换为字节/字符类型之后,是否有flag的信息
若没有,进行e次循环
循环体:$a \equiv a\cdot gE \pmod n$,代码实现:
d = inverse(e,phi)
a = pow(c,d,n)
for _ in range(e):
flag = a
if msg in long_to_bytes(flag):
print(long_to_bytes(flag))
break
else:
a = a*gE % n
因为e太大了,执行e次循环根本跑不完,想办法约简。
让$e = e//r$,且有$er\cdot dr \equiv 1 \pmod {\phi(n)}$相关参数也作改变,
$\phi(n) = (p-1)\cdot (q-1)$,$n = n//r$
$c \equiv m^{ep\cdot eq\cdot er} \pmod n$
$c^{dr} \equiv m^{er\cdot dr\cdot eq\cdot ep} \pmod n$
可得:$c\equiv c^{dr} \pmod n$
同时我们看到assert对明文的断言,长度在L到2L间,也就是1024bit到2048bit。那么明文至少要填充1024bit的\x00。当我们选择舍弃了r后,就需要把多余2048bit的填充的\x00除掉:
$c \equiv (m\cdot2^{1024})^e \pmod n$
$c\cdot 2^{-1024e} \equiv m^e \pmod n$
这部分代码如下:
ep = 757
eq = 66553
er = 5156273
e = 757*66553*5156273
c = c*inverse(2**(1024*e),n) % n
e = e // er
phi_n = (p - 1) * (q - 1)
n = n // r
dr = inverse(er,phi_n)
c = pow(c,dr,n)
phi = phi_n // e
g = 1
gE = pow(g,phi,n)
while gE == 1:
g = g + 1
gE = pow(g,phi,n)
d = inverse(e,phi)
a = pow(c,d,n)
for _ in tqdm(range(e)):
flag = a
if b"SUSCTF" in long_to_bytes(flag):
print()
print(long_to_bytes(flag))
break
else:
a = a * gE % n
用了近10分钟,还是挺久的。
参考:SUSCTF_Crypto_large case_复现_M3ng@L的博客-CSDN博客
也试一下AMM:
从开始到去除明文多余2048bit的填充部分的操作一样,不一样的是后面的操作。
$c \equiv m^{ep\cdot eq\cdot er} \pmod n$
$e \cdot d \equiv 1 \pmod {\phi(n)}$
分别计算模p和模q下的情况:
$ep\cdot eq\cdot er\cdot dp \equiv 1\pmod {(p-1)}$
$eq\cdot eq\cdot er\cdot dq \equiv 1\pmod {(q-1)}$
$cp \equiv c^{dp} \pmod p$
$cq \equiv c^{dq} \pmod q$
接着便是套用AMM模板了,上面的部分相同就不贴了:
import time
import random
...
def AMM(o, r, q):
start = time.time()
print('\n----------------------------------------------------------------------------------')
print('Start to run Adleman-Manders-Miller Root Extraction Method')
print('Try to find one {:#x}th root of {} modulo {}'.format(r, o, q))
g = GF(q)
o = g(o)
p = g(random.randint(1, q))
while p ^ ((q-1) // r) == 1:
p = g(random.randint(1, q))
print('[+] Find p:{}'.format(p))
t = 0
s = q - 1
while s % r == 0:
t += 1
s = s // r
print('[+] Find s:{}, t:{}'.format(s, t))
k = 1
while (k * s + 1) % r != 0:
k += 1
alp = (k * s + 1) // r
print('[+] Find alp:{}'.format(alp))
a = p ^ (r**(t-1) * s)
b = o ^ (r*alp - 1)
c = p ^ s
h = 1
for i in range(1, t):
d = b ^ (r^(t-1-i))
if d == 1:
j = 0
else:
print('[+] Calculating DLP...')
j = - discrete_log(d, a)
print('[+] Finish DLP...')
b = b * (c^r)^j
h = h * c^j
c = c^r
result = o^alp * h
end = time.time()
print("Finished in {} seconds.".format(end - start))
print('Find one solution: {}'.format(result))
return result
def findAllPRoot(p, e):
print("Start to find all the Primitive {:#x}th root of 1 modulo {}.".format(e, p))
start = time.time()
proot = set()
while len(proot) < e:
proot.add(pow(random.randint(2, p-1), (p-1)//e, p))
end = time.time()
print("Finished in {} seconds.".format(end - start))
return proot
def findAllSolutions(mp, proot, cp, p):
print("Start to find all the {:#x}th root of {} modulo {}.".format(e, cp, p))
start = time.time()
all_mp = set()
for root in proot:
mp2 = mp * root % p
all_mp.add(mp2)
end = time.time()
print("Finished in {} seconds.".format(end - start))
return all_mp
dp = inverse(eq*er,p-1)
cp = pow(c,dp,p)
dq = inverse(ep*er,q-1)
cq = pow(c,dq,q)
print(cp,cq)
mp = AMM(cp, ep, p)
mq = AMM(cq, eq, q)
p_proot = findAllPRoot(p, ep)
q_proot = findAllPRoot(q, eq)
mps = findAllSolutions(mp, p_proot, cp, p)
mqs = findAllSolutions(mq, q_proot, cq, q)
start = time.time()
print('Start CRT...')
for mpp in mps:
print(mpp)
for mqq in mqs:
solution = crt([int(mpp), int(mqq)], [p, q])
if b'SUSCTF' in long_to_bytes(solution):
print(long_to_bytes(solution))
end = time.time()
print("Finished in {} seconds.".format(end - start))
执行的时间似乎要更久。
SUSCTF 2022 - hash_hash - 博客园 (cnblogs.com)
2022 SUSCTF SU Writeup | TEAM-SU (su-team.cn)
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 1666739907@qq.com