Coppersmith算法学习记录

前言:

特别鸣谢两位师傅的博客,瑞思拜!这篇博客可以配套进行理解,不要急,顺着类型敲一敲代码,由浅入深,慢慢地就想通了

Coppersmith 攻击

https://xz.aliyun.com/t/13769?u_atoken=29e228a52f25d23a72b3ed98caa40f94&u_asig=1a0c399f17325926396723894e00f7

1:实现了从table列表里随机拿出四个字符,并且把它合起来,可以遍历到所有的情况

for i in product(table, repeat=4):
    head = ''.join(i)

2:已知明文高位求低位

 在这里试一下,发现n是2047位,也是说m**3还是比n小,所以求出的(m**3-c)就是它的原始值

解密脚本如下:

n=13112061820685643239663831166928327119579425830632458568801544406506769461279590962772340249183569437559394200635526183698604582385769381159563710823689417274479549627596095398621182995891454516953722025068926293512505383125227579169778946631369961753587856344582257683672313230378603324005337788913902434023431887061454368566100747618582590270385918204656156089053519709536001906964008635708510672550219546894006091483520355436091053866312718431318498783637712773878423777467316605865516248176248780637132615807886272029843770186833425792049108187487338237850806203728217374848799250419859646871057096297020670904211
e=3
c=15987554724003100295326076036413163634398600947695096857803937998969441763014731720375196104010794555868069024393647966040593258267888463732184495020709457560043050577198988363754703741636088089472488971050324654162166657678376557110492703712286306868843728466224887550827162442026262163340935333721705267432790268517
m_high=2519188594271759205757864486097605540135407501571078627238849443561219057751843170540261842677239681908736
#生成多项式环
R.<x>=PolynomialRing(Zmod(n),implementation='NTL')
m=m_high+x
M=m((m**3-c).small_roots()[0])
print(M)

R.<x>=PolynomialRing(Zmod(n),implementation='NTL')是生成一个多项式环,NTL库sagemath自带,无需下载

M=(m**3-c).small_roots()[0]是算法的核心,用于求解多项式的解

总结一下,这段代码的作用是:

  • 定义一个三次多项式 m3−cm3−c。
  • 找到这个多项式的所有小根。
  • 选择最小的那个根。
  • 将这个最小的根赋值给变量 M

例如,如果 c = 8,那么多项式就是 m3−8。假设我们找到了这个多项式的三个根分别是 -2, 和 2,那么 small_roots()[0] 就会选择 -2,并将其赋值给 M

注意求出的解是低位,需要加上高位,才能得出正确解

sage文档链接:Dense univariate polynomials over \(\ZZ/n\ZZ\), implemented using NTL - Polynomials

关于 sage.rings.polynomial.polynomial_modn_dense_ntl.small_roots(self , X=None , beta=1.0 , epsilon=None) 函数中参数更详细的介绍:

该函数是一个用于在整数模下搜索多项式小根的函数。该函数使用NTL库中的算法进行实现,并提供了一些参数来控制搜索的精度和效率。其中,

1、参数epsilon是一个可选参数,用于控制搜索多项式小根的精度。具体来说,epsilon用于控制NTL算法中使用的插值多项式的次数。插值多项式是一种多项式函数,可以通过一些已知的点来近似地计算一个函数在其他点上的值。在搜索多项式小根时,插值多项式用于确定多项式的根的近似位置。

epsilon的值较小时,NTL算法使用的插值多项式次数也会比较小,这可以降低计算量,但可能会导致算法无法找到所有小根。相反,当epsilon的值较大时,NTL算法使用的插值多项式次数也会比较大,这可以增加算法找到所有小根的可能性,但计算量也会相应地增加。

需要注意的是,如果不指定epsilon参数,则NTL算法将使用默认值。默认情况下,epsilon的值为$\beta/8$。在实践中,这个值通常是比较合适的,但也可能需要根据具体情况进行调整。因此,在使用small_roots函数时,我们需要根据具体情况选择合适的epsilon值,以获得更准确的结果。

2、X:用于指定搜索多项式小根的范围。默认情况下,X的值为None,表示搜索整个整数域。如果需要限制搜索的范围,可以将X设置为一个正整数,表示搜索区间为$[-X, X]$。对于非常大的搜索范围,可以将X设置为一个RR对象,表示使用实数范围进行搜索。

3、beta:用于控制NTL算法中的松弛因子。松弛因子是一种通过调整插值多项式的精度来控制搜索速度和精度的方法。beta的默认值为1.0,表示使用默认的松弛因子。可以通过调整beta的值来改变算法的搜索速度和精度。较小的beta值会加快搜索速度,但可能会降低搜索精度,而较大的beta值则会增加搜索精度,但可能会降低搜索速度。

3:已知p的高位攻击

3.1:已知p的高位足够

也是在这里突然想通了coppersmith到底干了一个什么事,n有两个大的素因子,p和q, coppersmith其实去找满足n的因子的多项式,显然只有p和q是因子,而p中最大的那部分数是已知的,所以算法在执行过程中先碰到的最小解一定是符合p的(在这个例子里),因此我们用coppersmith遍历能解出p。

代码上其实没有什么差异,将之前解明文的代码换换变量就可以了

3.2:已知p的高位不够,需要爆破去增加一些位数

from Crypto.Util.number import *
from gmpy2 import *
from secret import flag

