-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathRSA.py
More file actions
138 lines (119 loc) · 4.64 KB
/
Copy pathRSA.py
File metadata and controls
138 lines (119 loc) · 4.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
import random
import math
import time
def rabinMiller(n,t,kn):
assert t >= 1 and 0 <= kn <= 1
if n<=3:
if n>1:
return True
return False
elif n%2==0:
return False
RANDOM=random.SystemRandom()
r=n1=n-1
s=0
while (r%2)>0:
s+=1
r//=2
s1=s-1
for i in range(t):
if i==0 and kn==1:
a=2
else:
a=RANDOM.randint(2,n-2)
y=pow(a,r,n)
if y!=1 and y!=n1:
j=1
while j<=s1 and y!=n1:
y=(y*y)%n
if y==1:
return False
j+=1
if y!=n1:
return False
return True
def xgcd(b, n): #computes the gcd(b,n) using the extended euclidian algoritm
x0, x1, y0, y1 = 1, 0, 0, 1 #x0 and y0 are the last values of x and y, x1 and y1 are the current values of x and y
while n != 0: #after going through the loop, n is the remainder of b/n
q, b, n = b // n, n, b % n #q equals the integer part of b/n, b is set equal to n, and n is equal to b%n
x0, x1 = x1, x0 - q * x1 #store the current x val in x0, then set the current x val to the last x value minus q times the current x val
y0, y1 = y1, y0 - q * y1 #same thing as above, but for y; Start next loop with n as the new b and the remainder of b/n as the new n
return b, x0, y0 #return coefficents of bx + ny = gcd(b,n) and returns gcd(b, n)
def mulinv(b, n): #computes the multiplicative inverse of a number mod n
g, x, _ = xgcd(b, n)
if g == 1:
return x % n
def gen_primes(lower,upper): #generates two random primes in a range from lower to upper
candidate1 = random.randint(lower,upper)
candidate2 = random.randint(lower,upper)
#if it is not prime, regenerate it until it is
while not rabinMiller(candidate1,5,0) or not rabinMiller(candidate2,5,0) or candidate1 == candidate2:
if not rabinMiller(candidate1,5,0) or candidate1 == candidate2:
candidate1 = random.randint(lower,upper)
elif not rabinMiller(candidate2,5,0) or candidate1 == candidate2:
candidate2 = random.randint(lower,upper)
return candidate1, candidate2
def gen_rsa_primes(lower,upper,e):
p,q = gen_primes(lower,upper)
while not is_coprime(e,totient(p,q)):
p,q = gen_primes(lower,upper)
return p,q
def is_coprime(p,q):
return p%q != 0 and q%p != 0
def totient(p,q): #computes the totient of the product of the two prime inputs, the totient is the number of numbers coprime to that product
assert rabinMiller(p,5,0) and rabinMiller(q,5,0), "inputs must be prime"
return (p-1)*(q-1)
def gen_keys(p,q,e): #generates public and private keypairs
tot = totient(p,q)
n = p*q
assert e > 1 and e < tot, "public key is not within correct domain"
assert is_coprime(e,tot), "public key and totient are not coprime"
d = mulinv(e,tot)
return (e,n),(d,n)
#message input must be number (convert text to ascii numbers)
#public key input is a tuple of (public exponent, n)
def encrypt(public_key,message):
if type(message) == str:
ciphertext = []
for char in message:
ciphertext.append(encrypt(public_key,ord(char)))
else:
assert message > 1 and message < public_key[1],"seed is too small"
ciphertext = pow(message,public_key[0],public_key[1])
return ciphertext
#same format as encrypt
def decrypt(private_key,ciphertext):
if type(ciphertext) == list:
plaintext = []
for char in ciphertext:
plaintext.append(chr(decrypt(private_key,char)))
plaintext = "".join(plaintext)
else:
plaintext = pow(ciphertext,private_key[0],private_key[1])
return plaintext
#some brief tests to make sure it is working
t1,t2 = gen_rsa_primes(1,100,3)
assert rabinMiller(13,5,0),"is_prime did't correctly check if it was a prime"
assert rabinMiller(t1,5,0) and rabinMiller(t2,5,0), "gen_rsa_primes didn't generate a pair of primes"
assert is_coprime(totient(t1,t2),3), "gen_rsa_primes did not generate coprime primes"
assert totient(11,13) == 120, "totient is broken somehow"
assert is_coprime(12,13), "is_coprime does not correctly check for coprimes"
message = "abcdefghijklmnopqrstuvwxyz"
#message = 123
e = 2
start = time.clock()
p,q = gen_rsa_primes(pow(2,1024),pow(2,1025),e)
finish = time.clock() - start
public,private = gen_keys(p,q,e)
#public = (7,2534665157)
#private = (1810402843,2534665157)
#p,q = gen_rsa_primes(10000,15000,e)
#public,private = gen_keys(p,q,e)
print(public)
print(private)
print(message)
cipher = encrypt(public,message)
print(cipher)
plain = decrypt(private,cipher)
print(plain)
print(finish)