Wiener-attack

  1. 连分数
  2. 大致内容
连分数

形如:$a1+\frac{b1}{a2+\frac{b2}{a3+\frac{b3}{a4+…}}}$,$a_{n}$和$b_{n}$可取任意实数、复数。如果项数有限,则可以写成[$a_{1}$,$a_{2}$,$a_{3}$,$a_{4}$,…$a_{n}$]。

举例说明:把$\frac{61}{21}$写成连分数形式:

$2+\frac{1}{1+\frac{1}{9+\frac{1}{2}}}$ = [2,1,9,2]

大致内容

如果满足:d<$\frac{1}{3}n^{\frac{1}{4}}$,那么一种基于连分数(一个数论当中的问题)的特殊攻击类型就可以危害 RSA 的安全。此时需要满足:q<p<2q。

思路

在rsa加密里头,有ed $\equiv $ 1mod$\varphi (n)$,进一步有ed = 1+k*$\varphi (n)$,两边同除以d*$\varphi (n)$,并进行移位得到:

$\frac{e}{\varphi(n)} - \frac{k}{d} = \frac{1}{d\varphi(n)}$

又$\varphi (n)$ = p*q - p - q + 1 = n - (p+q) + 1$\approx$n(因为p、q非常大,n>>(p+q))

$\frac{e}{\varphi(n)} - \frac{k}{d} = \frac{1}{d\varphi(n)} \approx $$\frac{e}{n} - \frac{k}{d} = \frac{1}{d\varphi(n)}$

$d\varphi(n)$很大,倒数就非常小,故$\frac{e}{n}和\frac{k}{d}$相差很小,$\frac{e}{n}比\frac{k}{d}稍大些$,因为e和n是给出的,故我们可以通过计算,$\frac{e}{n}$的连分数展开,依次算出每一个渐进分数。$\frac{e}{n}比\frac{k}{d}大$,所以$\frac{e}{n}$的渐进分数覆盖了$\frac{k}{d}$。说明$\frac{e}{n}$的渐进分数里有等于$\frac{k}{d}$的分数。

举例说明:假设某个渐进分数$\frac{a}{b}$成立,则k=a,d=b,代回ed = 1+k$\varphi (n)$,就能够解出$\varphi (n)$来(设为y),可以列出一个表达式:n - (p+q) + 1 = y,n是已知的,把(p+q)当整体。所以(p+q)就能解出来,又n = pq也是已知的,通过韦达定理,有方程:$x^{2}$ - (p+q)*x+pq = 0,解方程就得到了p和q。

难点在于用脚本实现求解连分数,借鉴代码(doge)

例题:

n = 12238605063252292170613110607692779326628090745751955692266649177882959231822580682548279800443278979485092243645806337103841086023159482786712759291169541633901936290854044069486201989034158882661270017305064348254800318759062921744741432214818915527537124001063995865927527037625277330117588414586505635959411443039463168463608235165929831344586283875119363703480280602514451713723663297066810128769907278246434745483846869482536367912810637275405943566734099622063142293421936734750356828712268385319217225803602442033960930413469179550331907541244416573641309943913383658451409219852933526106735587605884499707827
e = 11850552481503020257392808424743510851763548184936536180317707155841959788151862976445957810691568475609821000653594584717037528429828330763571556164988619635320288125983463358648887090031957900011546300841211712664477474767941406651977784177969001025954167441377912326806132232375497798238928464025466905201977180541053129691501120197010080001677260814313906843670652972019631997467352264392296894192998971542816081534808106792758008676039929763345402657578681818891775091140555977382868531202964486261123748663752490909455324860302967636149379567988941803701512680099398021640317868259975961261408500449965277690517
c = 9472193174575536616954091686751964873836697237500198884451530469300324470671555310791335185133679697207007374620225900775502162690848135615431624557389304657410880981454777737587420426091879654002644281066474715074536611611252677882396384453641127487515845176069574754606670518031472235144795376526854484442135299818868525539923568705203042265537204111153151119105287648912908771710419648445826883069030285651763726003413418764301988228077415599665616637501056116290476861280240577145515875430665394216054222788697052979429015400411487342877096677666406389711074591330476335174211990429870900468249946600544116793793

e很大,这是关键特征,解密脚本:

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

# numerator(n):分子, denominator(d):分母
def t_cf(n, d):  # 将分数 x/y 转为连分数的形式
    res = []
    while d:
        res.append(n // d)
        n, d = d, n % d
    return res


def cf(sub_res):  # 得到渐进分数的分母和分子
    n, d = 1, 0
    for i in sub_res[::-1]:  # 从后面往前循环
        d, n = n, i * n + d
    return d, n


def list_fraction(x, y):  # 列出每个渐进分数
    res = t_cf(x, y)
    res = list(map(cf, (res[0:i] for i in range(1, len(res)))))  # 将连分数的结果逐一截取以求渐进分数
    return res


def get_pq(a, b, c):  # 由p+q和pq的值通过维达定理来求解p和q(解二元一次方程)
    par = 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 list_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 = invert(e, (p - 1) * (q - 1))  # 求ed=1 (mod  φ(n))的结果,也就是e关于 φ(n)的乘法逆元d
            return d
    print("求解d失败")


n = 12238605063252292170613110607692779326628090745751955692266649177882959231822580682548279800443278979485092243645806337103841086023159482786712759291169541633901936290854044069486201989034158882661270017305064348254800318759062921744741432214818915527537124001063995865927527037625277330117588414586505635959411443039463168463608235165929831344586283875119363703480280602514451713723663297066810128769907278246434745483846869482536367912810637275405943566734099622063142293421936734750356828712268385319217225803602442033960930413469179550331907541244416573641309943913383658451409219852933526106735587605884499707827
e = 11850552481503020257392808424743510851763548184936536180317707155841959788151862976445957810691568475609821000653594584717037528429828330763571556164988619635320288125983463358648887090031957900011546300841211712664477474767941406651977784177969001025954167441377912326806132232375497798238928464025466905201977180541053129691501120197010080001677260814313906843670652972019631997467352264392296894192998971542816081534808106792758008676039929763345402657578681818891775091140555977382868531202964486261123748663752490909455324860302967636149379567988941803701512680099398021640317868259975961261408500449965277690517
c = 9472193174575536616954091686751964873836697237500198884451530469300324470671555310791335185133679697207007374620225900775502162690848135615431624557389304657410880981454777737587420426091879654002644281066474715074536611611252677882396384453641127487515845176069574754606670518031472235144795376526854484442135299818868525539923568705203042265537204111153151119105287648912908771710419648445826883069030285651763726003413418764301988228077415599665616637501056116290476861280240577145515875430665394216054222788697052979429015400411487342877096677666406389711074591330476335174211990429870900468249946600544116793793
d = wienerAttack(e, n)

print(long_to_bytes(pow(c,d,n)))

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 1666739907@qq.com
github