-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrsa.py
153 lines (118 loc) · 3.74 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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
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
'''
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 multiplicative_inverse(e, phi):
g, x, y = egcd(e, phi)
if g != 1:
raise Exception('modular inverse does not exist')
else:
return x % 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(pow(num, 0.5)) + 2, 2):
if num % n == 0:
return False
return True
def generate_keypair(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 co-prime
e = random.randrange(1, phi)
# Use Euclid's Algorithm to verify that e and phi(n) are co-prime
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
plain = [chr(pow(char, key) % n) for char in ciphertext]
# Return the array of bytes as a string
return ''.join(plain)
def s2l(msg):
msg = msg.strip("[")
msg = msg.strip("]")
msg = msg.split(", ")
lm = len(msg)
lstm = [0] * lm
for i in range(0, lm):
lstm[i] = int(msg[i])
return lstm
if __name__ == '__main__':
'''
Detect if the script is being run directly by the user
'''
print("RSA Encrypter/ Decrypter")
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_keypair(p, q)
print("Your public key is ", public, " and your private key is ", private)
message = input("Enter a message to encrypt with your private key: ")
encrypted_msg = encrypt(private, message)
print("Your encrypted message is: ")
print(''.join(map(lambda x: str(x), encrypted_msg)))
print("Decrypting message with public key ", public, " . . .")
print("Your message is:")
print(decrypt(public, encrypted_msg))