-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathchat_client-cli.py
More file actions
148 lines (117 loc) · 4.21 KB
/
chat_client-cli.py
File metadata and controls
148 lines (117 loc) · 4.21 KB
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
import socket
import threading
import time
from random import *
from Cryptodome import Random
from Cryptodome.Cipher import PKCS1_OAEP
from Cryptodome.PublicKey import RSA
HEADERLEN = 8
NAME = f'cliCl-{randint(100, 999)}'
ENCODING = 'utf-8'
BUFFERSIZE = 64
# Size of RSA key to generate
KEYSIZE = 1024
# Use 127.0.0.1 to connect to server running on your own pc
SERVER_ADDR = ('127.0.0.1', 1252)
class Server:
def __init__(self, addr):
self.ip = addr[0]
self.port = addr[1]
self.conn = None
self.pubkey = None
self.rsaestablished = False
def connect(self):
if self.conn is None:
self.conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.conn.connect((self.ip, self.port))
def disconnect(self):
if self.conn is not None:
self.conn.close()
self.conn = None
def createKeys(size):
print('Generating RSA Keys')
random_generator = Random.new().read
key = RSA.generate(size, random_generator)
print('Done')
return key
def setupMsg(msg):
data = f'{"MSG":<{4}}{len(msg):<{4}}'.encode('utf-8') + msg
return data
def setupPubKey(key):
data = f'{"PK":<{4}}{len(key):<{4}}'.encode('utf-8') + key
return data
def showmsg():
full_msg = b''
new_msg = True
while 1:
try:
data = server.conn.recv(BUFFERSIZE)
except:
print(f'Connection Lost')
server.conn = None
break
# If data is not empty
if data:
if new_msg:
msgtype = data[:3].decode('utf-8') # Type of message (MSG/PK)
msglen = int(data[4:HEADERLEN].decode('utf-8')) # Length of message
new_msg = False
full_msg += data
if len(full_msg) - HEADERLEN == msglen:
# Uncomment the following line to see raw messages
# print(str(full_msg))
# If message is a public key
if msgtype.strip(' ') == 'PK':
print(f'PubKey Recieved from server')
# Import public key string into RSA key object
srvpubkey = RSA.importKey(full_msg[HEADERLEN:])
encryptor = PKCS1_OAEP.new(srvpubkey)
server.pubkey = encryptor
print('Sending ENCTEST message to server')
server.conn.sendall(setupMsg(server.pubkey.encrypt('ENCTEST'.encode('utf-8'))))
time.sleep(0.5)
server.conn.sendall(setupPubKey(pubkeybytes))
# If message is of MSG type
elif msgtype.strip(' ') == 'MSG':
decrypted = clidecryptor.decrypt(full_msg[HEADERLEN:]).decode('utf-8')
if server.rsaestablished is False:
if decrypted == 'ENCTEST':
server.rsaestablished = True
print(f'ENCTEST recieved from server')
else:
print(f'Server encryption test failed, Disconnecting')
server.disconnect()
else:
print(f'{decrypted}')
new_msg = True
full_msg = b''
def sendmsg():
global NAME
while 1:
msg = input()
if msg == '/exit':
server.disconnect()
exit()
elif msg.startswith('/name'):
try:
if len(msg.split(' ')[1]) <= 12:
NAME = msg.split(' ')[1]
else:
print('[ERROR] Name too long')
except:
continue
else:
server.conn.sendall(setupMsg(server.pubkey.encrypt(msg.encode('utf-8'))))
key = createKeys(KEYSIZE)
pubkey = key.publickey()
# Clients public key in bytes string format
pubkeybytes = pubkey.exportKey(format='PEM')
# Decryptor to decrypt messages from the server
clidecryptor = PKCS1_OAEP.new(key)
# Use 127.0.0.1 to connect to server running on your own pc
server = Server(SERVER_ADDR)
server.connect()
showthread = threading.Thread(target=showmsg)
sendthread = threading.Thread(target=sendmsg)
showthread.start()
sendthread.start()