import tkinter as tk
from tkinter import ttk, messagebox, filedialog
import socket
import threading
import struct
import os
from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.primitives import serialization, hashes
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
class SecureServer:
def __init__(self, root):
self.root = root
self.root.title("安全通信服务器")
self.root.geometry("600x500")
self.session_key = None
# 生成RSA密钥对
self.private_key = rsa.generate_private_key(
public_exponent=65537,
key_size=2048,
backend=default_backend()
)
self.public_key = self.private_key.public_key()
# 界面布局
self.create_widgets()
self.server_socket = None
self.client_socket = None
self.running = False
def create_widgets(self):
# 服务器控制区域
control_frame = ttk.Frame(self.root, padding=10)
control_frame.pack(fill=tk.X)
ttk.Label(control_frame, text="端口:").grid(row=0, column=0, padx=5)
self.port_entry = ttk.Entry(control_frame, width=10)
self.port_entry.grid(row=0, column=1, padx=5)
self.port_entry.insert(0, "12345")
self.start_btn = ttk.Button(control_frame, text="启动服务器", command=self.start_server)
self.start_btn.grid(row=0, column=2, padx=5)
self.stop_btn = ttk.Button(control_frame, text="停止服务器", command=self.stop_server, state=tk.DISABLED)
self.stop_btn.grid(row=0, column=3, padx=5)
# 状态显示
status_frame = ttk.LabelFrame(self.root, text="服务器状态", padding=10)
status_frame.pack(fill=tk.X, padx=10, pady=5)
self.status_text = tk.Text(status_frame, height=8, width=70)
self.status_text.pack(fill=tk.BOTH, expand=True)
self.status_text.config(state=tk.DISABLED)
# 文件接收区域
file_frame = ttk.LabelFrame(self.root, text="接收文件", padding=10)
file_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)
self.file_list = ttk.Treeview(file_frame, columns=("size", "status"), show="headings")
self.file_list.heading("#0", text="文件名")
self.file_list.heading("size", text="大小")
self.file_list.heading("status", text="状态")
self.file_list.column("#0", width=200)
self.file_list.column("size", width=100)
self.file_list.column("status", width=100)
self.file_list.pack(fill=tk.BOTH, expand=True, pady=5)
self.save_btn = ttk.Button(file_frame, text="保存文件", command=self.save_file, state=tk.DISABLED)
self.save_btn.pack(pady=5)
# 消息区域
msg_frame = ttk.LabelFrame(self.root, text="消息", padding=10)
msg_frame.pack(fill=tk.X, padx=10, pady=5)
self.msg_entry = ttk.Entry(msg_frame)
self.msg_entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=5)
self.send_btn = ttk.Button(msg_frame, text="发送", command=self.send_message, state=tk.DISABLED)
self.send_btn.pack(side=tk.RIGHT, padx=5)
def log(self, message):
self.status_text.config(state=tk.NORMAL)
self.status_text.insert(tk.END, message + "\n")
self.status_text.see(tk.END)
self.status_text.config(state=tk.DISABLED)
def start_server(self):
port = int(self.port_entry.get())
try:
self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server_socket.bind(('', port))
self.server_socket.listen(1)
self.running = True
threading.Thread(target=self.accept_connections, daemon=True).start()
self.log(f"服务器已启动,监听端口 {port}")
self.start_btn.config(state=tk.DISABLED)
self.stop_btn.config(state=tk.NORMAL)
except Exception as e:
messagebox.showerror("错误", f"启动服务器失败: {str(e)}")
def stop_server(self):
self.running = False
try:
if self.client_socket:
self.client_socket.close()
if self.server_socket:
self.server_socket.close()
self.log("服务器已停止")
except:
pass
self.start_btn.config(state=tk.NORMAL)
self.stop_btn.config(state=tk.DISABLED)
self.send_btn.config(state=tk.DISABLED)
self.save_btn.config(state=tk.DISABLED)
def accept_connections(self):
while self.running:
try:
self.log("等待客户端连接...")
self.client_socket, addr = self.server_socket.accept()
self.log(f"客户端已连接: {addr[0]}:{addr[1]}")
# 发送公钥给客户端
pubkey_bytes = self.public_key.public_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PublicFormat.SubjectPublicKeyInfo
)
self.send_data(self.client_socket, 0x01, pubkey_bytes)
self.log("已发送服务器公钥")
# 接收会话密钥
_, enc_session_key = self.recv_data(self.client_socket)
self.session_key = self.private_key.decrypt(
enc_session_key,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)
self.log("已接收并解密会话密钥")
self.send_btn.config(state=tk.NORMAL)
threading.Thread(target=self.receive_data, daemon=True).start()
except Exception as e:
if self.running:
self.log(f"连接错误: {str(e)}")
break
def send_data(self, sock, msg_type, data):
header = struct.pack('!BI', msg_type, len(data))
sock.sendall(header + data)
def recv_data(self, sock):
header = sock.recv(5)
if not header:
return None, None
msg_type, length = struct.unpack('!BI', header)
data = b''
while len(data) < length:
packet = sock.recv(length - len(data))
if not packet:
break
data += packet
return msg_type, data
def receive_data(self):
while self.running:
try:
msg_type, data = self.recv_data(self.client_socket)
if msg_type is None:
break
if msg_type == 0x03: # 文本消息
iv = data[:12]
tag = data[12:28]
ciphertext = data[28:]
cipher = Cipher(algorithms.AES(self.session_key), modes.GCM(iv, tag), backend=default_backend())
decryptor = cipher.decryptor()
message = decryptor.update(ciphertext) + decryptor.finalize()
self.log(f"客户端: {message.decode()}")
elif msg_type == 0x04: # 文件元数据
iv = data[:12]
tag = data[12:28]
ciphertext = data[28:]
cipher = Cipher(algorithms.AES(self.session_key), modes.GCM(iv, tag), backend=default_backend())
decryptor = cipher.decryptor()
meta = decryptor.update(ciphertext) + decryptor.finalize()
filename, filesize = meta.decode().split('|')
self.receiving_file = {
'name': filename,
'size': int(filesize),
'data': b'',
'received': 0
}
self.file_list.insert("", "end", text=filename, values=(f"{int(filesize)/1024:.1f} KB", "传输中"))
self.save_btn.config(state=tk.DISABLED)
self.log(f"开始接收文件: {filename} ({filesize} 字节)")
elif msg_type == 0x05: # 文件数据
iv = data[:12]
tag = data[12:28]
ciphertext = data[28:]
cipher = Cipher(algorithms.AES(self.session_key), modes.GCM(iv, tag), backend=default_backend())
decryptor = cipher.decryptor()
file_data = decryptor.update(ciphertext) + decryptor.finalize()
self.receiving_file['data'] += file_data
self.receiving_file['received'] += len(file_data)
# 更新进度
progress = self.receiving_file['received'] / self.receiving_file['size'] * 100
for item in self.file_list.get_children():
if self.file_list.item(item, "text") == self.receiving_file['name']:
self.file_list.item(item, values=(f"{self.receiving_file['size']/1024:.1f} KB", f"{progress:.1f}%"))
# 文件接收完成
if self.receiving_file['received'] >= self.receiving_file['size']:
self.receiving_file['data'] = self.receiving_file['data'][:self.receiving_file['size']]
for item in self.file_list.get_children():
if self.file_list.item(item, "text") == self.receiving_file['name']:
self.file_list.item(item, values=(f"{self.receiving_file['size']/1024:.1f} KB", "已接收"))
self.save_btn.config(state=tk.NORMAL)
self.log(f"文件接收完成: {self.receiving_file['name']}")
except Exception as e:
if self.running:
self.log(f"接收错误: {str(e)}")
break
def send_message(self):
message = self.msg_entry.get()
if not message or not self.client_socket:
return
try:
iv = os.urandom(12)
cipher = Cipher(algorithms.AES(self.session_key), modes.GCM(iv), backend=default_backend())
encryptor = cipher.encryptor()
ciphertext = encryptor.update(message.encode()) + encryptor.finalize()
tag = encryptor.tag
data = iv + tag + ciphertext
self.send_data(self.client_socket, 0x03, data)
self.log(f"服务器: {message}")
self.msg_entry.delete(0, tk.END)
except Exception as e:
self.log(f"发送消息失败: {str(e)}")
def save_file(self):
if not hasattr(self, 'receiving_file') or not self.receiving_file['data']:
return
file_path = filedialog.asksaveasfilename(
initialfile=self.receiving_file['name'],
filetypes=[("所有文件", "*.*")]
)
if file_path:
try:
with open(file_path, 'wb') as f:
f.write(self.receiving_file['data'])
self.log(f"文件已保存: {file_path}")
except Exception as e:
messagebox.showerror("错误", f"保存文件失败: {str(e)}")
if __name__ == "__main__":
root = tk.Tk()
app = SecureServer(root)
root.mainloop()
请根据上面的代码再加上我上面所述的要求,重新修改服务端代码
最新发布