对 RSA 的攻击

对 RSA 的攻击

文章目录

  • 对 RSA 的攻击
    • 直接分解 n
    • 计算 φ(n)
    • 解密指数
    • 低加密指数
      • 小明文攻击
      • 低加密指数广播攻击
        • 中国剩余定理
    • 共模攻击
    • Wiener 的低解密指数攻击
      • 原理
      • 代码
    • Rabin 解密
      • 分析
      • 代码

直接分解 n

  • 运气好可以试一试
  • yafu 工具
  • 网站 http://factordb.com/ 如果可以分解或以前分解成功过,可以直接得到 p , q p,q p,q

计算 φ(n)

  • 如果能得到 φ ( n ) \varphi(n) φ(n),则可通过 { n = p q φ ( n ) = ( p − 1 ) ( q − 1 ) \begin{cases} n=pq\\ \varphi(n)=(p-1)(q-1) \end{cases} {n=pqφ(n)=(p1)(q1)求出p,q
  • 也就是说,计算 φ ( n ) \varphi(n) φ(n)并不比分解 n 容易

解密指数

  • 如果能得到解密指数 d d d, 则可通过 { n = p q e d ≡ 1 ( m o d φ ( n ) ) φ ( n ) = p q − ( p + q ) + 1 \begin{cases} n=pq\\ ed \equiv 1\pmod{\varphi(n)}\\ \varphi(n)=pq-(p+q)+1 \end{cases} n=pqed1(modφ(n))φ(n)=pq(p+q)+1求出p,q
  • 也就是说,计算解密指数 d d d并不比分解 n 容易

低加密指数

小明文攻击

  • 可以考虑缩小范围后直接对明文进行枚举测试
  • 允许的话开一个进程池可以减短时间

低加密指数广播攻击

  • 如果选取了相同的加密指数对相同的明文进行了加密,如 { c 1 ≡ m e ( m o d n 1 ) c 2 ≡ m e ( m o d n 2 ) c 3 ≡ m e ( m o d n 3 ) \begin{cases} c_1\equiv m^e \pmod {n_1}\\ c_2\equiv m^e \pmod {n_2}\\ c_3\equiv m^e \pmod {n_3} \end{cases} c1me(modn1)c2me(modn2)c3me(modn3)
  • 直接使用中国剩余定理CRT得到 m e m^e me
  • 然后开方

中国剩余定理

import gmpy2
def GCRT(mi, ai):
    # mi,ai分别表示模数和取模后的值,都为列表结构
    assert (isinstance(mi, list) and isinstance(ai, list))
    curm, cura = mi[0], ai[0]
    for (m, a) in zip(mi[1:], ai[1:]):
        d = gmpy2.gcd(gmpy2.mpz(curm), gmpy2.mpz(m))
        c = a - cura
        assert (c % d == 0) #不成立则不存在解
        K = c // d * gmpy2.invert(gmpy2.mpz(curm // d), gmpy2.mpz(m // d))
        cura += curm * K
        curm = curm * m // d
        cura %= curm
    return (int(cura % curm), int(curm)) #(解,最小公倍数)

if __name__ == '__main__':
    m=[3,5,7,11,13,17,19]
    a=[2,3,4,5,6,7,8]
    print(GCRT(m,a))

共模攻击

  • 使用相同的模对相同明文用不同加密指数进行加密,如 { c 1 ≡ m e 1 ( m o d n ) c 2 ≡ m e 2 ( m o d n ) \begin{cases} c_1\equiv m^{e_1} \pmod n\\ c_2\equiv m^{e_2} \pmod n \end{cases} {c1me1(modn)c2me2(modn)则只要 e 1 ⊥ e 2 e_1\perp e_2 e1e2,即可找到 s 1 , s 2 s_1,s_2 s1,s2使得 s 1 e 1 + s 2 e 2 = 1 s_1e_1+s_2e_2=1 s1e1+s2e2=1从而 m ≡ m s 1 e 1 + s 2 e 2 ≡ c 1 s 1 c 2 s 2 ( m o d n ) m\equiv m^{s_1e_1+s_2e_2}\equiv c_1^{s_1}c_2^{s_2}\pmod n mms1e1+s2e2c1s1c2s2(modn)

Wiener 的低解密指数攻击

  • 当解密指数很小时可以考虑使用
    • 一般对应的加密指数会很大
  • 前提 { 3 d < n 1 / 4 q < p < 2 q \begin{cases} 3d< n^{1/4}\\ q< p < 2q \end{cases} {3d<n1/4q<p<2q

原理

  • 首先,由 e d ≡ 1 ( m o d φ ( n ) ) ed\equiv 1\pmod{\varphi(n)} ed1(modφ(n))得到 e d − k φ ( n ) = 1 e φ − k d = 1 φ d \begin{aligned} ed-k\varphi(n)&=1\\ \frac{e}{\varphi}-\frac{k}{d}&=\frac{1}{\varphi d} \end{aligned} edkφ(n)φedk=1=φd1
  • 因为当p,q很大时,n 和 φ \varphi φ应该会很接近,所以考虑用已知的 n 代替上式中的 φ \varphi φ,即 ∣ e n − k d ∣ = ∣ 1 + k ( φ − n ) n d ∣ \begin{aligned} \left|\frac{e}{n}-\frac{k}{d}\right|&=\left|\frac{1+k(\varphi-n)}{nd} \right| \end{aligned} nedk=nd1+k(φn)
  • n − φ = p + q − 1 < 2 q + q − 1 < 3 q < 3 n n-\varphi=p+q-1< 2q+q-1<3q< 3\sqrt n nφ=p+q1<2q+q1<3q<3n ∣ e n − k d ∣ < 3 k n d n = 3 k < 3 d < n 1 / 4 d n < 1 d n 1 / 4 < 1 3 d 2 \begin{aligned} \left|\frac{e}{n}-\frac{k}{d}\right|&< \frac{3k\sqrt{n}}{dn}=\frac{3k< 3d< n^{1/4}}{d\sqrt n}\\ &< \frac{1}{dn^{1/4}}\\ &< \frac{1}{3d^2} \end{aligned} nedk<dn3kn =dn 3k<3d<n1/4<dn1/41<3d21
  • 由如下定理:

定理:
假定 g c d ( a , b ) = g c d ( c , d ) = 1 gcd(a,b)=gcd(c,d)=1 gcd(a,b)=gcd(c,d)=1 ∣ a b − c d ∣ < 1 2 d 2 \left|\frac{a}{b}-\frac{c}{d}\right|< \frac{1}{2d^2} badc<2d21那么 c d \cfrac{c}{d} dc a b \cfrac{a}{b} ba 连分数展开的一个收敛子

  • 于是将 e n \cfrac{e}{n} ne 连分数得到一系列测试值,就必然能够得到 k , d k,d k,d
  • 从而密码攻破

代码

摘自 https://www.tr0y.wang/2017/11/06/CTFRSA/index.html

import gmpy2
import time
from binascii import unhexlify
# 展开为连分数
def continuedFra(x, y):
    cF = []
    while y:
        cF += [x // y]
        x, y = y, x % y
    return cF
def Simplify(ctnf):
    numerator = 0
    denominator = 1
    for x in ctnf[::-1]:
        numerator, denominator = denominator, x * denominator + numerator
    return (numerator, denominator)
# 连分数化简
def calculateFrac(x, y):
    cF = continuedFra(x, y)
    cF = map(Simplify, [cF[0:i] for i in range(1, len(cF))])
    return cF
# 解韦达定理
def solve_pq(a, b, c):
    temp=b*b-4*a*c
    if temp>=0:
        par = gmpy2.isqrt(temp)
        return (-b + par) // (2 * a), (-b - par) // (2 * a)
def wienerAttack(e, n):
    for (d, k) in calculateFrac(e, n):
        if k == 0: continue
        if (e * d - 1) % k != 0: continue
        phi = (e * d - 1) // k
        if phi<n:
            p, q = solve_pq(1, n - phi + 1, n)
            if p * q == n:
                return abs(int(p)), abs(int(q))
    print('not find!')
time.clock()
n = 12238605063252292170613110607692779326628090745751955692266649177882959231822580682548279800443278979485092243645806337103841086023159482786712759291169541633901936290854044069486201989034158882661270017305064348254800318759062921744741432214818915527537124001063995865927527037625277330117588414586505635959411443039463168463608235165929831344586283875119363703480280602514451713723663297066810128769907278246434745483846869482536367912810637275405943566734099622063142293421936734750356828712268385319217225803602442033960930413469179550331907541244416573641309943913383658451409219852933526106735587605884499707827
e = 11850552481503020257392808424743510851763548184936536180317707155841959788151862976445957810691568475609821000653594584717037528429828330763571556164988619635320288125983463358648887090031957900011546300841211712664477474767941406651977784177969001025954167441377912326806132232375497798238928464025466905201977180541053129691501120197010080001677260814313906843670652972019631997467352264392296894192998971542816081534808106792758008676039929763345402657578681818891775091140555977382868531202964486261123748663752490909455324860302967636149379567988941803701512680099398021640317868259975961261408500449965277690517
c = 9472193174575536616954091686751964873836697237500198884451530469300324470671555310791335185133679697207007374620225900775502162690848135615431624557389304657410880981454777737587420426091879654002644281066474715074536611611252677882396384453641127487515845176069574754606670518031472235144795376526854484442135299818868525539923568705203042265537204111153151119105287648912908771710419648445826883069030285651763726003413418764301988228077415599665616637501056116290476861280240577145515875430665394216054222788697052979429015400411487342877096677666406389711074591330476335174211990429870900468249946600544116793793
p, q = wienerAttack(e, n)
print('[+]Found!')
print('  [-]p =',p)
print('  [-]q =',q)
print('  [-]n =',p*q)
d = gmpy2.invert(e,(p-1)*(q-1))
print('  [-]d =', d)
m=hex(pow(c,d,n))
print('  [-]m is:' + str(unhexlify(m[2:])))
print('\n[!]Timer:', round(time.clock(),2), 's')
print('[!]All Done!')


#Tr0y{W1eNer_AttaCk_1s_p0werfu1!}

Rabin 解密

Rabin 密码体制
n = p q n=pq n=pq,其中 p , q p,q p,q为素数,且 p , q ≡ 3 ( m o d 4 ) p,q\equiv 3\pmod 4 p,q3(mod4)。设 P = C = Z n ∗ \mathcal{P=C }=\mathbb{Z}_n^* P=C=Zn,且定义 K = ( n , p , q ) \mathcal{K}={(n,p,q)} K=(n,p,q) K = ( n , p , q ) K=(n,p,q) K=(n,p,q),定义 e K ( x ) = x 2 m o d    n d K ( x ) = y m o d    n \begin{aligned} e_K(x)&=x^2\mod n\\ d_K(x)&=\sqrt{y}\mod n \end{aligned} eK(x)dK(x)=x2modn=y modn n n n为公钥, p , q p,q p,q为私钥

  • 条件 p , q ≡ 3 ( m o d 4 ) p,q\equiv 3\pmod 4 p,q3(mod4)以及 P = C = Z n ∗ \mathcal{P=C}=\mathbb{Z}_n^* P=C=Zn而非 Z n \mathbb{Z}_n Zn均可以省去
  • 加这些限制条件只是为了简化分析

分析

  • 在加密正确进行的情况下得到密文 y y y,想找出对应明文 x x x,使得 x 2 ≡ y ( m o d n ) x^2\equiv y\pmod n x2y(modn)这等价于求解 { z 2 ≡ y ( m o d p ) z 2 ≡ y ( m o d q ) \begin{cases} z^2\equiv y\pmod p\\ z^2\equiv y\pmod q \end{cases} {z2y(modp)z2y(modq)
  • 事实上,由 Euler 准则,有 y p − 1 2 ≡ 1 ( m o d p ) y^{\frac{p-1}{2}}\equiv 1\pmod p y2p11(modp)
  • 所以,当 p ≡ 3 ( m o d 4 ) p\equiv 3\pmod 4 p3(mod4)时,有一个简单公式来计算模 p p p二次剩余的平方根,即 y ≡ y ( p − 1 ) / 2 y ≡ y ( p + 1 ) / 2 ≡ ± y ( p + 1 ) / 4 ( m o d p ) \sqrt{y}\equiv \sqrt{y^{(p-1)/2}y}\equiv \sqrt{y^{(p+1)/2}}\equiv\pm y^{(p+1)/4}\pmod p y y(p1)/2y y(p+1)/2 ±y(p+1)/4(modp)
  • 同样可得到模 q q q的的2个平方根 ± y ( q + 1 ) / 4 m o d    q \pm y^{(q+1)/4}\mod q ±y(q+1)/4modq
  • 最后利用CRT球的 y m o d    n y\mod n ymodn的4个平方根

代码

import gmpy2
def rabin_decrypt(c, p, q, e=2):
    n = p * q
    mp=pow(c,(p+1)//4,p)
    mq=pow(c,(q+1)//4,q)
    yp = gmpy2.invert(p, q)
    yq = gmpy2.invert(q, p)
    r = (yp * p * mq + yq * q * mp) % n
    rr = n - r
    s = (yp * p * mq - yq * q * mp) % n
    ss = n - s
    return (r, rr, s, ss)

你可能感兴趣的:(密码学)