Before all
自己在嗑RSA的時候會發現看到後來好多 Coppersmith’s 相關的東西……
所以今天就來整理一些
主要用來放攻擊方法和腳本,其他的數學我覺得底下 #meow 的連結一定會寫得更好。
之後應該會加更多東西(如果有看到?)
meow?
超詳細數學證明和相關資料:
https://www.math.auckland.ac.nz/~sgal018/crypto-book/ch19.pdf
CTF WIKI:
https://ctf-wiki.org/crypto/asymmetric/rsa/rsa_coppersmith_attack/
基本原理
其實跟 CTF WIKI 幾乎一樣
有個多項式$f$以及模數$N$
此時,必須要有模數$N$有個因數$b$滿足$b \geq N^\beta$,$0< \beta \leq1$,而$f$的最高次為$\delta$
則Coppersmith’s Method可以在複雜度為$O(c\delta^5 log^9(N))$內找到多項式所有的根$x_0$
其中,$|x_0|\leq c N^{\frac{\beta^2}{\delta}}$
而這裡面主要是使用LLL算法(詳細請看lattices章節)找到多項式g滿足:
- 跟 f 在模$N$底下具有相同的根
- 最高次小於 $\delta$
- 定義域為$Z$
Sage math 實作
review
在sage math裡面可以定義一個多項式環像是這樣:
1
| P.<x>=PolynomialRing(Zmod(n))
|
則接下來所有帶x的多項式都會在Zmod(n)
底下做事,也就是模$n$底下。
然而,有時候會發現無法使用,這時候就可以嘗試利用preparse
函數:
1
| preparse('P.<x>=PolynomialRing(Zmod(n))')
|
Result:
1
| P = PolynomialRing(Zmod(n), names=('x',)); (x,) = P._first_ngens(1)
|
small_roots
在定義好PolymonialRing
後,sage裡面可以定義多項式像是:
然後使用:
可以直接得到該多項式在mod n底下的所有解(就是mod n為0的case)
但small_roots如果加了其他參數,像是:
1
| f.small_roots(X=2**128, beta=0.4)
|
那sage就會去把所有模$b$底下,小於$2^{128}$的解算出來。
其中,所有$b$滿足$b\geq N^\beta$。
monic
f.monic()
會把f最高項係數變成1,整個多項式解不變。
Known High Bits Of p
與一般的RSA題目一樣,但是多洩漏了其中一個質數大部分的bits。
source.py
1 2 3 4 5 6 7 8 9 10
| from Crypto.Util.number import * import secret p=getPrime(1004) q=getPrime(1004) n=p*q e=65537 m=bytes_to_long(secret.flag) c=pow(m, e, n) p0=(p>>120)<<120 print(f'{e=}\n{p0=}\n{n=}\n{c=}')
|
output:
1 2 3 4
| e=65537 p0=100465147640470485747293851090553574310053846134542653110704375676461794188050191127456143420090556236801889086711291980553762803490312581046371622870118885986763001912930292410236052966369197265314469363900415533118122038452105876822779245783522825304703574113976849737577129994640979865687397702303744 n=9358294656208497385745434081628457905779263307683434943156483514225129151118781992081317431005767541191066082926013882312659363690266983156107387214041005908019920858498754227661688449973057792052555960805263584061590368578897283881536232480071584234752271762419511847036422301239877606394638940073902997079428457423278415147306781623381163825231265165174852942029342005272627678806408259172877110585065440907744079380341938662530592616068654539113193581491867956360391381284386206799666451643805534487406525739167743974211495493692774788851513689797110146360608259027416196901679191902424554095345163007 c=6170141117310175595348810174464424974102515146766823582968196972770630845077260468896168991247383199702954907173412521293108538007202468268521821472498223995423396084372233553988037880795510363416470730618971989758460635306563027013683072184493221401011751850093605052602074410616558416040654196817317524403836542977145554429556261174576928382083234138500759504174823279318744947301881921849301569065217486802173407809085814053069088495214821174942469051430725477655350720103052904487538623797670952706325913765157345516378821524593872129832388609068307445134272454291753269768219407292025886810682462973
|
在上面的範例裡,可以假設$f(x)=p0+x$,則當解出$f(x)$在$mod$ $p$下的根時,那個$x$就是p的後120 bits。
於是利用剛剛前面講過的small_roots
就可以解決問題~
$\beta$的值通常會在0.4左右,看情況而定,能從一開始Coppersmith’s method利用條件算(
solve.sage:
1 2 3 4 5 6 7 8 9 10 11 12
| e=65537 p0=100465147640470485747293851090553574310053846134542653110704375676461794188050191127456143420090556236801889086711291980553762803490312581046371622870118885986763001912930292410236052966369197265314469363900415533118122038452105876822779245783522825304703574113976849737577129994640979865687397702303744 n=9358294656208497385745434081628457905779263307683434943156483514225129151118781992081317431005767541191066082926013882312659363690266983156107387214041005908019920858498754227661688449973057792052555960805263584061590368578897283881536232480071584234752271762419511847036422301239877606394638940073902997079428457423278415147306781623381163825231265165174852942029342005272627678806408259172877110585065440907744079380341938662530592616068654539113193581491867956360391381284386206799666451643805534487406525739167743974211495493692774788851513689797110146360608259027416196901679191902424554095345163007 c=6170141117310175595348810174464424974102515146766823582968196972770630845077260468896168991247383199702954907173412521293108538007202468268521821472498223995423396084372233553988037880795510363416470730618971989758460635306563027013683072184493221401011751850093605052602074410616558416040654196817317524403836542977145554429556261174576928382083234138500759504174823279318744947301881921849301569065217486802173407809085814053069088495214821174942469051430725477655350720103052904487538623797670952706325913765157345516378821524593872129832388609068307445134272454291753269768219407292025886810682462973 P.<x>=PolynomialRing(Zmod(n)) f=p0+x p_small=f.small_roots(2**121, 0.4)[0] p=p0+p_small q=int(n)//int(p) phi=(p-1)*(q-1) d=inverse(int(e), int(phi)) print(long_to_bytes(pow(int(c), int(d), int(n))))
|
註:會掛一堆int()
是因為sage會把這些int當作PolynomialRing底下的物件。
Known High Bits Message Attack
在已經知道大部分訊息時的攻擊:
假設今天原始訊息為$M$,你已經知道前k個bits的$M_0$,那在拿到加密後的訊息:$M^e(mod)$ $N$時可以破解。
把多項式變成$(M_0+x)^e-C$即可owob
Franklin–Reiter Attack
一樣在RSA加密底下
令一個訊息$M_0$被$f(x)=ax+b$處理後為$M_1$,它們加密後分別是$C_0$以及$C_1$
則因為$x^e-C_0$和$f(x)^e-C_1$的解在模$N$底下都有$M_0$,所以只要算出它們的gcd,當中一定有$x-M_0$。
(所以在CTF競賽中,這類型題目的$e$一般不會太大,不然很難剛好線性。
攻擊複雜度為:$O(elog^2N)$
1 2 3 4 5 6 7 8 9 10
| def attack(c1, c2, a, b, e, n): PR.<x>=PolynomialRing(Zmod(n)) g1 = x^e - c1 g2 = (a*x+b)^e - c2 g2 = g2.monic() def gcd(g1, g2): while g2: g1, g2 = g2, g1 % g2 return g1.monic() return -gcd(g1, g2)[0]
|
Coppersmith’s short pad Attack
當訊息的padding太小會出事,因為對應的多項式根很小(就是訊息)
詳細可以去看:https://en.wikipedia.org/wiki/Coppersmith%27s_attack#Coppersmith%E2%80%99s_short-pad_attack
實作:https://github.com/yud121212/Coppersmith-s-Short-Pad-Attack-Franklin-Reiter-Related-Message-Attack/blob/master/coppersmiths_short_pad_attack.sage
Boneh and Durfee attack
進階版的Wiener’s Attack
界是$d>N^{2.092}$
可以看:
https://github.com/mimoo/RSA-and-LLL-attacks/blob/master/boneh_durfee.sage