arrow-left

All pages
gitbookPowered by GitBook
1 of 1

Loading...

Wiener's Attack

Wiener's attack is an attack on RSA that uses continued fractions to find the private exponent ddd when it's small (less than 13n4\frac{1}{3}\sqrt[4]{n}31​4n​, where nnn is the modulus). We know that when we pick the public exponent eee to be a small number and calcute its inverse d≑eβˆ’1mod  ϕ(n)d \equiv e^{-1} \mod \phi(n)d≑eβˆ’1modΟ•(n)

hashtag
Wiener's theorem

Wiener's attack is based on the following theorem:

Let , with . Let . Given and with , the attacker can efficiently recover .

hashtag
Some observations on RSA

In order to better understand Wiener's Attack, it may be useful to take note of certain properties of RSA:

We may start by noting that the congruence can be written as the equality for some value , we may additionally note that , since both and are much shorter than , we can say that .

Dividing the former equation by gives us , and using the latter approximation, we can write this as . Notice how the left-hand side of this equation is composed entirely of public information, this will become important later.

It is possible to quickly factor by knowing and . Consider the quadratic polynomial , this polynomial will have the roots and . Expanding it gives us , and substituting for the variables we know we can write this as . Applying the quadratic formula gives us and : , where , , and .

Wiener's attack works by expanding to a continued fraction and iterating through the terms to check various approximations of . In order to make this checking process more efficient, we can make a few observations (this part is optional):

  • Since is even, and and are both by definition coprime to , we know that is odd.

  • Given the above equations and the values of , , , and , we can solve for with the equation , thus we know that has to be divisible by .

hashtag
The Attack

Suppose we have the public key , this attack will determine

  1. Convert the fraction into a continued fraction

  2. Iterate over each convergent in the continued fraction:

  3. Check if the convergent is by doing the following:

Here's a sage implementation to play around with:

//TODO: Proof of Wiener's theorem

hashtag
Automation

The Python module owiener simplifies the scripting process of Wiener's attack:

Here is a Wiener's attack template:

If our Ο•(n)\phi(n)Ο•(n) is correct, the polynomial x2βˆ’(nβˆ’Ο•(n)+1)x+nx^2 - (n - \phi(n) + 1)x + nx2βˆ’(nβˆ’Ο•(n)+1)x+n will have roots ppp and qqq, which we can verify by checking if pq=npq = npq=n.

