-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathP1_RSA_Elia.py
241 lines (197 loc) · 6.49 KB
/
P1_RSA_Elia.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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# Algorithms Project 1 - RSA
# Objective: implement RSA Encryption and apply it to digital signature
import pandas as pd
import sys
import random
import math
import csv
import hashlib
def multiply(a, b):
"""
Multiply two numbers using recursive multiplication algorithm.
Args:
a (int): The first number.
b (int): The second number.
Returns:
int: The product of a and b.
"""
if (a==0 or b==0):
return 0
elif (b==1):
return a
elif (a==1):
return b
elif (b%2==0): # if b is even
return 2 * multiply(a, b//2)
elif (b%2!=0): # if b is odd
return a + (2 * multiply(a, b//2)) # b//2 is the floor division of b by 2
else:
return a * b
def FermatPrimalityTest(p):
"""
Performs the Fermat primality test on a given number p.
Args:
p (int): The number to be tested for primality.
Returns:
bool: True if p is likely to be prime, False otherwise.
"""
# 1 and negatives are not prime
if p <= 1 :
return False
# if it's even then it's not prime
if (p % 2 == 0):
return False
a = 2
# first fermet's pass
# if (a^n-1) % n != 1 then return False
if (pow(a, p-1, p) != 1):
return False
a = 7
# second fermet's pass
# if (a^n-1) % n != 1 then return False
if (pow(a, p-1, p) != 1):
return False
return True
def getPrime(minBits=256):
"""
Generates a prime number with a minimum number of bits using the Fermat primality test.
Args:
minBits (int): The minimum number of bits for the generated prime number. Default is 256.
Returns:
int: A prime number with at least minBits number of bits.
"""
num = 0
while (not FermatPrimalityTest(num)):
num = random.getrandbits(minBits)
# sometimes getrandbits() returns a number with less bits than required
# maybe because that most significant few bits are 0 and get trunkated
if(num.bit_length() < minBits):
num = multiply(num, 10000)
num += 7919
if(num.bit_length() < minBits):
num = multiply(num, 10000)
num += 3923
return num
def isCoprime(a, b):
"""
Check if two numbers are coprime.
Args:
a (int): First number.
b (int): Second number.
Returns:
bool: True if the numbers are coprime, False otherwise.
"""
return math.gcd(a, b) == 1
# returns the multiplicative inverse of a mod m
def getMultiplicativeInverse(a, m):
"""
Returns the multiplicative inverse of a mod m.
Args:
a (int): The number for which the multiplicative inverse is to be found.
m (int): The modulus.
Returns:
int: The multiplicative inverse of a mod m.
"""
return pow(a, -1, m)
def RSA_key_generation():
"""
Generates RSA keys and saves them to CSV files.
Returns:
None
"""
p = getPrime()
q = getPrime()
n = multiply(p,q)
phi = multiply(p-1, q-1)
e = getPrime(128)
while (not isCoprime(e, phi)):
e = getPrime(128)
d = getMultiplicativeInverse(e, phi)
# to be completed
pq = pd.Series([p,q])
en = pd.Series([e,n]) # e and n are public keys
dn = pd.Series([d,n]) # d and n are private keys
pq.to_csv("p_q.csv", index=False, header=False)
en.to_csv("e_n.csv", index=False, header=False)
dn.to_csv("d_n.csv", index=False, header=False)
print("done with key generation!")
def Signing(doc, key):
"""
Signs a document using the RSA algorithm and saves the signature to a file.
Args:
doc (str): The name of the document to be signed.
key (tuple): The RSA key (d, n).
Returns:
None
"""
# open doc and read it
with open(doc, mode ='r')as file:
docData = file.read()
# hash the document data and convert it to an integer
message = int(hashlib.sha256(docData.encode()).hexdigest(), 16)
# sign the message
signature = pow(message, key[0], key[1])
with open(doc+".signed", 'w') as f:
f.write(docData + "\n")
f.write(str(signature))
print("\nSigned ...")
def verification(doc, key):
"""
Verifies the signature of a document using the RSA algorithm.
Args:
doc (str): The name of the document to be verified.
key (tuple): The RSA key (e, n).
Returns:
None
"""
# open doc and read it
with open(doc, mode ='r')as file:
docLines = file.readlines()
# the document data is all the lines except the last one
docData = ''.join(docLines[:-1])
# remove new line at the end of the document data which shouldn't be there
if docData.endswith('\n'):
docData = docData[:-1]
# hash the document data and convert it to an integer
message = int(hashlib.sha256(docData.encode()).hexdigest(), 16)
# the signature is the last line
signature = int(docLines[-1])
# verify
# decryptedSignature = pow(signature, e) mod n
decryptedSignature = pow(signature, key[0], key[1])
match = message == decryptedSignature
# to be completed
if match:
print("\nAuthentic!")
else:
print("\nModified!")
# No need to change the main function.
def main():
# part I, command-line arguments will be: python yourProgram.py 1
if int(sys.argv[1]) == 1:
RSA_key_generation()
# part II, command-line will be for example: python yourProgram.py 2 s file.txt
# or python yourProgram.py 2 v file.txt.signed
else:
(task, fileName) = sys.argv[2:]
if "s" in task: # do signing
doc = fileName
# read d_n.csv file
with open('d_n.csv', mode ='r') as file:
csvFile = csv.reader(file)
d = int(next(csvFile)[0])
n = int(next(csvFile)[0])
key = (d, n) # key[0] is d and key[1] is n
Signing(doc, key)
else:
# do verification
doc = fileName
with open('e_n.csv', mode ='r') as file:
csvFile = csv.reader(file)
e = int(next(csvFile)[0])
n = int(next(csvFile)[0])
key = (e, n) # key[0] is e and key[1] is n
verification(doc, key)
print("done!")
if __name__ == '__main__':
main()