Crypto學習筆記

山西小嫦娥發表於2024-04-30

Crypto學習筆記(持續更新)

數學是個看天賦的學科,而我恰好沒有這個天賦,別人很容易理解的內容,我需要學習很久。

本篇部落格將記錄我探索Crypto世界的點滴旅程,初衷是為了方便自己查閱,也便於自我成長與回顧,倘若筆者淺薄之見,能有幸為諸位師傅學問之海添一滴水,實乃蓬蓽生輝,甚為喜悅。在此過程中,各位師傅如有任何觀察到的疏漏或偏差,歡迎隨時指正,先謝過各位師傅了。

二零二四年四月三十日記

2024第九屆中國海洋大學資訊保安競賽-NeXT RSA(費馬分解法,p、q相近)

題目描述:聰明的小軍覺得既然都選擇了隨機的 p,那根據 p 選擇 q,q 也是隨機的辣!

import sympy
import libnum

flag="flag{" + "???" + "}"
m = libnum.s2n(flag)

p = sympy.randprime(1<<1024, 1<<1025)# 生成1024位到1025位之間的隨機素數p
q = sympy.nextprime(p)# 找到大於p的下一個素數q

n = p*q
r = (p-1)*(q-1)
e = 65537

c = pow(m, e, n)

print(n, e, c)
# output:
#80044118049755180996754407858488943779355738585718372337839486032339412481191013051614126608584578841408197524632831442032118319629160505851518198448787590483634506563248531254421862061651099856312546562506221294620627871718678484548245902274972044599314097339549053518589561289734819710218838311181044519738709148493164321955860982700783886286661558574861608455547990794798848491695189544811325833194530596317989718866319530140199263278168146224240677087191093183415595617994125075880280632369616506148501757653260154487000183157405531772172082897743929126980157956142627803176227942226654177011633301413616266656761
#65537
#23280133104463252598665779150831148192014617461904564929071121215373331248942762386170411274023248423328388793808975632652896384007449549469345318875514363621903138122407682293848670093433946555776164835208375667498606187869211466397624286383057425296636315379314349307816391315242971306898487494604324473266965665471735612154916305882443496151118031672777088597821127499085632141307413890900246444539517971766135909771880642211582699957211983212981047822362311969553832913399476190919026666192056319334425636757404603336130688707109219644178606626422717046059209499394056295682594928581470210114322505904198054215544

其中 q 是 p 的下一個素數,這題可以使用費馬分解法。

由於p,q直接相鄰,則必有p < sqrt(n) < q 且p,q都是緊挨著sqrt(n) 的素數,用題目裡的nextprime(sqrt(n)) 即可得q,進而解出密文。

解題指令碼:

import gmpy2
import sympy
from Crypto.Util.number import *
 
n = 80044118049755180996754407858488943779355738585718372337839486032339412481191013051614126608584578841408197524632831442032118319629160505851518198448787590483634506563248531254421862061651099856312546562506221294620627871718678484548245902274972044599314097339549053518589561289734819710218838311181044519738709148493164321955860982700783886286661558574861608455547990794798848491695189544811325833194530596317989718866319530140199263278168146224240677087191093183415595617994125075880280632369616506148501757653260154487000183157405531772172082897743929126980157956142627803176227942226654177011633301413616266656761
c = 23280133104463252598665779150831148192014617461904564929071121215373331248942762386170411274023248423328388793808975632652896384007449549469345318875514363621903138122407682293848670093433946555776164835208375667498606187869211466397624286383057425296636315379314349307816391315242971306898487494604324473266965665471735612154916305882443496151118031672777088597821127499085632141307413890900246444539517971766135909771880642211582699957211983212981047822362311969553832913399476190919026666192056319334425636757404603336130688707109219644178606626422717046059209499394056295682594928581470210114322505904198054215544
e = 65537
n2=gmpy2.iroot(n,2)[0]
p=sympy.nextprime(n2)
q=n//p
phi=(p-1)*(q-1)
d=gmpy2.invert(e,phi)
m=pow(c,d,n)
print(long_to_bytes(m))

這段程式碼使用了幾個Python庫(gmpy2, sympy, Crypto.Util.number)來執行一個RSA加密資訊的解密過程。

  1. 匯入所需庫:

    import gmpy2
    import sympy
    from Crypto.Util.number import *
    
    • gmpy2庫用於高效的數學運算,特別是大數運算。
    • sympy庫用於符號數學計算,這裡主要用到了尋找下一個素數的功能。
    • Crypto.Util.number模組包含了處理大整數的工具。
  2. 定義密文、模數和公鑰指數:

    n = ...  # 很長的整數,模數
    c = ...  # 密文
    e = 65537  # 公鑰指數,常見的RSA公鑰指數
    
  3. 計算n的平方根:

    n2=gmpy2.iroot(n,2)[0]
    

    這裡嘗試計算n的平方根,並取整數部分,用於後續步驟中的近似估計p或q的大小。

  4. 尋找p和q:

    p=sympy.nextprime(n2)
    q=n//p
    

    首先,使用sympy.nextprime(n2)找到大於n的平方根的下一個素數作為p的一個估計值。然後,透過n除以p得到q的近似值。這裡的方法假設n是兩個相近的素數的乘積,且透過近似方法找到這兩個素數。

  5. 計算尤拉函式φ(n):

    phi=(p-1)*(q-1)
    

    計算模數n對應的尤拉函式φ(n),用於計算解密指數d。

  6. 計算解密指數d:

    d=gmpy2.invert(e,phi)
    

    利用擴充套件歐幾里得演算法計算d,使得(ed \equiv 1 \mod \phi(n))。

  7. 解密密文:

    m=pow(c,d,n)
    

    使用快速冪演算法計算(c^d \mod n),得到原始明文的數值表示。

  8. 轉換並列印解密結果:

    print(long_to_bytes(m))
    

    將解密得到的數值轉換為位元組串並列印出來,通常用於展示解密後的文字資訊。