Franklin-Reiter相关消息攻击

知识导入:

在这里插入图片描述

  • 总结:
    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]
  1. 使用辗转相除法求多项式的最大公因子
  2. 在代数中,一个多项式的首项系数通常被称为该多项式的引导系数(leading coefficient),而将多项式变成首项系数为1的形式被称为将多项式化为首一形式(monic form)
  3. 调用函数g1.monic()将g1转换为首一多项式(monic polynomial),并返回该多项式。
  4. 使用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。漂亮!

  • 7
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值