Set the numerator to be kkk and denominator to be ddd

  • Check if ddd is odd, if not, move on to the next convergent

  • Check if ed≑1mod  ked \equiv 1 \mod ked≑1modk, if not, move on to the next convergent

  • Set Ο•(n)=edβˆ’1k\phi(n) = \frac{ed-1}{k}Ο•(n)=kedβˆ’1​ and find the roots of the polynomial x2βˆ’(nβˆ’Ο•(n)+1)x+nx^2 - (n - \phi(n) + 1)x + nx2βˆ’(nβˆ’Ο•(n)+1)x+n

  • If the roots of the polynomial are integers, then we've found ddd. (If not, move on to the next convergent)

  • If all convergents have been tried, and none of them work, then the given RSA parameters are not vulnerable to Wiener's attack.

  • n=pqn = pqn=pq
    q<p<2qq < p < 2qq<p<2q
    d<13n4d < \frac{1}{3}\sqrt[4]{n}d<31​4n​
    nnn
    eee
    ed≑1mod  ϕ(n)ed \equiv 1 \mod \phi(n)ed≑1modΟ•(n)
    ddd
    ed≑1mod  ϕ(n)ed \equiv 1 \mod \phi(n)ed≑1modΟ•(n)
    ed=kΟ•(n)+1ed = k\phi(n)+1ed=kΟ•(n)+1
    kkk
    Ο•(n)=(pβˆ’1)(qβˆ’1)=pqβˆ’pβˆ’q+1\phi(n) = (p-1)(q-1) = pq - p - q + 1Ο•(n)=(pβˆ’1)(qβˆ’1)=pqβˆ’pβˆ’q+1
    ppp
    qqq
    pq=npq = npq=n
    Ο•(n)β‰ˆn\phi(n) \approx nΟ•(n)β‰ˆn
    dΟ•(n)d\phi(n)dΟ•(n)
    eΟ•(n)=k+1d\frac{e}{\phi(n)} = \frac{k+1}{d}Ο•(n)e​=dk+1​
    enβ‰ˆkd\frac{e}{n} \approx \frac{k}{d}neβ€‹β‰ˆdk​
    nnn
    nnn
    Ο•(n)\phi(n)Ο•(n)
    (xβˆ’q)(xβˆ’p)(x-q)(x-p)(xβˆ’q)(xβˆ’p)
    ppp
    qqq
    x2βˆ’(p+q)x+pqx^2 - (p + q)x + pqx2βˆ’(p+q)x+pq
    x2βˆ’(nβˆ’Ο•(n)+1)x+nx^2 - (n - \phi(n) + 1)x + nx2βˆ’(nβˆ’Ο•(n)+1)x+n
    ppp
    qqq
    p∧q=βˆ’bΒ±b2βˆ’4ac2ap \wedge q = \frac{-b \pm \sqrt{b^2-4ac}}{2a}p∧q=2aβˆ’bΒ±b2βˆ’4ac​​
    a=1a = 1a=1
    b=nβˆ’Ο•(n)+1b = n - \phi(n) + 1b=nβˆ’Ο•(n)+1
    c=nc = nc=n
    en\frac{e}{n}ne​
    kd\frac{k}{d}dk​
    Ο•(n)\phi(n)Ο•(n)
    eee
    ddd
    Ο•(n)\phi(n)Ο•(n)
    ddd
    eee
    nnn
    ddd
    kkk
    Ο•(n)\phi(n)Ο•(n)
    Ο•(n)=edβˆ’1k\phi(n) = \frac{ed-1}{k}Ο•(n)=kedβˆ’1​
    edβˆ’1ed-1edβˆ’1
    kkk
    (n,e)(n, e)(n,e)
    ddd
    en\frac{e}{n}ne​
    [a0;a1,a2,…,akβˆ’2,akβˆ’1,ak][a_0;a_1,a_2, \ldots , a_{k-2},a_{k-1}, a_k][a0​;a1​,a2​,…,akβˆ’2​,akβˆ’1​,ak​]
    a01,a0+1a1,a0+1a1+1a2, …,a0+1a1+β‹±akβˆ’2+1akβˆ’1,\frac{a_{0}}{1},a_{0} + \frac{1}{a_{1}},a_{0} + \frac{1}{a_{1} + \frac{1}{a_{2}}}, \ \ldots, a_{0} + \frac{1}{a_{1} + \frac{\ddots} {a_{k-2} + \frac{1}{a_{k-1}}}},1a0​​,a0​+a1​1​,a0​+a1​+a2​1​1​, …,a0​+a1​+akβˆ’2​+akβˆ’1​1​⋱​1​,
    kd\frac{k}{d}dk​
    from Crypto.Util.number import long_to_bytes
    
    def wiener(e, n):
        # Convert e/n into a continued fraction
        cf = continued_fraction(e/n)
        convergents = cf.convergents()
        for kd in convergents:
            k = kd.numerator()
            d = kd.denominator()
            # Check if k and d meet the requirements
            if k == 0 or d%2 == 0 or e*d % k != 1:
                continue
            phi = (e*d - 1)/k
            # Create the polynomial
            x = PolynomialRing(RationalField(), 'x').gen()
            f = x^2 - (n-phi+1)*x + n
            roots = f.roots()
            # Check if polynomial as two roots
            if len(roots) != 2:
                continue
            # Check if roots of the polynomial are p and q
            p,q = int(roots[0][0]), int(roots[1][0])
            if p*q == n:
                return d
        return None
    # Test to see if our attack works
    if __name__ == '__main__':
        n = 6727075990400738687345725133831068548505159909089226909308151105405617384093373931141833301653602476784414065504536979164089581789354173719785815972324079
        e = 4805054278857670490961232238450763248932257077920876363791536503861155274352289134505009741863918247921515546177391127175463544741368225721957798416107743
        c = 5928120944877154092488159606792758283490469364444892167942345801713373962617628757053412232636219967675256510422984948872954949616521392542703915478027634
        d = wiener(e,n)
        assert not d is None, "Wiener's attack failed :("
        print(long_to_bytes(int(pow(c,d,n))).decode())
    #!/usr/bin/env python3
    import owiener
    from Crypto.Util.number import long_to_bytes
    
    #--------Data--------#
    
    N = <N>
    e = <e>
    c = <c>
    
    #--------Wiener's attack--------#
    
    d = owiener.attack(e, N)
    
    if d:
        m = pow(c, d, N)
        flag = long_to_bytes(m).decode()
        print(flag)
    else:
        print("Wiener's Attack failed.")
    GitHub - orisano/owiener: A Python3 implementation of the Wiener attack on RSAGitHubchevron-right
    owiener
    Logo