m = bytes_to_long(flag)
e = 65537
p= getPrime(256)
leak_p = p >> 120
print("leak_p =",leak_p)
q = getPrime(256)
n = p*q
c= pow(m,e,n)
print("n =",n)
print("c =",c)
# leak_p = 57303545022436031674172379509633863887077
# n = 6290400850108673527783456723558868077251853788073859360516042680251422818079380463161520548743184302018140978345372703177688378631564416901363981788817257
# c = 3018879496435827891565409624549580574355607699876796814908055868300197064252462047054251836059387617618529706009316747223510404878163964048672091931778452

已知的高位需要多少,才能使用这种攻击,答案是high/total<0.44

(256 - 144) / 256 = 0.4375

所以已知的明文需要增加八位,八位二进制数范围是(0.256),所以可以采取爆破

from Crypto.Util.number import *
from libnum import *
n = 6290400850108673527783456723558868077251853788073859360516042680251422818079380463161520548743184302018140978345372703177688378631564416901363981788817257
c = 3018879496435827891565409624549580574355607699876796814908055868300197064252462047054251836059387617618529706009316747223510404878163964048672091931778452
e = 65537
leak_p = 57303545022436031674172379509633863887077
for i in range(1,256):
    p=i+(leak_p<<8)#为爆破留出空间
    ubit=113
    p=p<<112#注意这里需要将leak_p进行移位操作,将它放到high_P正确的位置上
    R.<x>=PolynomialRing(Zmod(n),implementation='NTL')
    f=x+p
    s=f.small_roots(2**ubit,beta=0.4)
    if s:
        print(f's=',s)
        p=int(s[0])+p
        q=n//p
        d=invmod(e,(p-1)*(q-1))
        flag=long_to_bytes(pow(c,d,n))
        if b'flag' in flag:
            print(flag)

 尽管在爆破时函数报错,但是在这之前flag已经出来了

3.3已知p的高位不够,但爆破量太大

这里就没有作过测试了,题主对思路出现了一些想不通的地方,思路是爆破2**10,相当于添加十位,然后再调整系数epsilon

4:已知p的低位攻击 

from Crypto.Util.number import *
from secret import flag
p = getPrime(1024)
q = getPrime(1024)
n = p*q
m = bytes_to_long(flag)
e = 65537
c = pow(m, e, n)

print("n =", n)
print("c =", c)
print("p =", p&((1<<560) - 1))

'''
n = 21595945409392994055049935446570173194131443801801845658035469673666023560594683551197545038999238700810747167248724184844583697034436158042499504967916978621608536213230969406811902366916932032050583747070735750876593573387957847683066895725722366706359818941065483471589153682177234707645138490589285500875222568286916243861325846262164331536570517513524474322519145470883352586121892275861245291051589531534179640139953079522307426687782419075644619898733819937782418589025945603603989100805716550707637938272890461563518245458692411433603442554397633470070254229240718705126327921819662662201896576503865953330533
c = 1500765718465847687738186396037558689777598727005427859690647229619648539776087318379834790898189767401195002186003548094137654979353798325221367220839665289140547664641612525534203652911807047718681392766077895625388064095459224402032253429115181543725938853591119977152518616563668740574496233135226296439754690903570240135657268737729815911404733486976376064060345507410815912670147466261149162470191619474107592103882894806322239740349433710606063058160148571050855845964674224651003832579701204330216602742005466066589981707592861990283864753628591214636813639371477417319679603330973431803849304579330791040664
p = 1426723861968216959675536598409491243380171101180592446441649834738166786277745723654950385796320682900434611832789544257790278878742420696344225394624591657752431494779
'''

已知p的低560位,计算464/1024=0.4531,但是p的位数过大,爆破去降指数显然不现实,所以只能直接试一试,调一调参数

from Crypto.Util.number import *
from libnum import *
n = 21595945409392994055049935446570173194131443801801845658035469673666023560594683551197545038999238700810747167248724184844583697034436158042499504967916978621608536213230969406811902366916932032050583747070735750876593573387957847683066895725722366706359818941065483471589153682177234707645138490589285500875222568286916243861325846262164331536570517513524474322519145470883352586121892275861245291051589531534179640139953079522307426687782419075644619898733819937782418589025945603603989100805716550707637938272890461563518245458692411433603442554397633470070254229240718705126327921819662662201896576503865953330533
c = 1500765718465847687738186396037558689777598727005427859690647229619648539776087318379834790898189767401195002186003548094137654979353798325221367220839665289140547664641612525534203652911807047718681392766077895625388064095459224402032253429115181543725938853591119977152518616563668740574496233135226296439754690903570240135657268737729815911404733486976376064060345507410815912670147466261149162470191619474107592103882894806322239740349433710606063058160148571050855845964674224651003832579701204330216602742005466066589981707592861990283864753628591214636813639371477417319679603330973431803849304579330791040664
pbar = 1426723861968216959675536598409491243380171101180592446441649834738166786277745723654950385796320682900434611832789544257790278878742420696344225394624591657752431494779
bit=1024-560
PR.<x> = PolynomialRing(Zmod(n))
f=pbar+x*2^560
f=f.monic()
root=f.small_roots(2**bit,beta=0.4,epsilon=0.015)
if root:
    p=int(root[0])*2^560+pbar
    q=n//p
    d=invmod(65537,(p-1)*(q-1))
    print(long_to_bytes(pow(c,d,n)))

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值