## Factoring RSA Moduli

### March 24, 2014

We studied RSA encryption in a previous exercise. To recap: select two prime numbers p and q and make their product n = p q the modulus of the crypto system. Choose an encryption key e and a decryption key d such that d e ≡ 1 (mod φ(p q)), where the totient φ(p q) = (p − 1) × (q − 1). Then encrypt a message m as c = me (mod n) and decrypt the cipher test c as m = cd.

In our implementation we chose p and q randomly and kept them secret, even from the user who knows the decryption key. Of course, it is hard for someone who knows who does not know d to factor n and thus compute d; that is the basis of the encryption. But it is fairly easy to recover p and q if you know n, e and d, as Boneh showed (page 205, left column, Fact 1):

1. [Initialize] Set k d e − 1.
2. [Try a random g] Choose g at random from {2, …, n − 1} and set tk.
3. [Next t] If t is divisible by 2, set tt / 2 and xg t (mod n). Otherwise go to Step 2.
4. [Finished?] If x > 1 and y = gcd(x −1, n) > 1 then set py and q &larrow; n / y, output p and q and terminate the algorithm. Otherwise go to Step 3.

For instance, given n = 25777, e = 3 and d = 16971, we calculate p = 149 and q = 173 when g = 5, noting that 149 × 173 = 25777; on average, it takes no more than two different g to complete the algorithm. Knowledge of p and q, though not necessary, is useful, because a more efficient decryption is possible using p, q and the Chinese remainder theorem, which does arithmetic with numbers the size of p and q instead of the size of their product.

Your task is to write a program that factors RSA moduli. When you are finished, you are welcome to read or run a suggested solution, or to post your own solution or discuss the exercise in the comments below.

Pages: 1 2

### 3 Responses to “Factoring RSA Moduli”

1. David said

In Erlang; gcd and powmod are defined in the module.

```-module(ex1).
-export([rsa_factors/3]).

gcd(A, 0) -> A;
gcd(A, B) -> gcd(B, A rem B).

powmod(_, 0, _) -> 1;
powmod(A, N, M) ->
case N band 1 of
0 -> X = powmod(A, N bsr 1, M), X*X rem M;
1 -> A*powmod(A, N-1, M) rem M
end.

try_random(N) -> random:uniform(N-2) + 1.

rsa_factors(N, E, D) ->
K = E*D - 1,
rsa_factors(N, E, D, K, K, try_random(N)).

rsa_factors(N, E, D, K, T, G) ->
if
T band 1 =:= 1 -> rsa_factors(N, E, D, K, K, try_random(N));
true ->
T2 = T bsr 1,
X = powmod(G, T2, N),
Y = gcd(X-1, N),
if
(X > 1) and (Y > 1) -> {Y, N div Y};
true -> rsa_factors(N, E, D, K, T2, G)
end
end.

9> ex1:rsa_factors(25777, 3, 16971).
{173,149}
10>
```
2. matthew said

Ok, here’s some Python: I’ve rearranged the algorithm a little to hopefully be more efficient – find the smallest possible value of x by repeated halving, then we only need one call to pow per value of g, the rest can be got by squaring. Also I’ve checked that we don’t have a trivial root of unity (and if we do, we can bail out early):

```#!/usr/bin/python
from random import randrange

def gcd (a,b):
while b != 0: a,b = b,a%b
return a

def factor(n,d,e):
k = d*e-1
while True:
g = randrange(2,n)
t = k
while t%2 == 0: t = t//2
x = pow(g,t,n)
while t < k and x != 1 and x != n-1:
if x*x%n==1:
a = gcd(x-1,n)
b = n//a
if a>b: return (b,a)
else: return (a,b)
x = x*x%n
t = t*2

def test(n,d,e):
(a,b) = factor(n,d,e)
print(n,d,e,a,b)
assert(a != 1)
assert(b != 1)
assert(a*b == n)

test(25777,3,16971)
test(0xa66791dc6988168de7ab77419bb7fb0c001c62710270075142942e19a8d8c51d053b3e3782a1de5dc5af4ebe99468170114a1dfe67cdc9a9af55d655620bbab,
0x10001,