Skip to content

Commit

Permalink
added project files
Browse files Browse the repository at this point in the history
  • Loading branch information
pablocelayes committed Feb 19, 2014
1 parent dcc38b4 commit 3d65e39
Show file tree
Hide file tree
Showing 6 changed files with 426 additions and 0 deletions.
111 changes: 111 additions & 0 deletions Arithmetic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
'''
Created on Dec 22, 2011
@author: pablocelayes
'''

def egcd(a,b):
'''
Extended Euclidean Algorithm
returns x, y, gcd(a,b) such that ax + by = gcd(a,b)
'''
u, u1 = 1, 0
v, v1 = 0, 1
while b:
q = a // b
u, u1 = u1, u - q * u1
v, v1 = v1, v - q * v1
a, b = b, a - q * b
return u, v, a

def gcd(a,b):
'''
2.8 times faster than egcd(a,b)[2]
'''
a,b=(b,a) if a<b else (a,b)
while b:
a,b=b,a%b
return a

def modInverse(e,n):
'''
d such that de = 1 (mod n)
e must be coprime to n
this is assumed to be true
'''
return egcd(e,n)[0]%n

def totient(p,q):
'''
Calculates the totient of pq
'''
return (p-1)*(q-1)

def bitlength(x):
'''
Calculates the bitlength of x
'''
assert x >= 0
n = 0
while x > 0:
n = n+1
x = x>>1
return n


def isqrt(n):
'''
Calculates the integer square root
for arbitrary large nonnegative integers
'''
if n < 0:
raise ValueError('square root not defined for negative numbers')

