-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path07_rsa_key_gen.py
139 lines (104 loc) · 3.54 KB
/
07_rsa_key_gen.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
rsa = __import__("06_rsa")
def doMillerRabin(n : int) -> bool:
"""
Does one iteration of the miller rabin test.
Args:
n (int): The value that will be checked against.
Returns:
bool: Returns whether this iteration of the test thinks that n is prime. If false is returned, n is defenitely not prime. If true, it might still be compound.
"""
# discard even inputs
if n % 2 == 0:
return False
# calculate m and k
m = n - 1
k = 0
while m & 1 == 0 and m > 1:
k += 1
m >>= 1
# choose a
a = random.randrange(1, n)
b = rsa.powWithMod(a, m, n)
if b == 1:
return True
# check all powers
for _ in range(k):
if b == n-1:
return True
else:
b = (b * b) % n
return False
def checkPrime(n : int, numTries : int = 15) -> bool:
"""
Checks whether n is prime by performing miller rabin multiple times.
A return value of false is always coorect while a true might be falsed (although that is really unlikely)
Args:
n (int): The value that will be checked against its primness.
numTries (int, optional): How many times should miller rabin be executed. Defaults to 15.
Returns:
bool: _description_
"""
for _ in range(numTries):
if not doMillerRabin(n):
return False
return True
def getNextPrime(start : int) -> int:
"""
Returns the next prime after start. Start has to be divisible by 30.
Args:
start (int): The value where the searching starts. It has to be divisible by 30.
Raises:
ValueError: When start is not divisible by 30.
Returns:
int: The next prime number after start
"""
if start % 30 != 0:
raise ValueError("Start has to be divisble by 30")
offsets = [1, 7, 11, 13, 17, 19, 23, 29]
for offset in offsets:
if checkPrime(start + offset):
return start + offset
return getNextPrime(start + 30)
def genKey() -> tuple[tuple[int]]:
"""
Generates a RSA key pair.
Returns:
tuple[tuple[int]]: Returns tuple of public and private keys.
"""
# generate p
z = random.randrange(10**100, 10**101)
p = getNextPrime(30 * z)
# generate q
z = random.randrange(10**100, 10**101)
q = getNextPrime(30 * z)
# generate d (For a prime d > max{p, q} we get gcd(d, phi(n)) = 1)
d = getNextPrime(30 * (max(p, q) // 30 + 1))
e = rsa.mudularInverse(d, (p-1)*(q-1))
n = p * q
return ((e, n), (d, n))
def findFactors(n : int) -> tuple[int]:
"""
Tries to find the factors of a number assuming they are close by. If they are not, the search will take forever.
The used method is the difference of squares:
Assume: n = (u-d)*(u+d) = u² - d² <=> d² = u² - n
=> If we find a u such that u² - n is a perfect square, we found our p = u-d, q = u+d such that n = p*q
Args:
n (int): The number that shoule factored
Returns:
tuple[int]: The factors of n.
"""
isSquare = lambda x : int(x**0.5)**2 == x
u = int(n**0.5) + 1
while not isSquare(u**2-n):
u += 1
w = int((u**2-n)**0.5)
return (u+w, u-w)
if __name__ == "__main__":
(encryptKey, decryptKey) = genKey()
cryptotext = rsa.rsa([12, 42, 1, 0, 76, 30], encryptKey)
print(cryptotext)
print(rsa.rsa(cryptotext, decryptKey))
print(findFactors(9854989 * 9857213))
print(findFactors(9999749 * 3005293))
# print(findFactors(5000000037041 * 10000000058171))