We experiment with Wiener's attack to break RSA when the secret exponent is short, meaning it is smaller than one quarter of the public modulus size. We discuss cryptanalysis details and present demos of the attack. Our very minor extension of Wiener's attack is also discussed.
If we have an RSA 2048 bits configuration, but our private exponent d is only about 512 bits, then the above attack breaks RSA in a few seconds.
This work uses Continued Fractions to derive the private keys from the given public keys. It turned out that one can derive the private exponent d by approximating it as a ratio of e/n, both are public values.
In a default settings of standard RSA libaries, this attack and my minor extension are not relevant (to the best of our knowledge). However, if we configure our library to choose a very large public encryption exponent e, then our private decryption exponent d could be short enough to mount an attack.
2. Disclaimer
● The opinions expressed here are my own
○ But not the views of my employer
● The source code fragments and exploits shown here can be reused
○ But without any warranty nor accept any responsibility for failures
● Do not apply the exploit discussed here on other systems
○ Without obtaining authorization from owners
2
3. Context (notations are formally defined later)
● A short RSA private exponent d will speed-up the digital signature process
● Wiener broke RSA when d < ⅓ n1/4
, where n is a public modulus
● Wiener used the theory of Continued Fractions (CFs) for his attack
● I extended Wiener’s attack when d < n1/4
; revealed ~60% of private keys
○ My very, very tiny contribution to RSA cryptanalysis
○ I also use CFs but note that my upper bound is slightly stronger (i.e., without the constant ⅓)
○ Other researchers extended Wiener’s attack using Lattice theory (a future topic)
3
4. Prerequisite
Some familiarity with the following topics will help to follow the rest of the slides
● Group Theory
● Number Theory
● Algorithms and Complexity Theory
● If not, it should still be possible to obtain a high-level overview
4
5. Agenda
● Introduction to Continued Fractions (CFs) and Convergents
● Brief overview of RSA
● Core idea of Wiener’s RSA Math Attack using CFs and Convergents
● Demos of Wiener’s Attack
● Extending Wiener’s Attack
● Implication of this attack and my extensions
5
6. Continued Fractions - A Jigsaw Puzzle Example
6
Reference: http://www.maths.surrey.ac.uk/hosted-sites/R.Knott/Fibonacci/cfINTRO.html
7. Continued Fractions
7
$ java ContFract 45 16
[2,1,4,3]
Equivalently, 45/16 = 2 + 1/(1 + 1/(4+⅓))
[2, 1, 4, 3] is just a shorthand for writing continued fractions
I wrote a recursive implementation that computes the continued fractions
(see the Appendix for code details)
8. 8
Convergents of Continued Fractions
$ java ContFract 45 16
[2,1,4,3]
Convergents of 45/16:
2/1
3/1
14/5
45/16
Interpretation: 45/16 can be approximated by 2/1, 3/1, 14/5, or 45/16
(see the Appendix for my code that generates convergents of given CFs)
9. How can Bob send a message to Alice securely?
9
Public Key PuA
● Alice and Bob never met each other
● Bob will encrypt using Alice’s public key
○ Assume that public keys are known to the world
● Alice will decrypt using her private key
○ Private keys are secrets (never sent out)
● Bob can sign messages using his private key
○ Alice verifies message integrity using Bob’s public key
● Note: Alice and Bob need other evidence (e.g., passwords,
certificates) to prove their identity to each other
● Who are Alice, Bob, and Eve?
Private Key PrA
Public Key PuB
Private Key PrB
10. RSA Public Key Cryptography System
● Published in 1977 by Ron Rivest, Adi Shamir and Leonard Adleman
● Rooted in elegant mathematics - Group Theory and Number Theory
● Core idea: Anyone can encrypt a message using recipient's public key but
○ (as far as we know) no one can efficiently decrypt unless they got the matching private key
● Encryption and Decryption are inverse operations (math details later)
○ Work of Euclid, Euler, and Fermat provide the mathematical foundation of RSA
● Eavesdropper Eve cannot easily derive the secret (math details later)
○ Unless she solves “hard” number theory problems that are computationally intractable
10
11. 11
Notations and Facts (needed for RSA Trapdoor)
GCD(x, y): The greatest common divisor that divides integers x and y
Co-prime: If gcd(x, y) = 1, then x and y are co-primes
Zn
= { 0, 1, 2, …, n-1 }, n > 0; we may imagine Zn
as a circular wall clock
Z*
n
= { x ∈ Zn
| gcd(x, n) = 1 }; (additional info: Z*
n
is a multiplicative group)
φ(n): Euler’s Totient function denotes the number of elements in Z*
n
φ(nm) = φ(n).φ(m) (This property is called multiplicative)
φ(p) = p-1, if p is a prime number
12. Notations and Facts (needed for RSA Trapdoor) ...
● x ≡ y (mod n) denotes that n divides x-y; x is congruent to y mod n
● Euler’s Theorem: aφ(n)
≡ 1 (mod n), if gcd(a, n) = 1
● Fermat’s Little Theorem: ap
≡ a (mod p)
● Gauss’s Fundamental Theorem of Arithmetic: Any integer greater than 1 is
either a prime or can be written as a unique product of primes
○ Euclid’s work is the foundation for this theorem, see The Elements
● Euclid’s Lemma: if a prime p divides the product of two natural numbers a
and b, then p divides a or p divides b
● Euclid’s Infinitude of Primes (c. 300 BC): There are infinitely many primes
12
13. RSA - Key Generation Algo
1. Select an appropriate bitlength of the RSA modulus n (e.g., 2048 bits)
○ Value of the parameter n is not chosen until step 3; small n is dangerous (details later)
2. Pick two independent, large random primes, p and q, of half of n’s bitlength
○ In practice, q < p < 2q to avoid attacks (e.g., Fermat’s factorization)
3. Compute n = p.q (n is also called the RSA modulus)
4. Compute Euler’s Totient (phi) Function φ(n) = φ(p.q) = φ(p)φ(q) = (p-1)(q-1)
5. Select numbers e and d from Zn
such that e.d ≡ 1(mod φ(n))
○ e must be relatively prime to φ(n) otherwise d cannot exist (i.e., we cannot decrypt)
○ d is the multiplicative inverse of e in Zn
6. Public key is the pair <n, e> and private key is 4-tuple <φ(n), d, p, q>
13
14. RSA Trapdoor
● RSA: Zn
→ Zn
● Let x and y ∈ Zn
● y = RSA(x) = xe
mod n
○ We may view x as a plaintext, and y as the corresponding ciphertext
● x = RSA-1
(y) = yd
mod n
● e and d are also called encryption and decryption exponents, respectively
● Short private exponent d can speed-up decryption and digital signature
14
15. RSA Trapdoor variables’ dependency graph
15
Private variable
Public variable
Note: Public exponent e affects the private exponent d, and vice-versa
16. Additional facts (needed for Wiener’s attack)
16
Fact: φ(n) ≅ n
Proof:
φ(n) = φ(p) φ(q)
= (p-1)(q-1)
= pq-(p+q)+1
= n-(p+q) + 1
But, we know that p and q are ≅ n1/2
⇒ (p+q) is ≅ n1/2
That is, the half most-significant bits of n and φ(n) are the same.
Thus, φ(n) ≅ n
17. Additional facts (needed for Wiener’s attack) ...
17
Fact: φ(n) is an even integer
Proof:
φ(n) = φ(p) φ(q)
= (p-1)(q-1)
Since p and q are large primes, which are odd, (p-1) and (q-1) are even
Thus, φ(n) is even
18. Additional facts (needed for Wiener’s attack) ...
18
Fact: Both public and private exponents e and d, respectively, are odd
Proof (by contradiction):
We know that e.d ≡ 1(mod φ(n))
Recall that φ(n) is even
If e is even, then gcd(e, φ(n)) ≠ 1, meaning e-1
cannot exist
This means that we cannot find a private exponent d when e is even
Thus, e cannot be even. By symmetry, we can prove d cannot be even.
19. 19
e.d ≡ 1(mod φ(n))
e.d = k φ(n) + 1, for some integer k
e.d - k φ(n) = 1
e/φ(n) - k/d = 1/dφ(n) [ Divide both sides by dφ(n) ]
Since φ(n) ≅ n, we shall rewrite the above equation as follows:
e/n - k/d = 1/dφ(n)
Since 1/dφ(n) is very close to zero, we can assume e/n ≅ k/d
Wiener’s trick is to use continued fractions of e/n to find the secret d
Core idea of Wiener’s attack
20. Demo on a toy example: given e and n find d, p, q
20
~/crypto/RSA$ e=17993;n=90581
~/crypto/RSA$ java ContFract $e $n
[0,5,29,4,1,3,2,4,3]
Convergents:
0/1, 1/5 , 29/146, 117/589, 146/735, 555/2794, 1256/6323, 5579/28086,
17993/90581
(We confirm that d = 5 is part of the second convergent)
In fact, we can factor n and obtain its prime factors p and q
~/crypto/RSA$ java Wiener 17993 90581
p = 379;q = 239;d = 5
21. How do we know we found the correct k and d?
21
e.d - k φ(n) = 1 ⇒ φ(n) = (1+ e.d)/k
If our convergent has the correct k and d, we will have the correct φ(n)
We can easily factor n from φ(n) as follows:
Recall, φ(n) = φ(p) φ(q) = (p-1)(q-1) = (p-1)(n/p - 1) [since n = pq)
Thus, we have a quadratic equation in p: p2
- (n+ 1- φ(n))p + n = 0
22. How do we know we found the correct k and d? ...
22
We have to solve this quadratic equation: p2
- (n+ 1- φ(n))p + n = 0
From algebra, we can solve ax2
+ bx + c = 0 using this formula
x=(-b∓√(b2
-4ac))/2a
Also, we know that the product of the roots is equal to c/a
In our case, a= 1, c= n, thus the product of the roots is equal to n/1 or n
Thus, the roots of the above equation are the prime factors p and q of n
23. Demo of a failure case: given e and n, failed to find d
23
Let’s consider the following RSA public and private keys:
Modulus n = 2896258861; e = 3
Private exponent d = 1930766955
p = 60773; q = 47657; phi = 2896150432
On the next slide, we see that the continued fractions of e/n do not contain
our private d
24. Demo of a failure case ...
24
~/crypto/RSA$ e=3;n=2896258861
~/crypto/RSA$ java ContFract $e $n
[0,965419620,3] or equivalently 3/2896258861 = 0 + 1/(965419620 + 1/3)
Convergents of 3/2896258861:
0/1, 1/965419620, 3/2896258861
But, in this demo, our private d is not on the convergents of e/n
This is good news; otherwise, Wiener’s attack breaks RSA of all key sizes!
25. Wiener’s theorem
25
● In the second demo, we couldn’t break RSA to find d from <n, e>
● Wiener proposed a theorem that when d is a short exponent, RSA is broken
Wiener’s theorem:
Let n = p.q with q < p < 2q. Let d < ⅓ n1/4
.
Given a public key <n, e>, the attacker can efficiently recover d
(Proof of this theorem is available on Wiener’s scientific paper; see Reference)
26. 26
Given the following e and n, find the secret key d and the prime factors p and q of n
e=33672547072112314656651078977148787005668204236154288223148815626059007708315462154289140
7162030790423211692379963273370145059200992517210899677208889596721492587768302082907406775
6110912750277556274894856992024073398501111967137609209092570984393233736351167072391531480
6640781644396735162746292658899859420246138670751835588650985207031680560591542870935789937
3166310924232217467357023395601602891438578401546606183621952433052088827196826817253037765
3458491396816736415139246740145333580031514409135514775701485044224801944672279822801515660
9962120613943039013210849637569654388305153504439978201168471788723176150214329983085377958
5406252436627624363492400088852883975091348423911985416178681616736573097288682432337517107
8990178116883319826203584143299258980741509659746823155276429831056252447515925626520430628
1524515515498724456290501761225019991422899602124139563304509943629472833402342322795625444
05695397775825379
Demo of Wiener’s attack on 3072-bit RSA
27. Demo of Wiener’s attack on 3072-bit RSA
27
n=4050466034733459117948661369434325329501188802313051997345799125891234107704117348688572
822968241411391800177594762808482973937169233965712197573759407392734191096652663994703778
952808040029976107403041978089894572558126157484274922936971271935059438540235485442033522
092410944219234207779892780919268194592096253954224338348267423588803262305615750524899259
796607361932191762514074928166865880230696299936972520520739540022565477986672563141114258
269557279572211776430985902539245167493288546882957309657110558098268120282864883116155719
803815050249704505568603787870037703947767759977126644993587530424319006304920470091243583
680312305500138543915371880345656171175075023154693592436116591754759271057759187350884602
775086233232067093185076992797538352183746429604112717459337441775189073177524297828889314
984378091792879642015536509598546944461962454223058326141921389049433966741634936638738508
201842511886022226673797379
28. 28
~/crypto/RSA$ java Wiener $e $n (see the appendix for my source code of the Wiener’s attack)
p =
228618440729133922990816041940544024411254691463731802726037903132795186854345875230343
654044166412558405675977782990484963324748226257412262122902828233729941228471749311968
399790142534647671306340701348934334260898412253278448278316632896937705607555399352684
706458581812862425260205834305480643470587101546901092595466757522747687824561819969284
561829559772085613979978513486752508222389549523546596961480318085783601795272943091840
1932482234913144647546614991
q =
177171448716704031987577302931779222186678664673478368605300427464268720262494125698859
962426628193403104930277887600599755628207550142303130738737393343096277028378245919680
117760376326032850295376851534102776382092998169222152534639205700861898804972459240748
229287718125809927279358209490702299200864677079073467424894343765992685226911198449967
931089921852796127980417434976198444816772746792600009481764698694983378925257717545526
4099338052320517481915293069
d =
412459503645760125670382234066174085751948620885038895431186224951397107023102122068048
933395723899697528350276391124783190263850629056596301464439280785998971874955881360082
582010127704062829997247759017710111179965432716582124299
Private keys derived from public keys
29. Algorithmic complexity of Wiener’s attack
29
Let n be a 3072-bit RSA modulus
For a random public key <n, e>, the number of continued fractions is only 1774
~/crypto/RSA$ java ContFract $e $n
Number of fractions = 1774
In other words, the number of continued fractions is ≤ log2
n
Computing the continued fractions and convergents took less than a second
real 0m0.355s
user 0m0.270s
sys 0m0.044s
30. Algorithmic complexity of Wiener’s attack
30
~/crypto/RSA$ time java Wiener $e $n
d =
412459503645760125670382234066174085751948620885038895431186224951397107023102122068048933395
723899697528350276391124783190263850629056596301464439280785998971874955881360082582010127704
062829997247759017710111179965432716582124299
real 0m7.448s
user 0m7.346s
sys 0m0.080s
Took less than 8 seconds to disclose the private key of a random 3072-bit RSA modulus n
(My implementation is not optimized at all)
31. Extending Wiener’s attack
31
● I was curious to extend Wiener’s attack and took a baby-step
● My question: Can we break RSA when d < n1/4
instead of d < ⅓ n1/4
?
● In other words, how tight is the upper bound for d in order to apply
Wiener-style attack?
● I generated several thousand random RSA keys of different sizes, and
measured the success rate
○ Success means derive the correct d from <n, e>
32. Experimental results - Extending Wiener’s attack
32
(keySize=512 and numKeys=100).
~/crypto/RSA$ time java Wiener_Experiment $keySize $numKeys
Num of success = 67
real 0m5.070s
user 0m4.975s
sys 0m0.084s
~/crypto/RSA$ time java Wiener_Experiment $keySize $numKeys
Num of success = 65
real 0m4.627s
user 0m4.531s
sys 0m0.080s
Conclusion: About 65% of the RSA keys were broken
36. 36
Summary of my extension of Wiener’s attack
● My experimental results show that Wiener’s upper bound of d is not tight
● We are able to break on average 60% of RSA keys when d < n1/4
● Time to break these keys only grows linearly on the size of n
● Based on this success, I thought I could further improve the bound, but failed
when d < n1/2
(open problem)
● Boneh and Durfee used Lattice Theory to break RSA when d < n0.292
37. Does Wiener’s attack and my extension affect us?
● Fortunately no, by default, private exponents d are the same size as of the
public modulus n
● In many standard RSA libraries, users don’t get to choose d at all
● However, users have to choose the public exponent e
● By default, most libraries have e = 65537 (NIST recommended value)
● But users can choose other values of e if they prefer to
● If we choose a very large e, then d will be short, leading to Wiener’s attack
37
38. A simple trick to replicate Wiener’s attack
● In late 80s, Wiener invented a classical attack on RSA when d < ⅓ n1/4
● However, by default, key pairs generated by libraries have a very large d
○ Meaning, we cannot replicate Wiener’s attack in the default settings of JDK, for example
● In order to replicate Wiener’s attack, I formulated a simple trick as follows:
○ Step 1: Generate RSA key pair using JDK, for example
○ Step 2: Discard e and d of the above key pair
○ Step 3: Generate a new d such that d < ⅓ n1/4
and gcd(d, φ(n)) = 1
○ Step 4: Generate a new e = d-1
mod φ(n)
● See the appendix for code details to generate keys for Wiener’s attack
38
39. Conclusion
● Continued Fractions are successfully used to approximate e/n to find secret d
● Wiener’s attack break RSA with 100% success rate when d < ⅓ n1/4
● My extension of this attack achieves on avg. 60% success rate when d < n1/4
● The attack is very fast, in seconds, we are able to factor n and find secrets
● Choosing a short secret exponent d to speed-up decryption is dangerous
● Equivalently, choosing a very large public exponent e can be dangerous
● Choosing a very short public exponent e is also dangerous (a future topic)
39
41. Code for Continued Fraction Computation
41
// Continued Fraction
public static BigInteger[] getCF(BigInteger numerator, BigInteger denominator)
{
List<BigInteger> result = _getCF(numerator, denominator);
return result.toArray(new BigInteger[result.size()]);
}
42. 42
// Continued Fraction
private static List<BigInteger> _getCF(BigInteger numerator, BigInteger denominator)
{
assert !denominator.equals(zero);
List<BigInteger> result = new ArrayList<BigInteger>();
// if numerator < denominator, swap them and recurse
if(numerator.compareTo(denominator) == -1) {
result.add(zero);
result.addAll(_getCF(denominator, numerator));
return result;
}
BigInteger quotient = numerator.divide(denominator);
BigInteger remainder = numerator.mod(denominator);
result.add(quotient);
if(!remainder.equals(zero)){
result.addAll(_getCF(denominator, remainder));
}
return result;
}
43. 43
/* http://www.maths.surrey.ac.uk/hosted-sites/R.Knott/Fibonacci/cfINTRO.html#section9.1 */
public static List<Fraction> _calculateConvergents(BigInteger[] cfTerms) {
int len = cfTerms.length;
List<Fraction> result = new ArrayList<Fraction>();
Fraction f = new Fraction();
f.numerator = one;
f.denominator = zero;
result.add(0, f);
Fraction f2 = new Fraction();
f2.numerator = cfTerms[0];
f2.denominator = one;
result.add(1,f2);
for(int i = 2; i <= cfTerms.length; i++) {
Fraction temp = new Fraction();
Fraction prevCf = result.get(i-1);
Fraction prevPrevCf = result.get(i-2);
temp.numerator = cfTerms[i-1].multiply(prevCf.numerator).add(prevPrevCf.numerator);
temp.denominator= cfTerms[i-1].multiply(prevCf.denominator).add(prevPrevCf.denominator);
result.add(i, temp);
}
result.remove(0);
return result;
}
44. 44
/* Generates e and d that satisfy Wiener's bound */
public static BigInteger[] generate_wiener_e_d(BigInteger n, BigInteger phi)
{
BigInteger[] result = new BigInteger[2];
// max value of D is ⅓ n1/4
BigInteger maxD = BigIntUtil.iRoot(n, 4).divide(three);
while(true) {
BigInteger d = BigInteger.probablePrime(maxD.bitLength(), new SecureRandom());
if(d.compareTo(maxD) < 0 && d.gcd(phi).equals(one)) {
BigInteger e = d.modInverse(phi);
result[0] = e;
result[1] = d;
break;
}
}
return result;
}
45. 45
// Returns the prime factors p and q
public static BigInteger[] runWiener(BigInteger e, BigInteger n) {
BigInteger[] result = null;
// Compute the continued fractions of e/n
BigInteger[] cfTerms = BigIntUtil.getCF(e, n);
int len = cfTerms.length;
// Compute the convergents of the continued fractions
Fraction[] convergents = BigIntUtil.calculateConvergents(cfTerms);
// We start from i = 1 because when i = 0, k is 0 which is not valid in RSA
for(int i = 1; i < cfTerms.length; i++) {
BigInteger test_k = convergents[i].numerator;
BigInteger test_d = convergents[i].denominator;
// Check whether we got the valid k and d
result = factorize(n, e, test_k, test_d);
if(result != null) break;
}
return result;
}
46. 46
private static BigInteger[] factorize(BigInteger n, BigInteger e, BigInteger k, BigInteger d
{
BigInteger[] result = null;
// is d odd?
if(BigIntUtil.isEven(d)) return result;
BigInteger phi = e.multiply(d).subtract(one).divide(k);
// is phi even?
if(!BigIntUtil.isEven(phi)) return result;
BigInteger a = one;
BigInteger b = n.subtract(phi).add(one).multiply(minusOne);
BigInteger c = n;
BigInteger delta = b.multiply(b).subtract(four.multiply(a.multiply(c)));
if(delta.compareTo(zero)< 0) return result;
// Do we have integer square root?
if(!BigIntUtil.hasIntSqrt(delta)) return result;
result = BigIntUtil.quadraticSol(a, b, c);
return result;
}
47. References
● W. Diffie and M. E. Hellman, “New Directions in Cryptography,” IEEE
Transactions on Information Theory, vol. IT-22, no. 6, November, 1976.
● R. L. Rivest, A. Shamir, and L. Adleman, “A method for obtaining digital
signatures and public-key cryptosystems,” CACM 21, 2, February, 1978.
● A. Menezes, P. van Oorschot, and S. Vanstone, “Handbook of Applied
Cryptography,” CRC Press, 1996.
● M. Wiener, “Cryptanalysis of short RSA secret exponents,” IEEE Transactions
on Information Theory, vol. 36, no. 3, pp. 553–558, 1990.
47