if n == 0:
return 0
a, b = divmod(bitlength(n), 2)
x = 2**(a+b)
while True:
y = (x + n//x)//2
if y >= x:
return x
x = y


def is_perfect_square(n):
'''
If n is a perfect square it returns sqrt(n),
otherwise returns -1
'''
h = n & 0xF; #last hexadecimal "digit"

if h > 9:
return -1 # return immediately in 6 cases out of 16.

# Take advantage of Boolean short-circuit evaluation
if ( h != 2 and h != 3 and h != 5 and h != 6 and h != 7 and h != 8 ):
# take square root if you must
t = isqrt(n)
if t*t == n:
return t
else:
return -1

return -1

#TEST functions

def test_is_perfect_square():
print("Testing is_perfect_square")
testsuit = [4, 0, 15, 25, 18, 901, 1000, 1024]

for n in testsuit:
print("Is ", n, " a perfect square?")
if is_perfect_square(n)!= -1:
print("Yes!")
else:
print("Nope")

if __name__ == "__main__":
test_is_perfect_square()
66 changes: 66 additions & 0 deletions ContinuedFractions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
'''
Created on Dec 14, 2011
@author: pablocelayes
'''

def rational_to_contfrac (x, y):
'''
Converts a rational x/y fraction into
a list of partial quotients [a0, ..., an]
'''
a = x//y
if a * y == x:
return [a]
else:
pquotients = rational_to_contfrac(y, x - a * y)
pquotients.insert(0, a)
return pquotients

#TODO: efficient method that calculates convergents on-the-go, without doing partial quotients first
def convergents_from_contfrac(frac):
'''
computes the list of convergents
using the list of partial quotients
'''
convs = [];
for i in range(len(frac)):
convs.append(contfrac_to_rational(frac[0:i]))
return convs

def contfrac_to_rational (frac):
'''Converts a finite continued fraction [a0, ..., an]
to an x/y rational.
'''
if len(frac) == 0:
return (0,1)
elif len(frac) == 1:
return (frac[0], 1)
else:
remainder = frac[1:len(frac)]
(num, denom) = contfrac_to_rational(remainder)
# fraction is now frac[0] + 1/(num/denom), which is
# frac[0] + denom/num.
return (frac[0] * num + denom, num)

def test1():
'''
Verify that the basic continued-fraction manipulation stuff works.
'''
testnums = [(1, 1), (1, 2), (5, 15), (27, 73), (73, 27)]
for r in testnums:
(num, denom) = r
print('rational number:')
print(r)

contfrac = rational_to_contfrac (num, denom)
print('continued fraction:')
print(contfrac)

print('convergents:')
print(convergents_from_contfrac(contfrac))
print('***********************************')

if __name__ == "__main__":
test1()
91 changes: 91 additions & 0 deletions MillerRabin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import random, sys

def miller_rabin_pass(a, s, d, n):
'''
n is an odd number with
n-1 = (2^s)d, and d odd
and a is the base: 1 < a < n-1
returns True iff n passes the MillerRabinTest for a
'''
a_to_power = pow(a, d, n)
i=0
#Invariant: a_to_power = a^(d*2^i) mod n

# we test whether (a^d) = 1 mod n
if a_to_power == 1:
return True

# we test whether a^(d*2^i) = n-1 mod n
# for 0<=i<=s-1
while(i < s-1):
if a_to_power == n - 1:
return True
a_to_power = (a_to_power * a_to_power) % n
i+=1

# we reach here if the test failed until i=s-2
return a_to_power == n - 1

def miller_rabin(n):
'''
Applies the MillerRabin Test to n (odd)
returns True iff n passes the MillerRabinTest for
K random bases
'''
#Compute s and d such that n-1 = (2^s)d, with d odd
d = n-1
s = 0
while d%2 == 0:
d >>= 1
s+=1

#Applies the test K times
#The probability of a false positive is less than (1/4)^K
K = 20

i=1
while(i<=K):
# 1 < a < n-1
a = random.randrange(2,n-1)
if not miller_rabin_pass(a, s, d, n):
return False
i += 1

return True

def gen_prime(nbits):
'''
Generates a prime of b bits using the
miller_rabin_test
'''
while True:
p = random.getrandbits(nbits)
#force p to have nbits and be odd
p |= 2**nbits | 1
if miller_rabin(p):
return p
break

def gen_prime_range(start, stop):
'''
Generates a prime within the given range
using the miller_rabin_test
'''
while True:
p = random.randrange(start,stop-1)
p |= 1
if miller_rabin(p):
return p
break

if __name__ == "__main__":
if sys.argv[1] == "test":
n = sys.argv[2]
print (miller_rabin(n) and "PRIME" or "COMPOSITE")
elif sys.argv[1] == "genprime":
nbits = int(sys.argv[2])
print(gen_prime(nbits))


Binary file added RSAfracCont.pdf
Binary file not shown.
94 changes: 94 additions & 0 deletions RSAvulnerableKeyGenerator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
'''
Created on Dec 14, 2011
@author: pablocelayes
'''

#!/usr/bin/python
# -*- coding: utf-8 -*-
"""\
This module generates RSA-keys which are vulnerable to
the Wiener continued fraction attack
(see RSAfracCont.pdf)
The RSA keys are obtained as follows:
1. Choose two prime numbers p and q
2. Compute n=pq
3. Compute phi(n)=(p-1)(q-1)
4. Choose e coprime to phi(n) such that gcd(e,n)=1
5. Compute d = e^(-1) mod (phi(n))
6. e is the publickey; n is also made public (determines the block size); d is the privatekey
Encryption is as follows:
1. Size of data to be encrypted must be less than n
2. ciphertext=pow(plaintext,publickey,n)
Decryption is as follows:
1. Size of data to be decrypted must be less than n
2. plaintext=pow(ciphertext,privatekey,n)
-------------------------------
RSA-keys are Wiener-vulnerable if d < (n^(1/4))/sqrt(6)
"""

import random, MillerRabin, Arithmetic

def getPrimePair(bits=512):
'''
genera un par de primos p , q con
p de nbits y
p < q < 2p
'''

assert bits%4==0

p = MillerRabin.gen_prime(bits)
q = MillerRabin.gen_prime_range(p+1, 2*p)

return p,q

def generateKeys(nbits=1024):
'''
Generates a key pair
public = (e,n)
private = d
such that
n is nbits long
(e,n) is vulnerable to the Wiener Continued Fraction Attack
'''
# nbits >= 1024 is recommended
assert nbits%4==0

p,q = getPrimePair(nbits//2)
n = p*q
phi = Arithmetic.totient(p, q)

# generate a d such that:
# (d,n) = 1
# 36d^4 < n
good_d = False
while not good_d:
d = random.getrandbits(nbits//4)
if (Arithmetic.gcd(d,phi) == 1 and 36*pow(d,4) < n):
good_d = True

e = Arithmetic.modInverse(d,phi)
return e,n,d

if __name__ == "__main__":
print("hey")
for i in range(5):
e,n,d = generateKeys()
print ("Clave Publica:")
print("e =")
print(e)
print("n =")
print(n)
print ("Clave Privada:")
print("d =")
print(d)
print("-----------------------")
Loading

0 comments on commit 3d65e39

Please sign in to comment.