-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathclient.py
More file actions
128 lines (112 loc) · 4.4 KB
/
client.py
File metadata and controls
128 lines (112 loc) · 4.4 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
import socket
from utilities.ccakem import kem_keygen1024, kem_encaps1024, kem_decaps1024
from Crypto.Protocol.KDF import HKDF
from Crypto.Cipher import AES
from utilities.util import decode, encode
from Crypto.Hash import SHA512
import threading
import argparse
import psutil
HOST = "localhost"
PORT = 65432 # Default port
SALT = b'f285df90eef0292d294e94f00ce3a69e'
def port_in_use(port):
"""Check if the given port is already in use."""
for conn in psutil.net_connections():
if conn.laddr.port == port:
return True
return False
def handle_receive(conn, aes_key):
"""Handle receiving messages."""
while True:
try:
ciphertext = conn.recv(8096)
if not ciphertext:
break
tag = conn.recv(16)
nonce = conn.recv(16)
cipher = AES.new(aes_key, AES.MODE_EAX, nonce=nonce)
plaintext = cipher.decrypt(ciphertext)
try:
cipher.verify(tag)
plaintext = plaintext.decode('utf-8')
if plaintext == 'quit':
print("Connection closed by peer.")
break
print("Received:", plaintext)
except ValueError:
print("Key incorrect or message corrupted.")
except Exception as e:
print(f"Receive error: {e}")
break
def handle_send(conn, aes_key):
"""Handle sending messages."""
while True:
try:
# Get user input for the message
message = input("Enter message: ").encode("utf-8")
# Encrypt the message and obtain the nonce and tag
cipher = AES.new(aes_key, AES.MODE_EAX)
ciphertext, tag = cipher.encrypt_and_digest(message)
conn.sendall(ciphertext)
conn.sendall(tag)
conn.sendall(cipher.nonce)
if message.decode('utf-8') == 'quit':
print("Closing connection.")
break
except Exception as e:
print(f"Send error: {e}")
break
def key_exchange(conn, role, priv, pub):
"""Perform key exchange using KEM."""
if role == "send":
conn.sendall(encode(pub)) # Send public key
receiver_pub = decode(conn.recv(8096)) # Receive public key
shared_secret, cipher = kem_encaps1024(receiver_pub)
conn.sendall(encode(cipher)) # Send cipher
else:
sender_pub = decode(conn.recv(8096)) # Receive public key
conn.sendall(encode(pub)) # Send public key
cipher = decode(conn.recv(8096)) # Receive cipher
shared_secret = kem_decaps1024(priv, cipher)
return encode(shared_secret)
def main(role, port):
"""Main function to establish connection and handle messaging."""
s = None
try:
if role == "receive":
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((HOST, port))
s.listen()
print(f"Waiting for a connection on port {port}...")
conn, addr = s.accept()
else:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, port))
conn, addr = s, (HOST, port)
print(f"Connected as {role} by", addr)
priv, pub = kem_keygen1024()
root_key = key_exchange(conn, role, priv, pub)
aes_key = HKDF(root_key, 16, salt=SALT, hashmod=SHA512)
if role == "send":
# Start only the send thread for the "send" role
send_thread = threading.Thread(target=handle_send, args=(conn, aes_key))
send_thread.start()
send_thread.join()
elif role == "receive":
# Start only the receive thread for the "receive" role
receive_thread = threading.Thread(target=handle_receive, args=(conn, aes_key))
receive_thread.start()
receive_thread.join()
except Exception as e:
print(f"Error: {e}")
finally:
if s:
s.close()
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Quantum Messaging Application')
parser.add_argument('--role', choices=['send', 'receive'], required=True, help='Role: send or receive')
parser.add_argument('--port', type=int, default=PORT, help='Port to connect to or bind to (default: 65432)')
args = parser.parse_args()
main(args.role, args.port)