1. 程式人生 > 其它 >RSA之初學維納攻擊

RSA之初學維納攻擊

Wiener’s Attack

適用情況:e過大或過小。

在e過大或過小的情況下,可使用演算法從e中快速推斷出d的值。

Wiener 表示如果滿足:

d<1/3n1/4

那麼一種基於連分數的特殊攻擊型別就可以危害 RSA 的安全。此時需要滿足:

q<p<2q

如果滿足上述條件,通過 Wiener Attack 可以在多項式時間中分解 n,思路如下:

N = pq

φ(n)=(p−1)(q−1)=pq−(p+q)+1=N−(p+q)+1

∵p, q 非常大 ,
∴pq≫p+q,
∴φ(n)≈N

∵ed≡1modφ(n),
∴ed−1=kφ(n),
這個式子兩邊同除 dφ(n)

可得:

eφ(n)−kd=1dφ(n)

∵φ(n)≈N,
∴eN−kd=1dφ(n),同樣 dφ(n) 是一個很大的數,所以 eN 略大於 kd, e 和 N 是我們是知道的,公鑰中給我們的,所以我們計算出 eN後,比它略小的 kd 用計算 eN 的連分數展開,依次算出這個分數每一個漸進分數,由於 eN 略大於 kd,wiener 證明了,該攻擊能精確的覆蓋 kd。

例題:
在不分解n的前提下,求d。

給定:

e = 14058695417015334071588010346586749790539913287499707802938898719199384604316115908373997739604466972535533733290829894940306314501336291780396644520926473

n = 33608051123287760315508423639768587307044110783252538766412788814888567164438282747809126528707329215122915093543085008547092423658991866313471837522758159

說明過程。

按照求解的漸進分數的分子分母分別對應減數的分子分母,從頭將所有的漸進分數的分子分母求解出來。

由於水平限制,我能看懂程式碼,但是寫不出來,以下內容來自搬運。

import gmpy2
def transform(x,y):       #使用輾轉相處將分數 x/y 轉為連分數的形式
    res=[]
    while y:
        res.append(x//y)
        x,y=y,x%y
    return res
    
def continued_fraction(sub_res):
    numerator,denominator=1,0
    for i in sub_res[::-1]:      #從sublist的後面往前迴圈
        denominator,numerator=numerator,i*numerator+denominator
    return denominator,numerator   #得到漸進分數的分母和分子,並返回

    
#求解每個漸進分數
def sub_fraction(x,y):
    res=transform(x,y)
    res=list(map(continued_fraction,(res[0:i] for i in range(1,len(res)))))  #將連分數的結果逐一擷取以求漸進分數
    return res

def get_pq(a,b,c):      #由p+q和pq的值通過維達定理來求解p和q
    par=gmpy2.isqrt(b*b-4*a*c)   #由上述可得,開根號一定是整數,因為有解
    x1,x2=(-b+par)//(2*a),(-b-par)//(2*a)
    return x1,x2

def wienerAttack(e,n):
    for (d,k) in sub_fraction(e,n):  #用一個for迴圈來注意試探e/n的連續函式的漸進分數,直到找到一個滿足條件的漸進分數
        if k==0:                     #可能會出現連分數的第一個為0的情況,排除
            continue
        if (e*d-1)%k!=0:             #ed=1 (mod φ(n)) 因此如果找到了d的話,(ed-1)會整除φ(n),也就是存在k使得(e*d-1)//k=φ(n)
            continue
        
        phi=(e*d-1)//k               #這個結果就是 φ(n)
        px,qy=get_pq(1,n-phi+1,n)
        if px*qy==n:
            p,q=abs(int(px)),abs(int(qy))     #可能會得到兩個負數,負負得正未嘗不會出現
            d=gmpy2.invert(e,(p-1)*(q-1))     #求ed=1 (mod  φ(n))的結果,也就是e關於 φ(n)的乘法逆元d
            return d
    print("該方法不適用")
    
    
e = 14058695417015334071588010346586749790539913287499707802938898719199384604316115908373997739604466972535533733290829894940306314501336291780396644520926473
n = 33608051123287760315508423639768587307044110783252538766412788814888567164438282747809126528707329215122915093543085008547092423658991866313471837522758159
d=wienerAttack(e,n)
print("d=",d)`

參考:https://en.wikipedia.org/wiki/Wiener%27s_attack