本代码成功实现了一个安全的多客户端即时聊天应用程序,采用了对称加密(使用Fernet库)和SHA-256哈希算法来保护通信的机密性和完整性。
服务器端负责监听客户端的连接请求,一旦有两个客户端连接成功,就为每个客户端创建一个独立的线程。这些线程负责接收、解密和转发消息。
在消息传输过程中,使用哈希算法验证以确保消息未被篡改。
这种设计保证了消息的机密性和完整性,使得即时聊天更加安全可靠。此外,代码还提供了可扩展性,可以根据实际需求进一步增加功能和改进安全性。
在运行代码前要先打开cmd安装pycryptodome库
pip install pycryptodome
生成密钥的代码
from cryptography.fernet import Fernet
# 生成Fernet密钥
new_key = Fernet.generate_key()
# 将新密钥保存到文件
with open("./des_bkey.bin", "wb") as key_file:
key_file.write(new_key)
# 生成Fernet密钥
new_key = Fernet.generate_key()
# 将新密钥保存到文件
with open("./des_akey.bin", "wb") as key_file:
key_file.write(new_key)
生成AB密钥的代码(a,b自己改一下)
from cryptography.fernet import Fernet
# 生成Fernet密钥
a_private_key = Fernet.generate_key()
# 将相同的密钥赋值给public_keyb变量
public_keya = a_private_key
# 将密钥写入文件
with open("a_private_key.key", "wb") as private_key_file:
private_key_file.write(a_private_key)
with open("public_keya.key", "wb") as public_key_file:
public_key_file.write(public_keya)
print("Keys have been saved to b_private_key.key and public_keyb.key")
重点:运行代码时要先运行主机端代码,再运行客户端B代码,最后运行客户端A代码
以下是主机端代码
import socket
import threading
from cryptography.fernet import Fernet
import hashlib
# 加载a和b的共享密钥
with open("D:/pythondm/des_akey.bin", "rb") as file:
a1 = file.read()
with open("D:/pythondm/des_bkey.bin", "rb") as file:
b1 = file.read()
# 创建a到b的加密套件
a_to_b_cipher = Fernet(a1)
# 创建b到a的加密套件
b_to_a_cipher = Fernet(b1)
# 创建服务器套接字
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = '127.0.0.1'
port = 1235
server_socket.bind((host, port))
server_socket.listen(2) # 监听两个客户端连接
print(f"等待客户端连接在 {host}:{port}")
clients = []
def sha256_hash(message):
sha256 = hashlib.sha256()
sha256.update(message.encode())
return sha256.hexdigest()
def sign_message(message):
# 进行哈希值计算
signature = hashlib.sha256(message.encode()).hexdigest()
return signature
def verify_signature(message, signature):
# 验证哈希值
calculated_signature = hashlib.sha256(message.encode()).hexdigest()
return calculated_signature == signature
def forward_message(sender_socket, receiver_cipher):
while True:
try:
encrypted_message = sender_socket.recv(1024)
if not encrypted_message:
break
# 解密消息
decrypted_message = receiver_cipher.decrypt(encrypted_message).decode()
print(f"收到消息: {decrypted_message}")
# 发送消息给接收者
receiver_socket = clients[1 - clients.index(sender_socket)]
# 根据消息的来源选择正确的加密密钥
if sender_socket == clients[0]:
sender_cipher = a_to_b_cipher
else:
sender_cipher = b_to_a_cipher
# 数字签名
signature = sign_message(decrypted_message)
# 将消息和哈希值一起加密并发送
message_with_signature = f"{decrypted_message}:{signature}"
encrypted_message = sender_cipher.encrypt(message_with_signature.encode())
receiver_socket.send(encrypted_message)
except Exception as e:
print(f"错误: {e}")
break
while True:
# 接受客户端连接
client_socket, client_address = server_socket.accept()
print(f"连接来自 {client_address} 的客户端")
clients.append(client_socket)
# 当有两个客户端连接时,为每个客户端创建一个线程
if len(clients) == 2:
client1_thread = threading.Thread(target=forward_message, args=(clients[0], b_to_a_cipher))
client2_thread = threading.Thread(target=forward_message, args=(clients[1], a_to_b_cipher))
client1_thread.daemon = True
client2_thread.daemon = True
client1_thread.start()
client2_thread.start()
客户端A代码
import socket
import threading
from cryptography.fernet import Fernet
import hashlib
# 加载共享密钥a1
with open("D:/pythondm/des_akey.bin", "rb") as file:
shared_key_a = file.read()
# 创建b_to_a加密套件
b_to_a_cipher = Fernet(shared_key_a)
# 与服务器建立连接
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = '127.0.0.1'
port = 1235
client_socket.connect((host, port))
def sha256_hash(message):
sha256 = hashlib.sha256()
sha256.update(message.encode())
return sha256.hexdigest()
def sign_message(message):
signature = hashlib.sha256(message.encode()).hexdigest()
return signature
def verify_signature(message, signature):
calculated_signature = hashlib.sha256(message.encode()).hexdigest()
return calculated_signature == signature
def receive_messages():
while True:
try:
encrypted_message = client_socket.recv(1024)
decrypted_message = b_to_a_cipher.decrypt(encrypted_message).decode()
# 拆分消息和签名
message, received_signature = decrypted_message.rsplit(':', 1)
# 验证消息的签名
if verify_signature(message, received_signature):
print(f"客户端B: {message}")
else:
print("接收到篡改的消息!")
except Exception as e:
print(f"错误: {e}")
break
# 创建消息接收线程
receive_thread = threading.Thread(target=receive_messages)
receive_thread.daemon = True
receive_thread.start()
while True:
message = input("客户端A: ")
# 哈希值计算
signature = sign_message(message)
# 将消息和哈希值一起加密并发送
message_with_signature = f"{message}:{signature}"
encrypted_message = b_to_a_cipher.encrypt(message_with_signature.encode())
client_socket.send(encrypted_message)
客户端B代码
import socket
import threading
from cryptography.fernet import Fernet
import hashlib
# 加载共享密钥b1
with open("D:/pythondm/des_bkey.bin", "rb") as file:
shared_key_b = file.read()
# 创建a_to_b加密套件
a_to_b_cipher = Fernet(shared_key_b)
# 与服务器建立连接
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = '127.0.0.1'
port = 1235
client_socket.connect((host, port))
def sha256_hash(message):
sha256 = hashlib.sha256()
sha256.update(message.encode())
return sha256.hexdigest()
def sign_message(message):
signature = hashlib.sha256(message.encode()).hexdigest()
return signature
def verify_signature(message, signature):
calculated_signature = hashlib.sha256(message.encode()).hexdigest()
return calculated_signature == signature
def receive_messages():
while True:
try:
encrypted_message = client_socket.recv(1024)
decrypted_message = a_to_b_cipher.decrypt(encrypted_message).decode()
# 拆分消息和签名
message, received_signature = decrypted_message.rsplit(':', 1)
# 验证消息的签名
if verify_signature(message, received_signature):
print(f"客户端A: {message}")
else:
print("接收到篡改的消息!")
except Exception as e:
print(f"错误: {e}")
break
# 创建消息接收线程
receive_thread = threading.Thread(target=receive_messages)
receive_thread.daemon = True
receive_thread.start()
while True:
message = input("客户端B: ")
# 哈希值计算
signature = sign_message(message)
# 将消息和哈希值一起加密并发送
message_with_signature = f"{message}:{signature}"
encrypted_message = a_to_b_cipher.encrypt(message_with_signature.encode())
client_socket.send(encrypted_message)
如果生成密钥有问题,就直接用我给的
a_private_key.key
NzHjn4Em974MZVnKC-mC9fTKUo9898ToRm1vM3i1Z-M=
b_private_key.key
OtsUYQW4Ym-zewNDL6KhzyUIHInN9Kblwubn6LFxTVQ=
des_akey.bin
cYQ2KCOHuVw3GDwa_7FABPXIqLW5CedgOcpGfNXjiwM=
des_bkey.bin
W9lIxjJ3Ki_lZyTBXSDxgpvKc0gVSjesn2UANVTauso=
public_keya.key
NzHjn4Em974MZVnKC-mC9fTKUo9898ToRm1vM3i1Z-M=
public_keyb.key
OtsUYQW4Ym-zewNDL6KhzyUIHInN9Kblwubn6LFxTVQ=
运行过程
先启动主机端
启动客户端b
启动客户端a
b端输入
可以在主机端和a端看到