-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsecurechat.py
74 lines (64 loc) · 1.93 KB
/
securechat.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
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import x25519
from cryptography.hazmat.primitives.kdf.hkdf import HKDF
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from threading import Thread
from time import sleep
import zmq
import sys
def sub_routine(socket, crypto):
while True:
cipherText = socket.recv()
message = crypto.update(cipherText).decode()
print("them> ", message)
context = zmq.Context()
#pub/sub is a disgusting hack
pub = context.socket(zmq.PUB)
sub = context.socket(zmq.SUB)
#Are we running as a server?
if len(sys.argv) == 1:
isServer = True
pub.bind("tcp://*:5555")
sub.bind("tcp://*:5556")
else:
isServer = False
pub.connect("tcp://" + sys.argv[1] + ":5556")
sub.connect("tcp://" + sys.argv[1] + ":5555")
sub.setsockopt_string(zmq.SUBSCRIBE, "")
#handshake
if isServer:
message = sub.recv().decode()
if message != "hello":
raise Exception("handshake failed")
else:
#sleep resolves a cursed timing issue
sleep(0.1)
pub.send(b"hello")
#Diffie-Hellman
privateKey = x25519.X25519PrivateKey.generate()
publicKey = privateKey.public_key().public_bytes_raw()
pub.send(publicKey)
theirPublicKey = x25519.X25519PublicKey.from_public_bytes(sub.recv())
sharedKey = privateKey.exchange(theirPublicKey)
keyIv = HKDF(
algorithm=hashes.SHA256(),
length=48,
salt=None,
info=b'handshake data',
).derive(sharedKey)
key = keyIv[:32]
iv = keyIv[-16:]
#initalize AES
cipher = Cipher(algorithms.AES(key), modes.CBC(iv))
encryptor = cipher.encryptor()
decryptor = cipher.decryptor()
#start listenting thread
subber = Thread(target=sub_routine, args=[sub, decryptor])
subber.start()
#prompt for messages
while True:
message = input("> ")
for i in range(16 - len(message) % 16):
message += '\0'
cipherText = encryptor.update(message.encode())
pub.send(cipherText)