Factoring Multiple RSA Keys
March 20, 2012
We gave a list of keys in the exercise, but if you want to create your own list of keys, here’s a method to do so; we choose p from a list of primes, then for each q in a second list of similar-sized primes pair the q with a randomly-chosen p and output the product p · q:
(define keys
(let ((ps (primes 12345 12543)))
(list-of (* (fortune ps) q)
(q in (primes 56789 56987)))))
Note that some p are unused, some are used only once, and some are used multiple times; it is the ones that are used multiple times that we will be able to discover. We used list comprehensions and the fortune
function from the Standard Prelude and a segmented Sieve of Eratosthenes from a previous exercise. Your set of keys will differ from ours if your random-number generator is seeded differently.
The quadratic method uses a list comprehension to form the cross-product of all pairs of keys, then computes the gcd and reports those that are greater than 1. We use unique
and sort
from the Standard Prelude to make the list pretty, but that may not be necessary, depending on your objective:
> (unique equal?
(sort (lambda (a b) (< (car a) (car b)))
(list-of (list k1 d (/ k1 d))
(k1 in keys)
(k2 in keys)
(d is (gcd k1 k2))
(< 1 d k1))))
((704030867 12379 56873) (704387447 12377 56911)
(704488409 12401 56809) (704996429 12379 56951)
(705031051 12377 56963) (705674273 12421 56813)
(706323757 12401 56957) (707015741 12421 56921)
(707478271 12451 56821) (708093251 12457 56843)
(708374743 12451 56893) (708691187 12457 56891))
The linear method first computes the product of the keys, then uses a list comprehension to manage the computation:
> (unique equal?
(sort (lambda (a b) (< (car a) (car b)))
(let ((k-prod (apply * keys)))
(list-of (list k d (/ k d))
(k in keys)
(x is (/ (modulo k-prod (* k k)) k))
(integer? x)
(d is (gcd k x))
(< 1 d k))))))
((704030867 12379 56873) (704387447 12377 56911)
(704488409 12401 56809) (704996429 12379 56951)
(705031051 12377 56963) (705674273 12421 56813)
(706323757 12401 56957) (707015741 12421 56921)
(707478271 12451 56821) (708093251 12457 56843)
(708374743 12451 56893) (708691187 12457 56891))
You can run the program at http://programmingpraxis.codepad.org/5Frj9HCf.
I’m glad to see you reference Nadia’s work. I know she was worried when the first NY Times article came out that her work would be lost in the shuffle.
Continuing my exercises in J, here’s what i have:
I’m sorry but I couldn’t get the idea of the second algorithm. All gathered public key are: Pi(p,qi)=p*qi where 1 <= i <= 21.
Then we follow next steps:
1. Compute kij=Pi*Pj where i,j is between [1,21].
2. gcd with the next arguments:
a. Pi where 1 is between [1,21]
b. kprod = kij. What means (mod k 2)
Second question, why it solves the problem? Why its outcome gives us p and q?
Thanks for your time.
Best regards
Diego
My Python solution:
import itertools
keys = ”’
708894553 704488409 705674273
707478271 710167019 708093251
702013379 704030867 708691187
708374743 712748719 713581951
704387447 707015741 704308279
710872423 707947453 704996429
706323757 705031051 714623803
”’
keys = [int(i) for i in keys.strip().split()]
# uses algorithm from paxis problem: three binary algorithms
def gcd(a, b):
if a == 0: return b
if b == 0: return a
if a % 2 == 0 and b % 2 == 0:
return gcd(a >> 1, b >> 1) <> 1, b)
if b % 2 == 0: return gcd(a, b >> 1)
if a > b: return gcd(a-b, b)
else: return gcd(a, b-a)
def algo1(keys):
result = set()
for x,y in itertools.combinations(keys, 2):
g = gcd(x,y)
if g > 1:
result.add(g)
return list(result)
def algo2(keys):
prod = reduce(lambda x,y: x*y, keys)
result = set()
for key in keys:
g = gcd(key, (prod % key**2)/key)
if g > 1:
result.add(g)
return [int(x) for x in result]
print algo1(keys)
print algo2(keys)
Johann: If you know Nadia, please point out this blog entry to her.
Diego: You’re making it too complicated. Let’s say the keys are K_1 through K_21. Multiply them together to produce K_prod. Then for each K_i, reduce K_prod modulo K_i squared, divide by K_i, and take the gcd with K_i; if the gcd is greater than 1, you’ve found a factor.
PHP CLI :
output:
right?
[…] public keys are insecure. A couple days ago I noticed that the excellent Programming Praxis has a challenge based on that research and subsequent reporting in the press. This is excellent because it exposes […]
I managed to do it eventually, this has to be one of the most interesting exercises I’ve completed on here, along with the spigot algorithm for pi and the Mark V. Shaney exercise.