知识导入:
- 总结:
Franklin-Reiter相关消息攻击(Franklin-Reiter related-message attack):如果两个信息之间存在已知的固定差异,并且在相同的模数n下进行RSA加密,那么就有可能恢复出这两个消息 - 简单点说就是m和m+a两个明文在相同的e和n下进行加密,那么m就可以破解
如果两条消息之间仅存在已知的固定差异
并且在相同的RSA模N下加密
那么就有可能同时恢复它们
m1 = bytes_to_long(flag)
m2 = a * m1 + b
c1 = pow(m1,e,n)
c2 = pow(a * m1 + b,e,n)
其中c1,c2,e,n都已知,那么m1,m2可被破解
- 既然最后解的形式是(x - M)这样的,那么最后只要提结果后面的M即可,这里使用sage中的Q.coefficients()[0]
Q.coefficients() ------ 提取多项式Q中的系数,并且是升序排列
举个栗子:
f = x^3 + 2x^2 -3x + 4
f.coefficients()
返回列表[4,-3,2,1]
f = x^3 + 2x^2 + 4
f.coefficients()
返回列表[4,2,1] # 0省略
最后添个负号即可得到M
题一
题目描述:
from secret import flag
from Crypto.Util.number import *
m1 = bytes_to_long(flag)
N = getPrime(512)*getPrime(512)
e = 17
c1 = pow(m1, e, N)
a = getRandomNBitInteger(512)
b = getRandomNBitInteger(512)
m2 = a * m1 + b
c2 = pow(m2, e, N)
print(N, a, b, c1, c2, sep="\n")
# 51296885372346449295388453471330409021784141081351581975478435681552082076338697136130122011636685327781785488670769096434920591920054441921039812310126089859349902066456998315283909435249794317277620588552441456327265553018986591779396701680997794937951231970194353001576159809798153970829987274504038146741
# 13256631249970000274738888132534852767685499642889351632072622194777502848070957827974250425805779856662241409663031192870528911932663995606616763982320967
# 12614470377409090738391280373352373943201882741276992121990944593827605866548572392808272414120477304486154096358852845785437999246453926812759725932442170
# 18617698095122597355752178584860764221736156139844401400942959000560180868595058572264330257490645079792321778926462300410653970722619332098601515399526245808718518153518824404167374361098424325296872587362792839831578589407441739040578339310283844080111189381106274103089079702496168766831316853664552253142
# 14091361528414093900688440242152327115109256507133728799758289918462970724109343410464537203689727409590796472177295835710571700501895484300979622506298961999001641059179449655629481072402234965831697915939034769804437452528921599125823412464950939837343822566667533463393026895985173157447434429906021792720
题目分析:
典型的Franklin-Reiter相关消息攻击,直接上解题代码:
n=51296885372346449295388453471330409021784141081351581975478435681552082076338697136130122011636685327781785488670769096434920591920054441921039812310126089859349902066456998315283909435249794317277620588552441456327265553018986591779396701680997794937951231970194353001576159809798153970829987274504038146741
a=13256631249970000274738888132534852767685499642889351632072622194777502848070957827974250425805779856662241409663031192870528911932663995606616763982320967
b=12614470377409090738391280373352373943201882741276992121990944593827605866548572392808272414120477304486154096358852845785437999246453926812759725932442170
c1=18617698095122597355752178584860764221736156139844401400942959000560180868595058572264330257490645079792321778926462300410653970722619332098601515399526245808718518153518824404167374361098424325296872587362792839831578589407441739040578339310283844080111189381106274103089079702496168766831316853664552253142
c2=14091361528414093900688440242152327115109256507133728799758289918462970724109343410464537203689727409590796472177295835710571700501895484300979622506298961999001641059179449655629481072402234965831697915939034769804437452528921599125823412464950939837343822566667533463393026895985173157447434429906021792720
e=17
import libnum
def franklinReiter(n,e,c1,c2,a,b):
R.<X> = Zmod(n)[]
f1 = X^e - c1
f2 = (X*a+ b)^e - c2
# coefficient 0 = -m, which is what we wanted!
return Integer(n-(compositeModulusGCD(f1,f2)).coefficients()[0]) # 系数
# GCD is not implemented for rings over composite modulus in Sage
# so we do our own implementation. Its the exact same as standard GCD, but with
# the polynomials monic representation
def compositeModulusGCD(a, b):
if(b == 0):
return a.monic()
else:
return compositeModulusGCD(b, a % b)
m=franklinReiter(n,e,c1,c2,a,b)
print(libnum.n2s(int(m)))
# flag{a593591a-3749-cc52-0c27-e897fac2c967}
或者(本质一样,看起来更简洁一些):
import libnum
n=51296885372346449295388453471330409021784141081351581975478435681552082076338697136130122011636685327781785488670769096434920591920054441921039812310126089859349902066456998315283909435249794317277620588552441456327265553018986591779396701680997794937951231970194353001576159809798153970829987274504038146741
a=13256631249970000274738888132534852767685499642889351632072622194777502848070957827974250425805779856662241409663031192870528911932663995606616763982320967
b=12614470377409090738391280373352373943201882741276992121990944593827605866548572392808272414120477304486154096358852845785437999246453926812759725932442170
c1=18617698095122597355752178584860764221736156139844401400942959000560180868595058572264330257490645079792321778926462300410653970722619332098601515399526245808718518153518824404167374361098424325296872587362792839831578589407441739040578339310283844080111189381106274103089079702496168766831316853664552253142
c2=14091361528414093900688440242152327115109256507133728799758289918462970724109343410464537203689727409590796472177295835710571700501895484300979622506298961999001641059179449655629481072402234965831697915939034769804437452528921599125823412464950939837343822566667533463393026895985173157447434429906021792720
e=17
import binascii
def franklinReiter(n,e,c1,c2,a,b):
PR.<x> = PolynomialRing(Zmod(n))
g1 = (x)^e - c1
g2 = (a*x+b)^e - c2
def gcd(g1, g2):
while g2:
g1, g2 = g2, g1 % g2
return g1.monic() #
return -gcd(g1, g2)[0]
m=franklinReiter(n,e,c1,c2,a,b)
print(libnum.n2s(int(m)))
# flag{a593591a-3749-cc52-0c27-e897fac2c967}
- 其中:
def gcd(g1, g2):
while g2:
g1, g2 = g2, g1 % g2
return g1.monic() #
return -gcd(g1, g2)[0]
- 使用辗转相除法求多项式的最大公因子
- 在代数中,一个多项式的首项系数通常被称为该多项式的引导系数(leading coefficient),而将多项式变成首项系数为1的形式被称为将多项式化为首一形式(monic form)
- 调用函数g1.monic()将g1转换为首一多项式(monic polynomial),并返回该多项式。
- 使用g.monic()[0],则会返回g(x)除以引导系数后得到的多项式的常数项
比如:g.monic() = x + 32412345
那么:g.monic()[0] = 32412345
题二
题目描述:
from Crypto.Util.number import getPrime,bytes_to_long,long_to_bytes
from functools import reduce
from secret import flag, x, y
m = bytes_to_long(flag)
p = getPrime(1024)
q = getPrime(1024)
n = p*q
print(n)
assert(reduce(lambda x,y:x&y,[(i-5)*i+6==0 for i in x]))
assert(reduce(lambda x,y:x&y,[(j-15)*j+44==0 for j in y]))
print(pow(reduce(lambda x,y:x*m+y,x),17,n))
print(pow(reduce(lambda x,y:x*m+y,y),17,n))
# n = 23772599983135215481563178266884362291876571759991288577057472733374903836591330410574958472090396886895304944176208711481780781286891334062794555288959410390926474473859289842654809538435377431088422352076225067494924657598298955407771484146155998883073439266427190212827600119365643065276814044272790573450938596830336430371987561905132579730619341196199420897034988685012777895002554746080384319298123154671447844799088258541911028041717897434816921424155687677867019535399434825468160227242441375503664915265223696139025407768146464383537556265875013085702422829200814612395116961538432886116917063119749068212699
# c1 = 10900151504654409767059699202929100225155892269473271859207513720755903691031362539478242920144073599515746938827937863835169270383721094542639011665235593065932998091574636525973099426040452626893461449084383663453549354608769727777329036059746386523843912382289597182615339786437186169811342356085836838520978047561127661777189045888648773949147220411427306098338616422692914110656004863767719312410906124366000507952960331116878197129010412361636679449281808407214524741732730279777729251515759320442591663641984363061618865267606007355576230009922421807527598213455112981354590909603317525854070358390622096569841
# c2 = 17298679220717326374674940612143058330715465693318467692839033642321129433471254547497087746971317567301086124779289015934582615377165560688447452762043163082394944604062014490446763247008217251611443338103074143809936437694543761369945095202092750900940979469994907399829695696313513303922266742415376818434932335640062684245008822643258497589196668426788916969378417960200705779461808292296450298558001909603602502604228973101048082095642290047196235959438278631661658312398313171590515776453711432353011579809351076532129444735206408591345372296372378396539831385036814349328459266432393612919118094115543053115450
题目分析:
- 首先来看一下下面这一串
assert(reduce(lambda x,y:x&y,[(i-5)*i+6==0 for i in x]))
1. [(i-5)*i+6==0 for i in x] 使用列表推导式判断等式是否成立,
若成立,返回True,否则False,故列表中最终得到的是[True,True]
2. 为什么是True呢,因为用了assert断言函数,
如果为真则正常执行,如果为假则报错,过程中断
给的题目是会正常运行下去的,故该结果应为True,
3. 由此可以反推出x = [2,3](解方程得到),显然也可以知道下一串中y = [4,11]
4. reduce函数是应用lambda表达式对列表([True,True])中的每一个元素依次进行异或操作
5. PS:“lambda x,y:x&y”中的‘x’
与
“[(i-5)*i+6==0 for i in x]”中的‘x’
并不是同一个!!!(如果这里清楚了,那这句话就是真的弄明白了!)
- 所以推出(解方程相信大家都会)
x = [2,3]
y = [4,11]
- 接下来看最后一串:
reduce(lambda x,y:x*m+y,x)
这里就不过多说理论方面的了,我直接举个例子吧
x = [1,2,3,4]
reduce(lambda x,y:x+y,x),使用reduce对x进行累积
x = 1,y = 2,==>
x+y = 3 ①
x = ①,y = 3,==>
x+y = 6 ②
x = ②,y = 4,==>
x+y = 10 ③
即 1+2+3+4
最终得到的结果为10
再举个更难一点的例子
x = [1,2,3,4]
reduce(lambda x,y:x*m+y,x),使用reduce对x进行累积
x = 1,y = 2,==>
x*m+y = 1*m+2 ①
x = ①,y = 3,==>
x*m+y = (1*m+2)*m+3 ②
x = ②,y = 4,==>
x*m+y = ((1*m+2)*m+3)*m+4 ③
最终得到的即为式③
- 由此可以得知题目中
reduce(lambda x,y:x*m+y,x) = 2*m+3
reduce(lambda x,y:x*m+y,y) = 4*m+11
- 最终得到:
c1 = pow(2*m+3,17,n)
c2 = pow(4*m+11,17,n)
- 又是典型的Franklin-Reiter相关消息攻击,直接上代码解题
import libnum
n = 23772599983135215481563178266884362291876571759991288577057472733374903836591330410574958472090396886895304944176208711481780781286891334062794555288959410390926474473859289842654809538435377431088422352076225067494924657598298955407771484146155998883073439266427190212827600119365643065276814044272790573450938596830336430371987561905132579730619341196199420897034988685012777895002554746080384319298123154671447844799088258541911028041717897434816921424155687677867019535399434825468160227242441375503664915265223696139025407768146464383537556265875013085702422829200814612395116961538432886116917063119749068212699
c1 = 10900151504654409767059699202929100225155892269473271859207513720755903691031362539478242920144073599515746938827937863835169270383721094542639011665235593065932998091574636525973099426040452626893461449084383663453549354608769727777329036059746386523843912382289597182615339786437186169811342356085836838520978047561127661777189045888648773949147220411427306098338616422692914110656004863767719312410906124366000507952960331116878197129010412361636679449281808407214524741732730279777729251515759320442591663641984363061618865267606007355576230009922421807527598213455112981354590909603317525854070358390622096569841
c2 = 17298679220717326374674940612143058330715465693318467692839033642321129433471254547497087746971317567301086124779289015934582615377165560688447452762043163082394944604062014490446763247008217251611443338103074143809936437694543761369945095202092750900940979469994907399829695696313513303922266742415376818434932335640062684245008822643258497589196668426788916969378417960200705779461808292296450298558001909603602502604228973101048082095642290047196235959438278631661658312398313171590515776453711432353011579809351076532129444735206408591345372296372378396539831385036814349328459266432393612919118094115543053115450
e = 17
import binascii
def franklinReiter(n,e,c1,c2):
PR.<x> = PolynomialRing(Zmod(n))
g1 = (2*x+3)^e - c1
g2 = (4*x+11)^e - c2
def gcd(g1, g2):
while g2:
g1, g2 = g2, g1 % g2
return g1.monic()
return -gcd(g1, g2)[0]
m=franklinReiter(n,e,c1,c2)
print(libnum.n2s(int(m)))
# flag{r54__r3l473d_m355463_4774ck_4l50_c4ll3d_fr4nkl1n_r3173r_4774ck~}
题三
(NEEPUSec CTF 2021 RSA)
题目描述:
from Crypto.Util.number import *
from sympy import nextprime
import gmpy2
import random
def encode (p1,p2,e):
not_hint = (p1 + 1) * (p2 + 1)
S = gmpy2.invert(e, not_hint)
not_p = S%(p1+1)
return not_p
flag = b'Neepu{********************}'
flag = bytes_to_long(flag)
p = getPrime(512)
q = getPrime(512)
n = p*q
e = nextprime(random.randint(1,1000))
d = gmpy2.invert(e, (p-1)*(q-1))
c = pow(flag, e, n)
print(c)
print(n)
m = encode(p, q, e)
c1 = pow(m, 7, n)
c2 = pow(m+e, 7, n)
print(c1)
print(c2)
c = 78543767285872349029076059073458316000847341792088805258173041942425687239313215276670106926320359777962661495032475004417723103701253550583245518206305422982968675291500865382213182669036827898932991063338163290845510339896689210314509493839746410486257998875782496654704288722251878269643040214139429715671
n = 91995272927105081122659192011056020468305570748555849650309966887236871318156855318666540461669669247866754568189179687694315627673545298267458869140096224628114424176937828378360997230874932015701507629238213240839370628366083111028544554453150572165461450371411341485911677167168492357154684642531577228543
c1 = 10186066785511829759164194803209819172224966119227668638413350199662683285189286077736537161204019147791799351066849945954518642600518196927152098131117402608793752080104402893792812059620726950782670809837962606250674588612783027976958719051829085903720655233948024280118985875980227528403883475592567727892
c2 = 46182103994299145562022812023438495797686077104477472631494150222038404419414100727667171290098624214113241032861128455086601197239761085752413519627251290509474327611253599768650908336142621210005389246714504358370629231557080301516460985022782887233790302054696967900384601182742759555421864610431428746119
题目分析:
c1 = pow(m, 7, n)
c2 = pow(m+e, 7, n)
很熟悉的两串,但其中有两个未知数,以上两题都只有一个未知数,所以先要把e给求出来,再使用Franklin-Reiter相关消息攻击求出m。如何求e呢,这里便用到了短填充攻击(Coppersmith’s short-pad attack)【目前本人也没看此攻击手法,等推到了原理再说】,不多说,直接上解题代码
def short_pad_attack(c1, c2, e, n):
PRxy.< x, y > = PolynomialRing(Zmod(n))
PRx.< xn > = PolynomialRing(Zmod(n))
PRZZ.< xz, yz > = PolynomialRing(Zmod(n))
g1 = x ^ e - c1
g2 = (x + y) ^ e - c2
q1 = g1.change_ring(PRZZ)
q2 = g2.change_ring(PRZZ)
h = q2.resultant(q1)
h = h.univariate_polynomial()
h = h.change_ring(PRx).subs(y=xn)
h = h.monic()
kbits = n.nbits() // (2 * e * e)
diff = h.small_roots(X=2 ^ kbits, beta=0.4)[0] # find root < 2^kbits with factor >= n^0.4
return diff
def related_message_attack(c1, c2, diff, e, n):
PRx.< x > = PolynomialRing(Zmod(n))
g1 = x ^ e - c1
g2 = (x + diff) ^ e - c2
def gcd(g1, g2):
while g2:
g1, g2 = g2, g1 % g2
return g1.monic()
return -gcd(g1, g2)[0]
if __name__ == '__main__':
c2 = 10186066785511829759164194803209819172224966119227668638413350199662683285189286077736537161204019147791799351066849945954518642600518196927152098131117402608793752080104402893792812059620726950782670809837962606250674588612783027976958719051829085903720655233948024280118985875980227528403883475592567727892
c1 = 46182103994299145562022812023438495797686077104477472631494150222038404419414100727667171290098624214113241032861128455086601197239761085752413519627251290509474327611253599768650908336142621210005389246714504358370629231557080301516460985022782887233790302054696967900384601182742759555421864610431428746119
n = 91995272927105081122659192011056020468305570748555849650309966887236871318156855318666540461669669247866754568189179687694315627673545298267458869140096224628114424176937828378360997230874932015701507629238213240839370628366083111028544554453150572165461450371411341485911677167168492357154684642531577228543
e = 7
diff = short_pad_attack(c1, c2, e, n)
print("difference of two messages is %d" % diff)
m1 = related_message_attack(c1, c2, diff, e, n)
print("m1:", m1)
print("m2:", m1 + diff)
- 另一种方法求m(直接爆破e):
import binascii
def attack(c1, c2, n, e):
PR.<x> = PolynomialRing(Zmod(n))
g1 = (x)^7 - c1
g2 = (x+e)^7 - c2
def gcd(g1, g2):
while g2:
g1, g2 = g2, g1 % g2
return g1.monic()
return -gcd(g1, g2)[0]
c1 = 10186066785511829759164194803209819172224966119227668638413350199662683285189286077736537161204019147791799351066849945954518642600518196927152098131117402608793752080104402893792812059620726950782670809837962606250674588612783027976958719051829085903720655233948024280118985875980227528403883475592567727892
c2 = 46182103994299145562022812023438495797686077104477472631494150222038404419414100727667171290098624214113241032861128455086601197239761085752413519627251290509474327611253599768650908336142621210005389246714504358370629231557080301516460985022782887233790302054696967900384601182742759555421864610431428746119
n = 91995272927105081122659192011056020468305570748555849650309966887236871318156855318666540461669669247866754568189179687694315627673545298267458869140096224628114424176937828378360997230874932015701507629238213240839370628366083111028544554453150572165461450371411341485911677167168492357154684642531577228543
for e in range(1,1000):
m = attack(c1, c2, n, e)
try:
if pow(m,7,n) == c1:
print((e,m))
except:
pass
#结果:(71, 129256555243625096140386916253259867206651269142565502540823654159666398099455456877012993395632742360829588042575108302297567291349420390228163587340859)
#e = 71
#m = 129256555243625096140386916253259867206651269142565502540823654159666398099455456877012993395632742360829588042575108302297567291349420390228163587340859
- 求到m,又m = s % (p+1) = d % (p+1),这不就类似于dp泄露吗,简单推导一下,把加1换成减1即可得到p,q,直接上解题代码了
import gmpy2
from Crypto.Util.number import *
e = 71
# m = 129256555243625096140386916253259867206651269142565502540823654159666398099455456877012993395632742360829588042575108302297567291349420390228163587340859
c = 78543767285872349029076059073458316000847341792088805258173041942425687239313215276670106926320359777962661495032475004417723103701253550583245518206305422982968675291500865382213182669036827898932991063338163290845510339896689210314509493839746410486257998875782496654704288722251878269643040214139429715671
n = 91995272927105081122659192011056020468305570748555849650309966887236871318156855318666540461669669247866754568189179687694315627673545298267458869140096224628114424176937828378360997230874932015701507629238213240839370628366083111028544554453150572165461450371411341485911677167168492357154684642531577228543
# dp = m ,类似的dp
dp = 129256555243625096140386916253259867206651269142565502540823654159666398099455456877012993395632742360829588042575108302297567291349420390228163587340859
for i in range(1,65535):
p = (dp*e-1)//i-1
if n%p == 0:
q = n//p
d = gmpy2.invert(e, (p - 1) * (q - 1))
flag = pow(c,d,n)
print(long_to_bytes(flag))
break
# Neepu{Have-a-g00d-day12138}
收获与体会:
学到挺多,对相关消息攻击掌握了,对reduce(),lambda()函数理解更透彻了,
学到了dp泄露的另一种变形,嗯,不得不说,收获挺大的
浅记一下:
做完NEEPUSec CTF 2023后,感觉这个比赛的题目质量很不错,于是就找了一下它往年的题,然后就做到了NEEPUSec CTF 2021 RSA这题。一开始看它题目描述感觉很简单,但推来推去也只能得到 m * e = 1 % (p+1),m和e还是不知道,结果就是,啥都没求出来。看完wp后知道原来这里对m,e的求解有具体知识点,于是查找了很多资料,最终把这题给弄懂了。
其实一开始是本着直接套脚本的想法,但突然想到了某位前辈说的一句话 “我们是搞网络安全的,不是找flag的ctfer,别把两者搞反了”。
但其实说完全弄懂这题还是有些勉强,里面有一些小点还是不太懂的,比如求公因子后会得到x-M,其中M即为所求的m,不太明白(挠头),比如短填充攻击(还没找资料看),总之大体步骤和含义是清楚了。
2023/06/08 来解疑了:
理解为什么是x - M2了,M2是f(x) - c1 = 0 (mod N)的一个解,把 f(x) - c1 写成下面的形式:f(x) - c1 = (x - M2) * g(x) + r(x),其中,g(x) 是商式,r(x) 是余数多项式,需要证明当 x = M2时,r(x) 的值为 0。如果 r(x) 的值不为 0,那么 f(M2) - c1 的值就不为 0,这与知道事实相矛盾。因此,当 x = M2 时,r(x) 的值必须为 0,所以说,f(x) - c1 能够被 (x - M2) 整除,意味着 x - M2 是 f(x) - c1 的一个因子,同理x - M2 也是x ^ e - c2 = 0 (mod N)的一个因子
题四
(于2023-09-17记录)
题目描述:
from Crypto.Util.number import *
from secret import flag
m = bytes_to_long(flag)
p1, q1 = getPrime(512), getPrime(512)
n1 = p1*q1
e = 65537
p2, q2 = getPrime(512), getPrime(512)
n2 = p2*q2
print(f'n1 = {n1}')
print(f'n2 = {n2}')
print(f'c1 = {pow(m,e,n2)}')
print(f'c2 = {pow(n1-m,e,n2)}')
# n1 = 52579135273678950581073020233998071974221658902576724000130040488018033110534210901239397446395736563148970863970460542205225993317478251099451639165369081820130823165642873594136020122857712288395352930384057524510346112486008850200845915783772351449146183974239444691330777565342525218070680067550270554767
# n2 = 68210568831848267339414957973218186686176324296418282565773310695862151827108036984694027795077376921170907068110296451176263520249799154781062517066423984526868547296781709439425857993705489037768605485740968600877866332458671029054092942851472208033494968784822459369206497698469167909174346042658361616469
# c1 = 42941712708129054668823891960764339394032538100909746015733801598044118605733969558717842106784388091495719003761324737091667431446354282990525549196642753967283958283202592037329821712755519455155110675327321252333824912095517427885925854391047828862338332559137577789387455868761466777370476884779752953853
# c2 = 62704043252861638895370674827559804184650708692227789532879941590038911799857232898692335429773480889624046167792573885125945511356456073688435911975161053231589019934427151230924004944847291434167067905803180207183209888082275583120633408232749119300200555327883719466349164062163459300518993952046873724005
题目分析:
线性相关,想到相关消息攻击
不过此题比较特殊,e很大,用上面的脚本跑大概要1个小时,这里引入另一种解法,half gcd
算法
参考:
https://www.cnblogs.com/whx1003/p/16217087.html
代码参考:
https://github.com/rkm0959/rkm0959_implements/blob/main/Half_GCD/code.sage
常规:
from Crypto.Util.number import *
e = 65537
n1 = 52579135273678950581073020233998071974221658902576724000130040488018033110534210901239397446395736563148970863970460542205225993317478251099451639165369081820130823165642873594136020122857712288395352930384057524510346112486008850200845915783772351449146183974239444691330777565342525218070680067550270554767
n2 = 68210568831848267339414957973218186686176324296418282565773310695862151827108036984694027795077376921170907068110296451176263520249799154781062517066423984526868547296781709439425857993705489037768605485740968600877866332458671029054092942851472208033494968784822459369206497698469167909174346042658361616469
c1 = 42941712708129054668823891960764339394032538100909746015733801598044118605733969558717842106784388091495719003761324737091667431446354282990525549196642753967283958283202592037329821712755519455155110675327321252333824912095517427885925854391047828862338332559137577789387455868761466777370476884779752953853
c2 = 62704043252861638895370674827559804184650708692227789532879941590038911799857232898692335429773480889624046167792573885125945511356456073688435911975161053231589019934427151230924004944847291434167067905803180207183209888082275583120633408232749119300200555327883719466349164062163459300518993952046873724005
def attack(c1, c2):
PR.<x>=PolynomialRing(Zmod(n2))
g1 = x^e - c1
g2 = (n1-x)^e - c2
def gcd(g1, g2):
while g2:
g1, g2 = g2, g1 % g2
if(g2.degree() % 100 == 0):
print(g2.degree())
return g1.monic()
return -gcd(g1, g2)[0]
m1 = attack(c1, c2)
flag = long_to_bytes(int(m1))
print(flag)
half gcd:
from Crypto.Util.number import *
import sys
def HGCD(a, b):
if 2 * b.degree() <= a.degree() or a.degree() == 1:
return 1, 0, 0, 1
m = a.degree() // 2
a_top, a_bot = a.quo_rem(x^m)
b_top, b_bot = b.quo_rem(x^m)
R00, R01, R10, R11 = HGCD(a_top, b_top)
c = R00 * a + R01 * b
d = R10 * a + R11 * b
q, e = c.quo_rem(d)
d_top, d_bot = d.quo_rem(x^(m // 2))
e_top, e_bot = e.quo_rem(x^(m // 2))
S00, S01, S10, S11 = HGCD(d_top, e_top)
RET00 = S01 * R00 + (S00 - q * S01) * R10
RET01 = S01 * R01 + (S00 - q * S01) * R11
RET10 = S11 * R00 + (S10 - q * S11) * R10
RET11 = S11 * R01 + (S10 - q * S11) * R11
return RET00, RET01, RET10, RET11
def GCD(a, b):
print(a.degree(), b.degree())
q, r = a.quo_rem(b)
if r == 0:
return b
R00, R01, R10, R11 = HGCD(a, b)
c = R00 * a + R01 * b
d = R10 * a + R11 * b
if d == 0:
return c.monic()
q, r = c.quo_rem(d)
if r == 0:
return d
return GCD(d, r)
sys.setrecursionlimit(500000)
e = 65537
n1 = 52579135273678950581073020233998071974221658902576724000130040488018033110534210901239397446395736563148970863970460542205225993317478251099451639165369081820130823165642873594136020122857712288395352930384057524510346112486008850200845915783772351449146183974239444691330777565342525218070680067550270554767
n2 = 68210568831848267339414957973218186686176324296418282565773310695862151827108036984694027795077376921170907068110296451176263520249799154781062517066423984526868547296781709439425857993705489037768605485740968600877866332458671029054092942851472208033494968784822459369206497698469167909174346042658361616469
c1 = 42941712708129054668823891960764339394032538100909746015733801598044118605733969558717842106784388091495719003761324737091667431446354282990525549196642753967283958283202592037329821712755519455155110675327321252333824912095517427885925854391047828862338332559137577789387455868761466777370476884779752953853
c2 = 62704043252861638895370674827559804184650708692227789532879941590038911799857232898692335429773480889624046167792573885125945511356456073688435911975161053231589019934427151230924004944847291434167067905803180207183209888082275583120633408232749119300200555327883719466349164062163459300518993952046873724005
R.<x> = PolynomialRing(Zmod(n2))
f = x^e - c1
g = (n1 - x)^e - c2
res = GCD(f,g)
print(long_to_bytes(int(-res.monic().coefficients()[0])))
gcd的结果是 ax - b,我们要得到的是x - m,用monic()将ax - b化为首一多项式即x系数位1,如此得到x - m,然后用coefficients()[0]提取到-m,最后再添个符号得到flag。漂亮!