-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathchallenge37_client.py
151 lines (122 loc) · 4.91 KB
/
challenge37_client.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
#!/usr/bin/env python3
from utils import power_mod, Random
import socket
import threading
from time import time
from Crypto.Hash import SHA256, HMAC
from aes import aes_cbc_decrypt, aes_cbc_encrypt
from padding import pkcs7_pad, pkcs7_unpad
from os import urandom
'''
sending A = 0 or A = N forces S on the server side to be equal to 0.
So by setting S = 0 on the client side as well, we bypass password authentication
'''
# --------------------------------------------------------
# ---------------------- functions -----------------------
# --------------------------------------------------------
class Client():
def __init__(self, HOST = 'localhost', PORT = 10000):
# create a TCP socket
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.host = HOST
self.port = PORT
self.other = "S" # other user's nickname
self.email = "[email protected]"
self.password = "secretpasswodrd"
# connect to the server
self._connect()
# Starting Threads For Listening And Writing
receive_thread = threading.Thread(target=self.receive)
receive_thread.start()
write_thread = threading.Thread(target=self.write)
write_thread.start()
def _connect(self):
# initiate server connection
try:
self.sock.connect((self.host, self.port))
print(f"Connected to {self.host}:{self.port}")
# sending email (l) and password (P)
self.sock.sendall(f'{self.email},{self.password}'.encode())
message = self.sock.recv(1024)
# receiving N, g, k
message = self.sock.recv(1024)
self.N, self.g, self.k = [int(x) for x in message.decode().split(',')]
# sending A the public key in DH
self.a = Random(int(time())).random()
self._private_key = power_mod(self.a, 1, self.N)
#self.A = power_mod(self.g, self._private_key, self.N)
# sending A = 0, must change S = 0 on client side as well
self.A = 0
# sending A = N
self.A = self.N
self.sock.send(str(self.A).encode())
# receive salt, B
message = self.sock.recv(1024)
self.salt, self.B = [int(x) for x in message.decode().split(',')]
# compute uH and u
hash_256 = SHA256.new()
hash_256.update((str(self.A)+str(self.B)).encode())
uH = hash_256.hexdigest()
# convert to int
self.u = int(uH, 16)
# get xH and x, hash salt + password
hash_256 = SHA256.new()
hash_256.update((str(self.salt)+self.password).encode())
xH = hash_256.hexdigest()
# convert to int
self.x = int(xH, 16)
# generate S
var_1 = self.B - self.k*power_mod(self.g, self.x, self.N)
var_2 = self._private_key + self.u*self.x
if self.A == 0 or self.A == self.N:
self.S = 0
else:
self.S = power_mod(var_1, var_2, self.N)
# generate K
hash_256 = SHA256.new()
hash_256.update((str(self.S).encode()))
self.K = hash_256.hexdigest()
self.shared_key = hash_256.digest()
# generate HMAC
h = HMAC.new(self.K.encode(), digestmod=SHA256)
h.update(str(self.salt).encode())
hmac_digest = h.hexdigest()
self.sock.send(hmac_digest.encode())
except:
print('server is off')
# Sending Messages To Server
def write(self):
while True:
message = input('')
try:
if self.shared_key:
# dh exchange is over, encrypt messages
iv = urandom(16)
padded = pkcs7_pad(message)
encrypted_msg = aes_cbc_encrypt(padded, self.shared_key, iv)
print(f"sending ({message}) -> {encrypted_msg}")
self.sock.send(encrypted_msg + iv)
else:
self.sock.send(message.encode())
except KeyboardInterrupt:
print('closing connection.')
exit()
# Listening to Server
def receive(self):
while True:
# Receive Message From Server
message = self.sock.recv(1024)
# if connection closes
if message == b'':
print("connection lost!")
self.sock.close()
break
else:
print(f"{self.other}: {message.decode()}")
# --------------------------------------------------------
# ------------------------- main -------------------------
# --------------------------------------------------------
def main():
client = Client()
if __name__ == "__main__":
main()