forked from TheAlgorithms/Python
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrsa_algo.py
139 lines (119 loc) · 3.79 KB
/
rsa_algo.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
import random
import sys
from sympy import isprime, mod_inverse
from typing import Tuple, List
def generate_prime_candidate(length: int) -> int:
"""
Generate a large prime number candidate.
>>> p = generate_prime_candidate(16)
>>> isprime(p)
True
"""
p = random.getrandbits(length)
while not isprime(p):
p = random.getrandbits(length)
return p
def generate_keys(keysize: int) -> Tuple[Tuple[int, int], Tuple[int, int]]:
"""
Generate RSA keys.
>>> public, private = generate_keys(16)
>>> len(bin(public)) - 2 # Check bit length of n
32
>>> len(bin(private)) - 2 # Check bit length of n
32
"""
try:
e = d = n = 0
p = generate_prime_candidate(keysize)
q = generate_prime_candidate(keysize)
n = p * q
phi = (p - 1) * (q - 1)
e = random.randrange(1, phi)
g = gcd(e, phi)
while g != 1:
e = random.randrange(1, phi)
g = gcd(e, phi)
d = mod_inverse(e, phi)
return ((e, n), (d, n))
except ValueError as ex:
print(f"Value error generating keys: {ex}", file=sys.stderr)
sys.exit(1)
except TypeError as ex:
print(f"Type error generating keys: {ex}", file=sys.stderr)
sys.exit(1)
except Exception as ex:
print(f"Unexpected error generating keys: {ex}", file=sys.stderr)
sys.exit(1)
def gcd(a: int, b: int) -> int:
"""
Compute the greatest common divisor of a and b.
>>> gcd(48, 18)
6
"""
while b != 0:
a, b = b, a % b
return a
def encrypt(pk: Tuple[int, int], plaintext: str) -> List[int]:
"""
Encrypt a message with a public key.
>>> public, private = generate_keys(16)
>>> encrypted = encrypt(public, "test")
>>> isinstance(encrypted, list)
True
"""
try:
key, n = pk
cipher = [(ord(char) ** key) % n for char in plaintext]
return cipher
except TypeError as ex:
print(f"Type error during encryption: {ex}", file=sys.stderr)
return None
except Exception as ex:
print(f"Unexpected error during encryption: {ex}", file=sys.stderr)
return None
def decrypt(pk: Tuple[int, int], ciphertext: List[int]) -> str:
"""
Decrypt a message with a private key.
>>> public, private = generate_keys(16)
>>> encrypted = encrypt(public, "test")
>>> decrypted = decrypt(private, encrypted)
>>> decrypted == "test"
True
"""
try:
key, n = pk
plain = [chr((char ** key) % n) for char in ciphertext]
return ''.join(plain)
except TypeError as ex:
print(f"Type error during decryption: {ex}", file=sys.stderr)
return None
except Exception as ex:
print(f"Unexpected error during decryption: {ex}", file=sys.stderr)
return None
if __name__ == '__main__':
import doctest
doctest.testmod()
try:
keysize = 1024
public, private = generate_keys(keysize)
message = "Hello, RSA!"
print("Original message:", message)
encrypted_msg = encrypt(public, message)
if encrypted_msg:
print("Encrypted message:", encrypted_msg)
decrypted_msg = decrypt(private, encrypted_msg)
if decrypted_msg:
print("Decrypted message:", decrypted_msg)
else:
print("Decryption failed.", file=sys.stderr)
else:
print("Encryption failed.", file=sys.stderr)
except ValueError as ex:
print(f"Value error: {ex}", file=sys.stderr)
sys.exit(1)
except TypeError as ex:
print(f"Type error: {ex}", file=sys.stderr)
sys.exit(1)
except Exception as ex:
print(f"Unexpected error: {ex}", file=sys.stderr)
sys.exit(1)