coppersmith铜匠入门

芝士就是力量

    • 芝士

      SageMath简明教程 | tl2cents blog (tanglee.top)

      PR.<x> = PolynomialRing(Zmod(n))   # x是规定下面方程的自变量, PolynomialRing()是与环有关,Zmod规定了环的模数
      
      f = (x + 1) ^ 2   	# 定义了一个式子
      
      f = f.monic()    	# 将多项式首项的系数化为一
      
      res = f.roots()   	# 或者small_roots()  # res现在是列表
      
      res = int(res[0]) 	# 把res的sage.rings.integer.Integer环域改成int,或者用ZZ(res[0])也行
      ...
      

      步骤

      1. 先把最少能small_roots()的未知数界限推出来,用这个:coppersmith small_roots未知位数检测.ipynb
        # sagemath 9.3 from Crypto.Util.number import getPrime p = getPrime(int(1024)) q = getPrime(int(1024)) n = p * q test_bits = 455 p_h = p >> test_bits R.<x> = PolynomialRing(Zmod(n)) f = (p_h << test_bits) + x f.small_roots(2**test_bits,0.4)
        保险起见,算出来的位数实际用减一,例如在1024位pq下算出455,用454;在512位pq下算出227,用226
      2. 查看coppersmith small_roots()所需要的位数是否满足,有时候需要爆破几位
      3. 编写脚本,确定f 方程(本人目前不会,解多项式原理不懂,一开始以为是把类似x**2 + 2*x + 1 = 0 左边当成f方程来解方程,但是在下面遇到了右边单独放了p并不是0)
      4. 得到缺陷q本身,解rsa

      例题

      1. NSSCTF工坊[RSA4]P8

        • 题目

          from Crypto.Util.number import *
          
          p = getPrime(512)
          q = getPrime(512)
          
          flag = b'NSSCTF{******}'
          
          n = p*q
          m = bytes_to_long(flag)
          
          e = 3
          c = pow(m, e, n)
          
          print(f'n = {n}')
          print(f'm = {m>>100}')
          print(f'c = {c}')
          
          '''
          n = 1527542955109141740955682973826193262775892499957309448026045241470857728195657663426381459817190647872750820593934305392986732687654051540838628636529717414135863605586498459487983117670942529496973140251670874510207985224170313618738268651184582186637089407746738836054395760157095709388670653150429457223183161697730087281761369404956762102465246289770300941300936135728738323821631682286737786472020790680432476428922187234364341215016265407571963282147129157
          m = 2214226572250613833249705195927505959981823363137633354626532745196588970707
          c = 22113876206623661468496987580282614626160320529328454393375952035910523390370709980915981609422504775420007441257006956611997263223244837790238493516238723139514158563675396731542096229586616735753203254810465452822757959264870210654015436735165961713016222816604825816304606749448517022584926571828009062411578367333
          '''
          
        • 解析

          m缺少了低位100位,也就是高位泄露了,那么原本完整的m可以构成这个式子
          $$
          m = m_high + x
          $$
          x为m的低位,而m_high用上面的m乘上2**100提高到原本的高位(演示如下)

          	 m = 10101010111010100010101  	# 原本的m	
          	 m = 10101010111  				# m右移一定位数后
          m_high = 10101010111000000000000    # 乘上对应的数,让对应的10到达原本的未知,剩下后面我们补上的0就由x来补上 
          

          综上,问题就转移到求x身上,我们来用已知条件和式子来构造一个方程式

          已知 m, c,n,e
          $$
          c = m^e \pmod n
          $$
          那么有
          $$
          m^e - c = 0 \pmod n
          $$
          m展开得到
          $$
          (m_high + x)^e - c = 0 \pmod n
          $$
          这下我们获得了所有解题思路,接下来写代码

        • exp

          # sagemath 9.3
          from Crypto.Util.number import *
          
          n = 1527542955109141740955682973826193262775892499957309448026045241470857728195657663426381459817190647872750820593934305392986732687654051540838628636529717414135863605586498459487983117670942529496973140251670874510207985224170313618738268651184582186637089407746738836054395760157095709388670653150429457223183161697730087281761369404956762102465246289770300941300936135728738323821631682286737786472020790680432476428922187234364341215016265407571963282147129157
          m = 2214226572250613833249705195927505959981823363137633354626532745196588970707
          c = 22113876206623661468496987580282614626160320529328454393375952035910523390370709980915981609422504775420007441257006956611997263223244837790238493516238723139514158563675396731542096229586616735753203254810465452822757959264870210654015436735165961713016222816604825816304606749448517022584926571828009062411578367333
          
          m_high = m<<100
          
          PR.<x> = PolynomialRing(Zmod(n))
          f = (m_high + x)**3 - c
          f = f.monic()
          m0 = f.small_roots()
          print(m0)
          m = m_high + m0[0]
          flag = long_to_bytes(int(m)).decode()
          print(flag) # NSSCTF{688404a6-c408-4196-bc43-7f18317a9170}
          
      2. NSSCTF工坊[RSA4]P9(构造多项式不懂,为什么右边不是0,而是p)

        • 题目

          from Crypto.Util.number import *
          
          p = getPrime(512)
          q = getPrime(512)
          
          flag = b'NSSCTF{******}'
          
          n = p*q
          m = bytes_to_long(flag)
          
          e = 65537
          c = pow(m, e, n)
          
          print(f'n = {n}')
          print(f'p = {p>>100}')
          print(f'c = {c}')
          
          '''
          n = 64335017257291288694879798080666629573501118113377179370850991421806469826103134483305987256497147128148330360834028920504233940886960965527818740354522230977284177508093687651712761343376265176857120577153061490788347779327206437787594150381508592990273475278503352979893670354730287704989079247190299342871
          p = 7550547038897825994210519739007596111285476244196123253081036462313916767780871742001683690783926938603422562506786339392389
          c = 63156227746402147833665215816432368072100003179308515827461336094419526246728847463629131014545663919689064970828884371592840335299717484415279040662500514230579275586231051576688620810169339105201465431624989678170362157914366609856305650090630980489686792938272599406165204410721499875713189193728688835223
          '''
          
        • 解析

          p高位泄露

          Crypto系列——RSA(四) | NSSCTF

        • exp

          # sagemath 9.3
          from Crypto.Util.number import *
          
          n = 64335017257291288694879798080666629573501118113377179370850991421806469826103134483305987256497147128148330360834028920504233940886960965527818740354522230977284177508093687651712761343376265176857120577153061490788347779327206437787594150381508592990273475278503352979893670354730287704989079247190299342871
          p = 7550547038897825994210519739007596111285476244196123253081036462313916767780871742001683690783926938603422562506786339392389
          c = 63156227746402147833665215816432368072100003179308515827461336094419526246728847463629131014545663919689064970828884371592840335299717484415279040662500514230579275586231051576688620810169339105201465431624989678170362157914366609856305650090630980489686792938272599406165204410721499875713189193728688835223
          e = 65537
          
          p_high = p<<100  # 乘上2**100一样作用
          
          PR.<x> = PolynomialRing(Zmod(n))
          
          f = p_high + x
          f = f.monic()
          out_p = f.small_roots(2^100,0.4)
          print(out_p)
          p = int(p_high + out_p[0])
          assert n % p == 0
          q = n // p
          phi = (p-1)*(q-1)
          d = inverse(e, phi)
          m = pow(c, d, n)
          flag = long_to_bytes(int(m)).decode()
          print(flag) # NSSCTF{36a5ae48-f281-4576-8d1f-acab0666bff2}
          
      3. BaseCTF2024 [Week2]铜匠

        • 题目

          from Crypto.Util.number import getPrime, bytes_to_long
          #from secret import flag
          flag=b'XXXX'
          
          p = getPrime(1024)
          q = getPrime(1024)
          n = p * q
          e = 65537
          hint1 = p >> 721
          hint2 = q % (2 ** 266)
          ct = pow(bytes_to_long(flag), e, n)
          print(hint1)
          print(hint2)
          print(n)
          print(ct)
          '''
          hint1 = 14439249591349619691972392177790365247490839237199085979433418493254022567815148979672690178
          hint2 = 90063199151369157959005663017593053931871580139169245885113098598755909124764417
          n = 18347545778876678838092757800261556931131930866012101566000425608407193858675622059415995283684230959320874387944052648148677918542763633503231962873204645415818139345588988936580526094727943067102768943117592654029397879665312089518191052154267343886226820785206334238961064175118262578895847281575656290248049404047727756356910896332939145136942219317065063060070725033146788186604738271846183709127655298440696824683099637827282095133642324657860714680107691622056420045091586609974536644773286992447027164350612852922016376888380895187804771279035652496676089183636450028327097084911908336202253562671798012457461
          ct = 15659576879410368237140555530527974801613150473447768911067611094143466009251385693099110691602954207905029692682380253595062935017486879899242785756448973466690818942065250284891341066578689696180061755610538867770441139827574063212967027249650509215685566103350688284041405586915563454117672061141919712416360596137520514412607512596079964611672166435592936417138352662031529414118312166411150736015788925026636845744110093161894267707446937939130745326244186579516665160036229715964182962542836836457885170975474737620430886449029488829662146456489724775166105816909257516908496172172266375617868819982791477888289
          '''
          
        • 解析

          下面鹤城杯的简易版,把p的未知位数改小了,刚好可以不用爆破得到p

          在查small_root()参数要求时,找到了原题鹤城杯2021,babyrsa

          文章RSA中coppersmith定理的应用条件_sagemath coppersmith-CSDN博客

          测试一下在pq均为1024位下,未知量需要控制在多少一下才能使得small_root()有解

          # sagemath 9.3
          from Crypto.Util.number import getPrime
          p = getPrime(int(1024)) # 1024可根据题意修改,若p,q不同位,请访问https://blog.csdn.net/qq_51999772/article/details/123620932
          q = getPrime(int(1024))
          n = p * q
          test_bits = 455 # 调节未知数大小
          p_h = p >> test_bits
          R.<x> = PolynomialRing(Zmod(n))
          f = (p_h << test_bits) + x
          f.small_roots(2**test_bits,0.4)
          

        ​ 这里关于f 方程 等号右边为什么不是0还是存有疑惑

        • exp

          # sagemath 9.3
          from Crypto.Util.number import *
          hint1 = 14439249591349619691972392177790365247490839237199085979433418493254022567815148979672690178
          hint2 = 90063199151369157959005663017593053931871580139169245885113098598755909124764417
          n = 18347545778876678838092757800261556931131930866012101566000425608407193858675622059415995283684230959320874387944052648148677918542763633503231962873204645415818139345588988936580526094727943067102768943117592654029397879665312089518191052154267343886226820785206334238961064175118262578895847281575656290248049404047727756356910896332939145136942219317065063060070725033146788186604738271846183709127655298440696824683099637827282095133642324657860714680107691622056420045091586609974536644773286992447027164350612852922016376888380895187804771279035652496676089183636450028327097084911908336202253562671798012457461
          ct = 15659576879410368237140555530527974801613150473447768911067611094143466009251385693099110691602954207905029692682380253595062935017486879899242785756448973466690818942065250284891341066578689696180061755610538867770441139827574063212967027249650509215685566103350688284041405586915563454117672061141919712416360596137520514412607512596079964611672166435592936417138352662031529414118312166411150736015788925026636845744110093161894267707446937939130745326244186579516665160036229715964182962542836836457885170975474737620430886449029488829662146456489724775166105816909257516908496172172266375617868819982791477888289
          e = 65537
          
          p_high = hint1
          q_low = hint2
          mod = 2 ** 266
          q_low_lnv = inverse(q_low, mod)
          p_low = n*q_low_lnv % mod
          
          i = 721 - 266 - 455 # i是p距离small_root成功所需要的位数还缺的位数(用来爆破),455是用另一个py文件推出来的
          print(i)
          PR.<x> = PolynomialRing(Zmod(n))
          if i != 0:
              for j in range(2**i):
                  f = p_high * (2**721) + p_low + (x*32  + j) * mod # 这里的32是步长
                  f = f.monic()
                  out_p = f.small_root(2**455,0.4)
                  if(len(out_p) != 0): 
                      print(out_p)
                      break
              p = (out_p[0]*32 + j) * mod + p_high * (2**721) + p_low
          
          else:
              f = p_high * (2**721) + p_low + (x*32) * 2**266
              f = f.monic()
              out_p = f.small_roots(2**455,0.4)
              p = p_high * (2**721) + p_low + (out_p[0]*32) * 2**266
              
          
          
          p = int(p)
          assert n%p == 0
          q = n//p
          phi = (p-1)*(q-1)
          d = inverse(e, phi)
          m = pow(ct, d, n)
          flag = long_to_bytes(int(m))
          print(flag.decode())
          
      4. 鹤城杯2021 babyrsa

        • 题目

          from Crypto.Util.number import getPrime, bytes_to_long
          from secret import flag
          
          p = getPrime(1024)
          q = getPrime(1024)
          n = p * q
          e = 65537
          hint1 = p >> 724
          hint2 = q % (2 ** 265)
          ct = pow(bytes_to_long(flag), e, n)
          print(hint1)
          print(hint2)
          print(n)
          print(ct)
          """
          hint1 = 1514296530850131082973956029074258536069144071110652176122006763622293335057110441067910479
          hint2 = 40812438243894343296354573724131194431453023461572200856406939246297219541329623
          n = 21815431662065695412834116602474344081782093119269423403335882867255834302242945742413692949886248581138784199165404321893594820375775454774521554409598568793217997859258282700084148322905405227238617443766062207618899209593375881728671746850745598576485323702483634599597393910908142659231071532803602701147251570567032402848145462183405098097523810358199597631612616833723150146418889589492395974359466777040500971885443881359700735149623177757865032984744576285054725506299888069904106805731600019058631951255795316571242969336763938805465676269140733371287244624066632153110685509892188900004952700111937292221969
          ct = 19073695285772829730103928222962723784199491145730661021332365516942301513989932980896145664842527253998170902799883262567366661277268801440634319694884564820420852947935710798269700777126717746701065483129644585829522353341718916661536894041337878440111845645200627940640539279744348235772441988748977191513786620459922039153862250137904894008551515928486867493608757307981955335488977402307933930592035163126858060189156114410872337004784951228340994743202032248681976932591575016798640429231399974090325134545852080425047146251781339862753527319093938929691759486362536986249207187765947926921267520150073408188188
          """
          
        • 解析

          有5位需要爆破,如果你用上面的脚本,会发现test_bits=455也是可以出结果的,但是我在实际应用中发现455并不能出结果,所以要减一

        • exp

          # sagemath 9.3
          from Crypto.Util.number import *
          
          hint1 = 1514296530850131082973956029074258536069144071110652176122006763622293335057110441067910479
          hint2 = 40812438243894343296354573724131194431453023461572200856406939246297219541329623
          n = 21815431662065695412834116602474344081782093119269423403335882867255834302242945742413692949886248581138784199165404321893594820375775454774521554409598568793217997859258282700084148322905405227238617443766062207618899209593375881728671746850745598576485323702483634599597393910908142659231071532803602701147251570567032402848145462183405098097523810358199597631612616833723150146418889589492395974359466777040500971885443881359700735149623177757865032984744576285054725506299888069904106805731600019058631951255795316571242969336763938805465676269140733371287244624066632153110685509892188900004952700111937292221969
          ct = 19073695285772829730103928222962723784199491145730661021332365516942301513989932980896145664842527253998170902799883262567366661277268801440634319694884564820420852947935710798269700777126717746701065483129644585829522353341718916661536894041337878440111845645200627940640539279744348235772441988748977191513786620459922039153862250137904894008551515928486867493608757307981955335488977402307933930592035163126858060189156114410872337004784951228340994743202032248681976932591575016798640429231399974090325134545852080425047146251781339862753527319093938929691759486362536986249207187765947926921267520150073408188188
          e = 65537
          
          p_high = hint1
          q_low = hint2
          mod = 2 ** 265
          
          q_low_lnv = inverse(q_low, mod)
          p_low = n*q_low_lnv % mod
          
          k = 724 - 265 - 455 + 1  # 要加一
          print(k)
          PR.<x> = PolynomialRing(Zmod(n))
          
          for i in range(2**k):
              f = p_high*(2**724) + p_low + (x*32 + i)*mod
              f = f.monic()
              out_p = f.small_roots(2**454, 0.4)  # small_roots别写错成small_root啦
              if len(out_p) != 0:
                  print(out_p[0])
                  break
          
          p = p_high*(2**724) + p_low + (out_p[0]*32 + i)*mod
          p = int(p)
          assert n%p==0
          q = n//p
          phi = (p-1)*(q-1)
          d = inverse(e, phi)
          m = pow(ct, d, n)
          flag = long_to_bytes(int(m)).decode()  # 记得把m 给int()
          print(flag) # flag{ef5e1582-8116-4f61-b458-f793dc03f2ff}
          
      5. NSSCTF工坊[RSA4]P10(原理未解)

        • 题目
        • 解析
        • exp
posted @ 2024-09-01 21:53  saga131  阅读(99)  评论(0编辑  收藏  举报