2024SHCTF--Crypto--Week1&Week2--WP
2024SHCTF
注:针对2024SHCTF赛事,写下自己的解题思路以及个别赛题赛后复现对于题目而产生的理解。
Week1
d_known
task:
from Crypto.Util.number import *
from gmpy2 import*
from flag import flag
m = bytes_to_long(flag)
p = getPrime(1024)
q = next_prime(p)
n = p * q
e = 0x10001
d = inverse(e, (p-1) * (q-1))
c = pow(m, e, n)
print(c)
print(d)
'''
c = 2023280206852799756188533543726445899210461674882103741449846207085209158128274530066961712554168490693338804965645257201915901430270289914927031884869765066207700835767543832965446328994297771171239554854439801951855734405930228978819264617926307331498279823792404896708489491845814993901912406921233209174052585982422702902921150509799525025006961668679058706680338445147732742087594370544143929344692878849762859325278353499113047627166145064375388330723568647380571912097704007649949039872655521965438358883046062395057460962164069910080794938688401346483471199715397419486956888803799635787660289917216321436075
d = 5325557477974651131933634251521791991925782269036709550928544143247135213750451805876289560548176503358408907072006083232605644148148348426759760165848721826856045819883560475601424759644170039021289236399016340754732526066778542800516887549418899285710399950124543460448926261999153088331976259647327700619342183115011084680629309966651674276478502656272680143227400879298842573111724783827297704483713490258469730037991356794901334012297158591206594636469676973210545148034611453362521846968132369356368152162040634155912080095620977164991291750678677808423018575966921693161165571968455135962605729487885568490033
'''
analysis:
已知d,
e.bit_length = 17;d.bit_length = 2046;phi.bit_length≈2048,所以可以大致推出k的位数,爆破求出phi
然后求出p,q,q = next_prime(p),p,q接近,直接对phi开方然后用next_prime,prevprime即可求解p,q
tqdm: tqdm是一个快速、扩展性很强的Python库,用于在长循环中添加一个进度提示信息,能够给用户一个直接的反馈。range-->trange
exp:
from Crypto.Util.number import *
from sympy import *
from gmpy2 import *
from tqdm import *
c = 2023280206852799756188533543726445899210461674882103741449846207085209158128274530066961712554168490693338804965645257201915901430270289914927031884869765066207700835767543832965446328994297771171239554854439801951855734405930228978819264617926307331498279823792404896708489491845814993901912406921233209174052585982422702902921150509799525025006961668679058706680338445147732742087594370544143929344692878849762859325278353499113047627166145064375388330723568647380571912097704007649949039872655521965438358883046062395057460962164069910080794938688401346483471199715397419486956888803799635787660289917216321436075
d = 5325557477974651131933634251521791991925782269036709550928544143247135213750451805876289560548176503358408907072006083232605644148148348426759760165848721826856045819883560475601424759644170039021289236399016340754732526066778542800516887549418899285710399950124543460448926261999153088331976259647327700619342183115011084680629309966651674276478502656272680143227400879298842573111724783827297704483713490258469730037991356794901334012297158591206594636469676973210545148034611453362521846968132369356368152162040634155912080095620977164991291750678677808423018575966921693161165571968455135962605729487885568490033
e = 65537
kphi = e*d - 1
for k in trange(2**13,2**17):
if kphi % k == 0:
phi = kphi // k
p = next_prime(iroot(phi,2)[0])
q = prevprime(iroot(phi,2)[0])
if d == inverse(e,(p-1)*(q-1)):
m = pow(c,d,p*q)
print(long_to_bytes(m))
# SHCTF{53398660-8e40-460d-9f28-2b25b687fbe9}
baby_mod
task:
from Crypto.Util.number import *
from enc import flag
m = bytes_to_long(flag)
p = getPrime(512)
q = getPrime(512)
r = getPrime(777)
t = getPrime(777)
tmp = getPrime(15)
e = 65537
n = p*q
print(f"c = {pow(m,e,n)}")
print(f"leak = {p*r-q*t-tmp}")
print(f"r = {r}")
print(f"t = {t}")
'''
c = 17937472553998606504669747140789726307439582196963451030969242254157949062129324494114590658920012871180079814675678946453897865233224992985089451278231663618857965418389487647355253063941790618808955858162224234190981820557457655720791346278352310012094147015720264246236621546172323951815149898363856098823
leak = -1587213174398707503036319512989790705844433773053364648490744871188009448006267321887626866013134130998268382756317172409049882250682995546076129821312371197174231288418315516151931068209717088211878340641266286735555866264605212381502721300165430517113230358235888004114974340620550567298211707561178407907225299235498063377164047589836058708230195966901891786125922264824283899806368097
r = 466415729162296733529092458774194130369566652709805609481844599849536821250812719015532685709318199315612306114406654748660375049578603355246845205423401652241172615507957208288364106021726317326899229799053280291178121413651628535023
t = 635316670184189895492730019113841833333699743242997516619486647136468690062607793643684031305893867906907074562340028701514502349937069085426784869269608878466785830130266100418807129895963018317044053909910919832387196116916663544813
'''
analysis:
此时有r,t,leak也就是说tmp确定时我们即可利用(leak+tmp)*inverse(r,t)%t求解p。
exp:
from Crypto.Util.number import *
# Given values
e = 65537
c = 17937472553998606504669747140789726307439582196963451030969242254157949062129324494114590658920012871180079814675678946453897865233224992985089451278231663618857965418389487647355253063941790618808955858162224234190981820557457655720791346278352310012094147015720264246236621546172323951815149898363856098823
leak = -1587213174398707503036319512989790705844433773053364648490744871188009448006267321887626866013134130998268382756317172409049882250682995546076129821312371197174231288418315516151931068209717088211878340641266286735555866264605212381502721300165430517113230358235888004114974340620550567298211707561178407907225299235498063377164047589836058708230195966901891786125922264824283899806368097
r = 466415729162296733529092458774194130369566652709805609481844599849536821250812719015532685709318199315612306114406654748660375049578603355246845205423401652241172615507957208288364106021726317326899229799053280291178121413651628535023
t = 635316670184189895492730019113841833333699743242997516619486647136468690062607793643684031305893867906907074562340028701514502349937069085426784869269608878466785830130266100418807129895963018317044053909910919832387196116916663544813
for temp in range(2**14,2**15):
if isPrime(temp):
p = (leak + temp) * inverse(r, t) % t
if isPrime(p):
q = (p * r - leak - temp) // t
if isPrime(q):
phi = (p - 1) * (q - 1)
d = inverse(e, phi)
m = pow(c, d, p * q)
flag = long_to_bytes(m)
print(flag)
break
# SHCTF{0055b9ad-d96a-4d43-a9a9-28ecb08d557e}
Week2
worde很大
task:
import gmpy2
from Crypto.Util.number import *
from enc import flag
m = bytes_to_long(flag)
p = getPrime(512)
q = getPrime(512)
n = p*q
e = getPrime(200)
d = gmpy2.invert(e,(p-1)*(q-1))
dp = d % (p-1)
c = pow(m,e,n)
print(f"n = {n}")
print(f"c = {c}")
print(f"e = {e}")
print(f"dp = {dp}")
'''
n = 107032957087630288996268413289950221007178661091952415803799204807322719946773789072727097283876411371451855146945178785099365053975022744275499071412639566826876925607457076160736517239727314406122177641305989161650710675377046111659861132320470194374212535258339049977749925125713806268856103059658246838823
c = 13426059268971299890058502967962382039319233826881681062400371816555313938352978412770129453032021159626652883952418968332266876616888219630681123569091893928354304104629165208088101777538952907693381585125393549212184411084081938892612243511190758716729464349148805390375073663394447190303250531328411306179
e = 940179304603814149880259136688231799983345424885109815443153
dp = 1389519949170420652498985591042020010547189625918115450421402099250611740108790835840554944891132491698692658805867305372374541674726218271082297905819817
'''
analysis:
dp泄露,但是e很大,利用费马小定理可以求出p
exp:
from Crypto.Util.number import *
n = 107032957087630288996268413289950221007178661091952415803799204807322719946773789072727097283876411371451855146945178785099365053975022744275499071412639566826876925607457076160736517239727314406122177641305989161650710675377046111659861132320470194374212535258339049977749925125713806268856103059658246838823
c = 13426059268971299890058502967962382039319233826881681062400371816555313938352978412770129453032021159626652883952418968332266876616888219630681123569091893928354304104629165208088101777538952907693381585125393549212184411084081938892612243511190758716729464349148805390375073663394447190303250531328411306179
e = 940179304603814149880259136688231799983345424885109815443153
dp = 1389519949170420652498985591042020010547189625918115450421402099250611740108790835840554944891132491698692658805867305372374541674726218271082297905819817
p = GCD(pow(5,e*dp,n)-5,n)
q = n // p
phi_n = (p-1) * (q-1)
d = inverse(e,phi_n)
m = pow(c,d,n)
flag = long_to_bytes(m)
print(flag)
#SHCTF{worD_E_YOU_d1aN_DA_EA7zaA}
pading
task:
from Crypto.Util.number import *
import gmpy2
flag = b'SHCTF{********}'
assert len(flag) == 39
p = getPrime(512)
q = getPrime(512)
n = p * q
e = 0x3
pad = b'a_easy_problem'
c = pow(bytes_to_long(flag + pad),e,n)
print(f'n = {n}')
print(f'c = {c}')
'''
n = 75098630616111482769180659620329958045667354926061075208260621193990567410087157843957397740063249813712091785246064471170031967563730722416238514564741845799209165882736179507743810974327683565208643579519017836211681069084365442156637269419638211790587926949896791807497864162801395061736248644788921667789
c = 3638646373008661843144668651345881752890064263891078270562520797735374345440840522319031089914051142881157757879267055752918804376422359639737717683576378097238618841707519724197204326012840131370755503486240820145945437287578597232976614322766435861623599998349726858207129492804638826767780589762299083258
'''
analysis:
此题对于flag+pad进行加密,小e,并且已知pad,隶属于高位攻击,使用coppersmith算法求解。
flag的二进制位时39*8=312,e次方之后是312*3=936而n的位数是1024,312的flag相对于1024的n来说是小值,可用coppersmith的方法求解。
beta的值依据912/1024=0.89取整0.8,epslilon慢慢放小。对于多项式的方程而言
现有一个e阶的多项式f,那么可以:f =
2.在模n意义下,快速求出
coppersmith: 在RSA中,高位攻击,已知部分二进制位,通过coppersmith定理(里面应用了LLL算法)求剩余二进制位。p,q位数一致时,unkown_bits/p_bits≤0.44.sagemath中的small_roots(X= ,beta= ),beta选在0.4.
small_roots: 使用small_roots时,多设一个参数epsilon,让里面构造的格大一点,就可以不用爆破直接出结果了,epsilon越小,造出来的格越大。在不设置的情况下默认为beta/8,这里就是0.4*8=0.05,这样跑不出来结果,就可以尝试缩小epsilon的值,可以通过逐步减小的值来求解答案epsilon=0.026就可以出结果。当epslion过小时,格过大,LLL算法会非常耗时,这里测试epsilon=0.01就需要一点时间了。所以一般取0.01左右出不来,就得考虑方法问题了。
exp:
from Crypto.Util.number import *
n = 75098630616111482769180659620329958045667354926061075208260621193990567410087157843957397740063249813712091785246064471170031967563730722416238514564741845799209165882736179507743810974327683565208643579519017836211681069084365442156637269419638211790587926949896791807497864162801395061736248644788921667789
c = 3638646373008661843144668651345881752890064263891078270562520797735374345440840522319031089914051142881157757879267055752918804376422359639737717683576378097238618841707519724197204326012840131370755503486240820145945437287578597232976614322766435861623599998349726858207129492804638826767780589762299083258
e=3
pre=b'SHCTF{'
suf=b'}a_easy_problem'
flag_length=39
# 去除高位,即SHCTF{
pre_bits=(flag_length+len(suf)-1-len(pre))*8
# 计算后面已知明文的bits
suf_bits=len(suf)*8
# 计算未知的bits
unknown_bits=(flag_length-len(pre)-1)*8
PR.<x> = PolynomialRing(Zmod(n))
# f = m^e-c
# x即unknown的部分
# bytes_to_long(a+b)≠bytes_to_long(a)+bytes_to_long(b);bytes_to_long(a+b)=bytes_to_long(a)*2^(len(a)*8)
f=(bytes_to_long(pre)*2^pre_bits+x*2^suf_bits+bytes_to_long(suf))^e-c
f=f.monic()
m=f.small_roots(X=2^unknown_bits,beta=0.4,epsilon=0.026)
if m:
x=m[0]
flag=pre+long_to_bytes(int(x))+suf
print(flag)
#b'SHCTF{4RE_yOu_PaDddln9_mE_8oY_EIz66G45}a_easy_problem'
ezECC
from Crypto.Util.number import *
from flag import flag
assert flag.startswith(b'SHCTF{')
m = next_prime(bytes_to_long(flag))
p = getPrime(512)
a,b = getPrime(128),getPrime(128)
E = EllipticCurve(Zmod(p),[a,b])
k = getPrime(256)
A1 = E.random_point()
A2 = A1*k
M = E.lift_x(m)
C = M+A2
print('p = ',p)
print('k = ',k)
print('A1 = ',A1)
print('C = ',C)
data:
p = 9799485259524549113003780400336995829253375211044694607315372450399356814285244762186468904824132005209991983177601498069896166228214442123763065076327679
k = 73771953838487511457389800773038323262861649769228176071578897500004883270121
A1 = (5945412329827707694132352090606154232045921322662767755331097180167148601629747751274580872108985870208681845078153424348847330421799769770041805208089791 : 4113102573821904570542216004200810877456931033522276527318388416329888348077285857968081007666714313806776668203284797556825595791189566621228705928598709 : 1)
C = (2336301464307188733995312208152021176388718095735565422234047912672553316288080052957448196669174030921526180747767251838308335308474037066343018337141276 : 6868888273736103386336636953449998615833854869329393895956720058438723636197866928342387693671211918574357564701700555086194574821628053750572619551290025 : 1)
analysis:
已知A1和C两个在曲线上地点和曲线地p值,根据曲线
两个式子相减求得a和b.构造曲线,由于C=M+A2,且A2=kA1,A1和k的值都已知。M=C-kA1求得M的值,由于M的x坐标是明文m的下一个素数,爆破即可。
点的处理: 对于题目给出数据的点,我们要进行修改,因为sagemath中的点要求(x,y)而非(x:y:1)
遗留问题: sympy中的prevprime函数的使用方法。
exp:
from Crypto.Util.number import *
p = 9799485259524549113003780400336995829253375211044694607315372450399356814285244762186468904824132005209991983177601498069896166228214442123763065076327679
k = 73771953838487511457389800773038323262861649769228176071578897500004883270121
A1 = (5945412329827707694132352090606154232045921322662767755331097180167148601629747751274580872108985870208681845078153424348847330421799769770041805208089791 , 4113102573821904570542216004200810877456931033522276527318388416329888348077285857968081007666714313806776668203284797556825595791189566621228705928598709 )
C = (2336301464307188733995312208152021176388718095735565422234047912672553316288080052957448196669174030921526180747767251838308335308474037066343018337141276 , 6868888273736103386336636953449998615833854869329393895956720058438723636197866928342387693671211918574357564701700555086194574821628053750572619551290025 )
a = inverse(A1[0]-C[0],p)*((A1[1]**2-A1[0]**3)-(C[1]**2-C[0]**3))% p
b = (C[1]**2-C[0]**3-a*C[0])%p
E = EllipticCurve(Zmod(p),[a,b])
A1 = E(A1)
C = E(C)
M = C-k*A1
mm = (M.xy())[0]
for i in range(292):
m = long_to_bytes(int(mm-i))
if m.endswith(b'}'):
print(m)
魔鬼的步伐
task:
from Crypto.Util.number import *
from random import choice
from enc import flag
m = bytes_to_long(flag)
def get_primes(limit):
primes = []
is_prime = [True] * (limit + 1)
for num in range(2, limit + 1):
if is_prime[num]:
primes.append(num)
for multiple in range(num * num, limit + 1, num):
is_prime[multiple] = False
return primes
def get_Prime(bits):
while True:
n = 2
while n.bit_length() < bits:
n *= choice(primes)
if isPrime(n + 1):
return n + 1
e = 65537
primes = get_primes(e)
p = get_Prime(512)
q = get_Prime(512)
n = p*q
c = pow(m,e,n)
print(f"n = {n}")
print(f"e = {e}")
print(f"c = {c}")
'''
n = 779579301738188606639541475585479048662338414978423162511086618350581959037809676355175033940672838358216296034989613684765924879020007985463372880378958453235938149726732804842653385407460552866449233717559756619739481517089434393605029261842182116054349584175198599481092380973944251651872382058614325364639417
e = 65537
c = 547032040563518540116157223879027303340872416038133089003193905244978422560735616179910978730578423924420033057963791332760379132346877909806353927165538096867865399527460216074519919572776729647581400118345644864260152466704275743378828075020134070702051989890847762735538767329450466068109132805742740564390842
'''
analysis:
欧拉函数φ(n): 给定一个正整数 n,欧拉函数就是求在 [1,n) 区间上,与 n互质的整数的个数。举例来说,设m = 8,则与8互质的正整数集合A={1, 3, 5, 7},此集合共有4个元素,所以 φ ( 8 ) = 4。
欧拉定理: 对任意两个正整数 a , n ,若两者互素,则:对比费马小定理,实际上就是欧拉定理的特殊情况。
所以只要指数是模数n的欧拉函数的倍数,在模n下就等于1.
对于本题中的情况:
求解φ(n)即可。
exp:
from Crypto.Util.number import *
# Given values
n = 779579301738188606639541475585479048662338414978423162511086618350581959037809676355175033940672838358216296034989613684765924879020007985463372880378958453235938149726732804842653385407460552866449233717559756619739481517089434393605029261842182116054349584175198599481092380973944251651872382058614325364639417
e = 65537
c = 547032040563518540116157223879027303340872416038133089003193905244978422560735616179910978730578423924420033057963791332760379132346877909806353927165538096867865399527460216074519919572776729647581400118345644864260152466704275743378828075020134070702051989890847762735538767329450466068109132805742740564390842
# 初始化生成光滑数的列表get_primes(e)
def get_primes(limit):
primes = []
is_prime = [True] * (limit + 1)
for num in range(2, limit + 1):
if is_prime[num]:
primes.append(num)
for multiple in range(num * num, limit + 1, num):
is_prime[multiple] = False
return primes
# 由于n = p * q ,而p,q分别由一个get_primes生成,所以最终n的列表应该是2*get_primes(e)
primes_value = get_primes(e) + get_primes(e)
# 求解φ(n)
def Solve(n):
counter = 0
for p in primes_value:
if n % p == 0:
counter += 1
return n - counter - 2 # 减去1和n的两种情况
# 取素数2当作最初的a,在φ(n)的范围内不断增大指数寻找GCD(a^{k*φ(n)}-1,n) != 0和 != n
a = 2
for _ in range(2,Solve(n)):
a = pow(a,_,n)
p = GCD(a-1,n)
if p !=1 and p != n:
q = n // p
break
phi_n = (p-1)*(q-1)
d = inverse(e,phi_n)
flag = long_to_bytes(pow(c,d,n))
print(flag)
#SHCTF{1rlCTioN_is_ThE_d3vils_st3P_4s}
E&R
task:
#sage
from Crypto.Util.number import *
from secret import flag
flag = flag[6:-1]
l = len(flag)
m1 = bytes_to_long(flag[:l//2])
m2 = bytes_to_long(flag[l//2:])
#RSA
p = getPrime(256)
q = getPrime(256)
n = p * q
e = 65537
r_q = int(bin(q)[2:][::-1] , 2)
leak = p ^ r_q
c = pow(m2,e,n)
#ECC
E = EllipticCurve(Zmod(n),[114514,1919810])
G = E.lift_x(Integer(m1))
P = G * e
print(f'leak = {leak}')
print(f'n = {n}')
print(f'c = {c}')
print(f'P = {P}')
# leak = 5599968251197363876087002284371721787318931284225671549507477934076746561842
# n = 7120275986401660066259983193598830554385933355254283093021239164350142898387660104515624591378875067038235085428170557400012848874756868985306042421950909
# c = 6803450117490196163076010186755045681029929816618361161925865477601994608941714788803007124967390157378525581080320415602012078322064392991884070073083436
# P = (4143131125485719352848137000299706175276016714942734255688381872061184989156686585992844083387698688432978380177564346382756951426943827434190895490233627 : 3879946878859691332371384275396678851932267609535096278038417524609690721322205780110680003522999409696718745532857001461869452116434787256032366267905519 : 1)
analysis:
剪枝: 剪枝是对于树算法类的题目而言的,通过减去已经计算后的树的枝点来缩短算法的时间复杂度。而在这里则是同时找到p和q高位或低位,要是只找p高位和q低位,爆破条件无法判断,这就是为什么这题需要同时用到pxorq的两端.
剪枝已知条件: p 与 q 的反方向二进制的异或值,共256bit,记为p_xor_q
剪枝搜索方式: 1.从两端向中间搜索 2. 每一次搜索,需利用当前 pxorq 两端的bit位。这是因为,pxorq 的当前最高位对应p的最高位及q的最低位,pxorq 的当前最低位对应p的最低位及q的最高位 (其中最高、最低均是对于当前搜索而言) 3.如果当前需搜索的最高位为”1”,则对应两种可能:p该位为1,q对应低位为0;p该位为0,q对应低位为1。剩下依此类推
剪枝条件: 将p、q未搜索到的位全填0,乘积应小于n 将p、q未搜索到的位全填1,乘积应大于n p、q 低 k 位乘积再取低 k 位,应与 n 的低 k 位相同
exp:
第一部分参考鸡块大神的文章。
from Crypto.Util.number import *
import sys
e = 65537
leak = 5599968251197363876087002284371721787318931284225671549507477934076746561842
n = 7120275986401660066259983193598830554385933355254283093021239164350142898387660104515624591378875067038235085428170557400012848874756868985306042421950909
c = 6803450117490196163076010186755045681029929816618361161925865477601994608941714788803007124967390157378525581080320415602012078322064392991884070073083436
P = (4143131125485719352848137000299706175276016714942734255688381872061184989156686585992844083387698688432978380177564346382756951426943827434190895490233627 , 3879946878859691332371384275396678851932267609535096278038417524609690721322205780110680003522999409696718745532857001461869452116434787256032366267905519)
p_xor_q = str(bin(leak)[2:]).zfill(256)
def find(ph, qh, pl, ql):
l = len(ph)
tmp0 = ph + (256 - 2 * l) * "0" + pl
tmp1 = ph + (256 - 2 * l) * "1" + pl
tmq0 = qh + (256 - 2 * l) * "0" + ql
tmq1 = qh + (256 - 2 * l) * "1" + ql
if (int(tmp0, 2) * int(tmq0, 2) > n):
return
if (int(tmp1, 2) * int(tmq1, 2) < n):
return
if (int(pl, 2) * int(ql, 2) % (2 ** (l - 1)) != n % (2 ** (l - 1))):
return
if (l == 128):
pp0 = int(tmp0, 2)
if (n % pp0 == 0):
pf = pp0
qf = n // pp0
print(pf)
print(qf)
phi = (pf - 1) * (qf - 1)
d = inverse(e, phi)
m1 = pow(c, d, n)
print(long_to_bytes(m1))
exit()
else:
if (p_xor_q[l] == "1" and p_xor_q[255 - l] == "1"):
find(ph + "1", qh + "0", "1" + pl, "0" + ql)
find(ph + "0", qh + "0", "1" + pl, "1" + ql)
find(ph + "1", qh + "1", "0" + pl, "0" + ql)
find(ph + "0", qh + "1", "0" + pl, "1" + ql)
elif (p_xor_q[l] == "1" and p_xor_q[255 - l] == "0"):
find(ph + "1", qh + "0", "0" + pl, "0" + ql)
find(ph + "0", qh + "0", "0" + pl, "1" + ql)
find(ph + "1", qh + "1", "1" + pl, "0" + ql)
find(ph + "0", qh + "1", "1" + pl, "1" + ql)
elif (p_xor_q[l] == "0" and p_xor_q[255 - l] == "1"):
find(ph + "0", qh + "0", "1" + pl, "0" + ql)
find(ph + "0", qh + "1", "0" + pl, "0" + ql)
find(ph + "1", qh + "0", "1" + pl, "1" + ql)
find(ph + "1", qh + "1", "0" + pl, "1" + ql)
elif (p_xor_q[l] == "0" and p_xor_q[255 - l] == "0"):
find(ph + "0", qh + "0", "0" + pl, "0" + ql)
find(ph + "1", qh + "0", "0" + pl, "1" + ql)
find(ph + "0", qh + "1", "1" + pl, "0" + ql)
find(ph + "1", qh + "1", "1" + pl, "1" + ql)
find("1", "1", "1", "1")
# p = 64760524083545528318139240449356269097871629401328435356643510319660757701117
# q = 109947782034870726628911928816041880655659770652764045401662566933641952899777
# -908f-7c002c687387
第二部分ECC,在这里已知n,a,b,P,而m2是就是M的x坐标,那么主要任务就是求出e,对于曲线的逆元。而n的位数较大,这里试过,无法直接求取模n的曲线的阶,而n = p * q,所以可以转为求模p,模q的阶,之后求取e对于n的逆元。
# sage
from Crypto.Util.number import *
p = 64760524083545528318139240449356269097871629401328435356643510319660757701117
q = 109947782034870726628911928816041880655659770652764045401662566933641952899777
e = 65537
n = 7120275986401660066259983193598830554385933355254283093021239164350142898387660104515624591378875067038235085428170557400012848874756868985306042421950909
P = E(4143131125485719352848137000299706175276016714942734255688381872061184989156686585992844083387698688432978380177564346382756951426943827434190895490233627 , 3879946878859691332371384275396678851932267609535096278038417524609690721322205780110680003522999409696718745532857001461869452116434787256032366267905519)
E = EllipticCurve(Zmod(n),[114514,1919810])
Ep = EllipticCurve(Zmod(p),[114514,1919810])
Eq = EllipticCurve(Zmod(q),[114514,1919810])
phi_n = Ep.order()*Eq.order()
d = inverse(e,phi_n)
G = P * d
m = G[0]
flag = long_to_bytes(int(m))
print(flag)
# a67b2a9b-0542-4646