-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy pathrsa.py
135 lines (99 loc) · 3.59 KB
/
rsa.py
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
import random
'''
Euclid's algorithm for determining the greatest common divisor
Use iteration to make it faster for larger integers
'''
def gcd(a, b):
while b != 0:
a, b = b, a % b
return a
'''
Euclid's extended algorithm for finding the multiplicative inverse of two numbers
'''
def multiplicative_inverse(e, phi):
d = 0
x1 = 0
x2 = 1
y1 = 1
temp_phi = phi
while e > 0:
temp1 = temp_phi//e
temp2 = temp_phi - temp1 * e
temp_phi = e
e = temp2
x = x2 - temp1 * x1
y = d - temp1 * y1
x2 = x1
x1 = x
d = y1
y1 = y
if temp_phi == 1:
return d + phi
'''
Tests to see if a number is prime.
'''
def is_prime(num):
if num == 2:
return True
if num < 2 or num % 2 == 0:
return False
for n in range(3, int(num**0.5)+2, 2):
if num % n == 0:
return False
return True
def generate_key_pair(p, q):
if not (is_prime(p) and is_prime(q)):
raise ValueError('Both numbers must be prime.')
elif p == q:
raise ValueError('p and q cannot be equal')
# n = pq
n = p * q
# Phi is the totient of n
phi = (p-1) * (q-1)
# Choose an integer e such that e and phi(n) are coprime
e = random.randrange(1, phi)
# Use Euclid's Algorithm to verify that e and phi(n) are coprime
g = gcd(e, phi)
while g != 1:
e = random.randrange(1, phi)
g = gcd(e, phi)
# Use Extended Euclid's Algorithm to generate the private key
d = multiplicative_inverse(e, phi)
# Return public and private key_pair
# Public key is (e, n) and private key is (d, n)
return ((e, n), (d, n))
def encrypt(pk, plaintext):
# Unpack the key into it's components
key, n = pk
# Convert each letter in the plaintext to numbers based on the character using a^b mod m
cipher = [pow(ord(char), key, n) for char in plaintext]
# Return the array of bytes
return cipher
def decrypt(pk, ciphertext):
# Unpack the key into its components
key, n = pk
# Generate the plaintext based on the ciphertext and key using a^b mod m
aux = [str(pow(char, key, n)) for char in ciphertext]
# Return the array of bytes as a string
plain = [chr(int(char2)) for char2 in aux]
return ''.join(plain)
if __name__ == '__main__':
'''
Detect if the script is being run directly by the user
'''
print("===========================================================================================================")
print("================================== RSA Encryptor / Decrypter ==============================================")
print(" ")
p = int(input(" - Enter a prime number (17, 19, 23, etc): "))
q = int(input(" - Enter another prime number (Not one you entered above): "))
print(" - Generating your public / private key-pairs now . . .")
public, private = generate_key_pair(p, q)
print(" - Your public key is ", public, " and your private key is ", private)
message = input(" - Enter a message to encrypt with your public key: ")
encrypted_msg = encrypt(public, message)
print(" - Your encrypted message is: ", ''.join(map(lambda x: str(x), encrypted_msg)))
print(" - Decrypting message with private key ", private, " . . .")
print(" - Your message is: ", decrypt(private, encrypted_msg))
print(" ")
print("============================================ END ==========================================================")
print("===========================================================================================================")