You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python带登录的Fernet加密聊天室客户端解密失败求助

问题分析与解决方案

你的聊天室客户端无法解密消息,核心是服务器端的两个逻辑错误导致加密数据损坏或双重加密:

错误点1:服务器错误地处理客户端发送的加密数据

客户端发送的是加密后的二进制数据,但服务器接收时先尝试将其解码为UTF-8字符串,再重新编码。加密后的bytes并非合法的UTF-8序列,这一步会直接损坏原始加密数据,后续解密即使不报错,也无法得到正确内容。

错误点2:广播时的双重加密逻辑

服务器在接收并解密客户端消息后,先重新加密明文,然后广播时又将这个加密后的消息与发送者前缀拼接再加密一次,导致客户端收到双重加密的数据,一次解密无法得到明文。


修正后的服务器代码

import socket
import threading
from cryptography.fernet import Fernet

# Generate a secret key for encryption
key = Fernet.generate_key()
cipher_suite = Fernet(key)
print(key.decode())

# Store username-password pairs (for demo purposes)
user_credentials = {
    "user1": "password1",
    "user2": "password2",
}

# Store connected clients
connected_clients = {}

def handle_client(client_socket):
    username = client_socket.recv(1024).decode('utf-8')
    password = client_socket.recv(1024).decode('utf-8')

    if username in user_credentials and user_credentials[username] == password:
        client_socket.send("Authenticated".encode('utf-8'))
        print(f"{username} has connected.")
        connected_clients[username] = client_socket

        while True:
            try:
                # 直接接收加密的二进制数据,不做UTF-8解码
                message = client_socket.recv(1024)
                # 先判断连接是否断开
                if not message:
                    del connected_clients[username]
                    client_socket.close()
                    print(f"{username} has disconnected.")
                    break
                # 直接解密二进制数据
                decrypted_message = cipher_suite.decrypt(message)
                decoded_message = decrypted_message.decode('utf-8')
                print(f"Received from {username}: {decoded_message}")
                # 将明文传给广播函数,由广播函数负责加密带前缀的消息
                broadcast_message(username, decoded_message)
            except Exception as e:
                print(str(e))
                break
    else:
        client_socket.send("Authentication failed".encode('utf-8'))
        client_socket.close()

def broadcast_message(sender, plain_message):
    for username, client_socket in connected_clients.items():
        if username != sender:
            try:
                # 将发送者和明文拼接后加密,生成最终要发送的加密消息
                encrypted_message = cipher_suite.encrypt(f"{sender}: {plain_message}".encode('utf-8'))
                client_socket.send(encrypted_message)
            except Exception as e:
                print(str(e))
                continue

def main():
    PORT = 5052
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server.bind(("0.0.0.0", PORT))
    server.listen(5)
    print(f"Server listening on port {PORT}")

    while True:
        client_socket, addr = server.accept()
        client_handler = threading.Thread(target=handle_client, args=(client_socket,))
        client_handler.start()

if __name__ == "__main__":
    main()

优化后的客户端代码(非必须但更高效)

import socket
from cryptography.fernet import Fernet
import threading

# 提前创建Fernet实例,避免每次发送/接收时重复初始化
key = input("Enter the secret key: ").encode()
cipher_suite = Fernet(key)

def send_message(client_socket):
    while True:
        message = input()
        client_socket.send(cipher_suite.encrypt(message.encode()))

def receive_message(client_socket):
    while True:
        try:
            message = client_socket.recv(1024)
            decrypted_message = cipher_suite.decrypt(message)
            print(decrypted_message.decode('utf-8'))
        except Exception as e:
            print(str(e))
            break

def main():
    PORT = 5052
    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    client.connect(("YOUR_SERVER_IP", PORT))

    username = input("Username: ")
    password = input("Password: ")

    client.send(username.encode())
    client.send(password.encode())

    response = client.recv(1024).decode()
    if response == "Authenticated":
        print("Authentication successful. You are now connected to the chatroom.")
        send_thread = threading.Thread(target=send_message, args=(client,))
        receive_thread = threading.Thread(target=receive_message, args=(client,))

        send_thread.start()
        receive_thread.start()
    else:
        print("Authentication failed. Closing connection.")
        client.close()

if __name__ == "__main__":
    main()

额外注意事项

  1. 确保客户端输入的密钥与服务器启动时打印的密钥完全一致,不要包含多余的空格或换行符。
  2. 服务器绑定的IP改为0.0.0.0可以允许外部设备连接,客户端需替换YOUR_SERVER_IP为服务器实际IP。
  3. 测试时先启动服务器,复制打印的密钥,再启动客户端输入该密钥。

内容的提问来源于stack exchange,提问作者7ven Perks

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 13:56:00