-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathHelper.py
385 lines (332 loc) · 12.5 KB
/
Helper.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
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
import json
import sys
import os
import re
import uuid
import time
import hashlib
import getpass
import socket, ssl
import threading
from cmd import Cmd
from os import urandom
from Crypto.Cipher import AES
from Crypto.PublicKey import RSA
from Crypto.Random import get_random_bytes
from Crypto.Cipher import AES, PKCS1_OAEP
from os.path import exists as file_exist
from contextlib import closing
flag = False
stop_event = False
contact_list = []
Contact_list_from_file = ''
user_file = "user.json"
contact_file = "contact.json"
private_key_file = "private.key"
public_key_file = "public.pem"
pattern = "^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$"
# function that validate useremail address with regular express
def validate_email():
# get user's email
email = input("Enter Email Address: ")
# validate email input using regular expression
while not re.match(pattern, email):
print("\nInvalid email address. Please try again.\n")
email = input("Enter Email Address: ")
return email.lower()
# function that generate public and private key
def generate_RSA_key():
key = RSA.generate(2048)
private_key = key.export_key()
file_out = open(private_key_file, "wb")
file_out.write(private_key)
file_out.close()
public_key = key.publickey().export_key()
file_out = open(public_key_file, "wb")
file_out.write(public_key)
file_out.close()
# function that encrypt file
def encrypt_textfile(input_textfile, output_textfile, receiver_public_key):
data = open(input_textfile, "r").read().encode("utf-8")
file_out = open(output_textfile, "wb")
recipent_key = RSA.import_key(open(receiver_public_key).read())
session_key = get_random_bytes(16)
# Encrypt the session key with the public RSA key
cipher_rsa = PKCS1_OAEP.new(recipent_key)
enc_session_key = cipher_rsa.encrypt(session_key)
# Encrypt the data with the AES session key
cipher_aes = AES.new(session_key, AES.MODE_EAX)
ciphertext, tag = cipher_aes.encrypt_and_digest(data)
[ file_out.write(x) for x in (enc_session_key, cipher_aes.nonce, tag, ciphertext)]
file_out.close()
# function that decrpyt file
def decrypt_textfile(input_textfile, output_textfile, sender_private_key):
file_in = open(input_textfile, "rb")
private_key = RSA.import_key(open(sender_private_key).read())
enc_session_key, nonce, tag, ciphertext = \
[ file_in.read(x) for x in (private_key.size_in_bytes(), 16, 16, -1) ]
file_in.close()
# Decrypt the session key with the private RSA key
cipher_rsa = PKCS1_OAEP.new(private_key)
session_key = cipher_rsa.decrypt(enc_session_key)
# Decrypt the data with the AES session key
cipher_aes = AES.new(session_key, AES.MODE_EAX, nonce)
data = cipher_aes.decrypt_and_verify(ciphertext,tag)
file_out = open(output_textfile, "wb")
file_out.write(data)
file_out.close()
def write_contact_file():
if file_exist(contact_file):
# decrypt first
decrypt_textfile(contact_file, contact_file, private_key_file)
# write back to json file with non duplicate key
with open(contact_file, "w") as write_json:
json.dump(Contact_list_from_file, write_json)
# Encrypt it
encrypt_textfile(contact_file, contact_file, public_key_file)
def read_contact_file():
global Contact_list_from_file
if file_exist(contact_file):
decrypt_textfile(contact_file, contact_file, private_key_file)
Contact_list_from_file = json.load(open(contact_file, "r"))
encrypt_textfile(contact_file, contact_file, public_key_file)
# function hash password value using sha356 with salt
def hash_data(password):
# uuid is used to generate a random number of the specified password
salt = uuid.uuid4().hex
return hashlib.sha256(salt.encode() + password.encode()).hexdigest() + ':' + salt
# function that take password of user entered and compare with hashed value in database
def check_hashed_data(hashed_password, user_password):
password, salt = hashed_password.split(':')
return password == hashlib.sha256(salt.encode() + user_password.encode()).hexdigest()
# Search thru contact file
def search_user(msg, Contact):
for keyval in Contact:
if msg.lower() == keyval["email"]:
name = keyval["name"]
return name
def search_email(msg, Contact):
for keyval in Contact:
if msg.lower() == keyval["email"]:
email = keyval["email"]
return email
def add_client_contact():
global Contact_list_from_file
# global stop_event
# stop_event = True
Duplicate = False
name = input("Enter Full Name: ")
email = validate_email()
# dictionary
contact = {
"name": name,
"email": email
}
# append contact.json everytime add new contact in
contact_list.append(contact)
if not file_exist(contact_file):
with open(contact_file, "w") as f:
# json.dump(list,f, indent=4)
json.dump(contact_list,f, indent=4)
encrypt_textfile(contact_file, contact_file, public_key_file)
Contact_list_from_file = contact_list
else:
# decrypt the contact.json file so system can access
read_contact_file()
Contact_list_from_file.append(contact)
# remove duplicate contact
unique_entries = []
for entry in Contact_list_from_file:
if entry not in unique_entries:
unique_entries.append(entry)
else:
Duplicate = True
Contact_list_from_file = unique_entries
write_contact_file()
# tell user that contact have been added
if Duplicate:
print("Duplicate contact, nothing added")
else:
print("Contact added")
# TCP client that send info to server and listen
def TCP_client(email):
while True:
global Contact_list_from_file
# message for handshake server and client
handshake_msg = "yes"
# create a socket object
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# get local machine name
host = socket.gethostname()
port = 9999
while True:
# try to connect to the server
try:
# keep connecting, if fail goes to exception, if succed break the loop
client_socket.connect((host, port))
break
except:
# if the connection fails, wait and try again
time.sleep(1)
# Wrap the socket in an SSL layer
context = ssl.create_default_context()
context.verify_mode = ssl.CERT_REQUIRED
context.check_hostname = True
context.load_verify_locations('cert.pem')
client_socket = context.wrap_socket(client_socket, server_hostname='localhost')
# send email address to server
client_socket.send(email.encode("utf-8"))
# Receive no more than 1024 bytes
incoming_msg = client_socket.recv(1024)
incoming_msg_str = incoming_msg.decode("utf-8")
# print("incoming_email_str is " + incoming_email_str)
if(incoming_msg_str != "no"): #if msg is 'sendrequest', skip this block
# open contact file
# search incoming email with existing email in contact list
contact_email_client = search_email(incoming_msg_str, Contact_list_from_file)
if contact_email_client == incoming_msg_str:
client_socket.send(handshake_msg.encode("utf-8"))
# File transfer receiving modules
if(incoming_msg_str == "sendrequest"):
contactemail = client_socket.recv(1024) #recieve identity of sender and filename
contactemail_str = contactemail.decode("utf-8")
filename = client_socket.recv(1024)
filename_str = filename.decode("utf-8")
filesize = client_socket.recv(1024)
filesize_str = filesize.decode("utf-8")
print("\nContact <" + contactemail_str + "> would like to send you <" + filename_str + "> Accept? (Press enter first, then y/n and enter again) y/n: ", end='', flush = True) #accept file
fileAccept = input()
if fileAccept == "y":
client_socket.send(fileAccept.encode("utf-8")) #send acceptance/refusal
with open(filename_str, "wb") as file:
c = 0
while c <= int(filesize_str):
data = client_socket.recv(1024)
if not (data):
break
file.write(data)
c += len(data)
print(filename_str + " successfully written.")
else:
msg = "n"
client_socket.send(msg.encode("utf-8")) #send acceptance/refusal
client_socket.close()
time.sleep(5)
# TCP server than get online user that have added into contact list
def list_all_online_contact(email):
connect = False
msg = "no"
# create a socket object
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# get local machine name
host = socket.gethostname()
port = 9999
# bind to the port
try:
serversocket.bind((host, port))
except OSError:
print("port: " + str(port) + " uses by other client, try again!")
return False
# queue up to 5 requests
serversocket.listen(5)
# Wrap the socket in an SSL context
context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
context.load_cert_chain(certfile='cert.pem', keyfile='cert.pem')
# Set a timeout for the accept() method
Wait_time = 3
serversocket.settimeout(Wait_time)
# Continuously accept connections and handle them until a timeout occurs
while True:
try:
# establish a connection
client_socket,addr = serversocket.accept()
# wrap the socket in an ssl layer
clientsocket = context.wrap_socket(client_socket, server_side=True)
# receiving email from other client
client_message = clientsocket.recv(1024)
client_msg_email_str = client_message.decode("utf-8")
# search client email within contact file
contact_email = search_email(client_msg_email_str, Contact_list_from_file)
contact_name = search_user(client_msg_email_str, Contact_list_from_file)
# if client email exist then send server email back
if contact_email == client_msg_email_str:
clientsocket.send(email.encode("utf-8"))
# receiving another message on handshake whether
# both client have added each other contact
client_handshake = clientsocket.recv(1024)
client_handshake_str = client_handshake.decode("utf-8")
if client_handshake_str == "yes":
print("* " + contact_name + " <" + contact_email + ">")
connect = True
else:
clientsocket.send(msg.encode("utf-8"))
clientsocket.close()
except socket.timeout:
break
serversocket.close()
return connect
def send_file(recipient_email, filename, email): #send file with arguments being file recipient, file, user_email
connect = False
msg = "no"
sendmsg = "sendrequest"
# create a socket object
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# get local machine name
host = socket.gethostname()
port = 9999
# bind to the port
try:
serversocket.bind((host, port))
except OSError:
print("port: " + str(port) + " in use by other client, try again!")
return False
# queue up to 5 requests
serversocket.listen(5)
# Wrap the socket in an SSL context
context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
context.load_cert_chain(certfile='cert.pem', keyfile='cert.pem')
# file_size
if file_exist(filename):
file_size = os.path.getsize(filename)
else:
print("File does not exist, please check file path")
return
# Set a timeout for the accept() method
Wait_time = 3
serversocket.settimeout(Wait_time)
# Continuously accept connections and handle them until a timeout occurs
while True:
try:
# establish a connection
client_socket,addr = serversocket.accept()
# wrap the socket in an ssl layer
clientsocket = context.wrap_socket(client_socket, server_side=True)
# receiving email from other client
client_message = clientsocket.recv(1024)
client_msg_email_str = client_message.decode("utf-8")
if(recipient_email == client_msg_email_str): #if email sent by client is recipient email
connect = True
clientsocket.send(sendmsg.encode("utf-8")) #send request to send a file
clientsocket.send(email.encode())
clientsocket.send(filename.encode()) #additionally send identity and filename
clientsocket.send(str(file_size).encode())
ready_to_accept = clientsocket.recv(1024) #receive acceptance/refusal from client
ready_to_accept_str = ready_to_accept.decode("utf-8")
# read data and send data byte by byte
if ready_to_accept_str == "y":
with open(filename, "rb") as file:
c = 0
while c <= file_size:
data = file.read(1024)
if not (data):
break
clientsocket.sendall(data)
c += len(data)
print("answer was yes, file has been sent")
else:
print("Reciever refuse to accpet file")
clientsocket.close()
except socket.timeout:
break
serversocket.close()
return connect