Created
August 13, 2017 21:28
-
-
Save alecdoconnor/faddeb2db1a2840a74820b6f23bb0828 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from Crypto.PublicKey import RSA | |
# pem = open('private.pem','r').read() | |
# key = RSA.importKey(pem) | |
# cyphertext = open('message.bin','r').read() | |
# print key.decrypt(cyphertext) | |
def gcd(a,b): | |
if b > a: | |
temp = b | |
b = a | |
a = temp | |
if b == 0: | |
#success | |
return a | |
if b == 1: | |
return 1 | |
return gcd(a%b, b) | |
def egcd(a, b): | |
if a == 0: | |
return (b, 0, 1) | |
else: | |
g, y, x = egcd(b % a, a) | |
return (g, x - (b // a) * y, y) | |
def modinv(a, m): | |
gcd, x, y = egcd(a, m) | |
if gcd != 1: | |
return None # modular inverse does not exist | |
else: | |
return x % m | |
for i in range(1,101): | |
pem = open('../%d.pem' % i,'r').read() | |
cyphertext = open('../%d.bin' % i,'r').read() | |
n = long(RSA.importKey(pem).n) | |
e = long(RSA.importKey(pem).e) | |
for j in range(1,101): | |
if i == j: | |
continue | |
pem2 = open('../%d.pem' % j,'r').read() | |
n2 = long(RSA.importKey(pem2).n) | |
modulus = gcd(n,n2) | |
if modulus != 1: | |
p = long(modulus) | |
q = long(n/modulus) | |
phi = (p-1)*(q-1) | |
d = modinv(e, phi) #(1/e)%phi | |
pem3 = RSA.construct((n,e,d)) | |
print pem3.decrypt(cyphertext) | |
There are not as many weak RSA keys available as the bug that was causing a faulty number generator on some systems has long since been patched. But it was only a few years ago that many keypairs across the Internet were vulnerable to this simple script.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Code to solve puzzle on:
http://www.loyalty.org/~schoen/rsa/
The concept is that not all random number generators are truly random.
The first step of generating a RSA keypair is to generate two prime numbers (p and q). If the random number generator fails and reuses the same primes, then the public key can be compared to other keys to determine the two prime numbers, and therefore, recreate the private key.
It works like this:
Imagine we have 100 keypairs, some of which happen to share a prime number. The public key reveals the
n
value (p * q
). If we compare then
values from different public keys, we can use the greatest common denominator to determine if there is a shared prime number. If we determine that they share a common prime number through GCD, then the other prime number (for each keypair) can be determined by dividingn
by the first prime number.For example:
n
values may be 55 and 77 (then
value will be a much larger number in reality)77/11 = 5
and55/11 = 7
The greatest common denominator is relatively easy for a computer to determine. Through iteration of the GCD function, we can continue to use the modulus to determine the next number to test. Refer to my code below:
a
is the larger number.b
) is zero or one. If so, we are finished and have determined the gcd. Ifb == 0
thena
is the GCD. Ifb == 1
then the GCD is equal to one and we can continue on to the nextn
to compute.a
can be replaced witha%b
. I will not go into the mathematical proof for this here.Using the same numbers as before:
gdc(77, 55)
Iteration 1:
77%55 = 22
=> computegcd(22, 55)
Iteration 2:
55%22 = 11
=> computegcd(11, 22)
Iteration 4:
22%11 = 0
=> 11 IS A PRIMESince 11 is a known prime, we can compute the other two primes:
77/11 = 7
,55/11 = 5