import sys import socket from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QPushButton, QFileDialog, QLineEdit, QLabel, QComboBox from PyQt5.QtCore import Qt from Crypto.PublicKey import RSA from Crypto.Cipher import AES, PKCS1_OAEP from Crypto.Random import get_random_bytes from Crypto.Signature import pkcs1_15 from Crypto.Hash import SHA256 from Crypto.Util.Padding import pad import hashlib import os class FileTransferApp(QWidget): def __init__(self): super().__init__() # 生成公钥和私钥 self.generate_keys_if_not_exists() self.init_ui() def init_ui(self): self.setWindowTitle('文件加密和传输') self.setGeometry(100, 100, 400, 300) layout = QVBoxLayout() self.file_label = QLabel('未选择文件') layout.addWidget(self.file_label) self.select_button = QPushButton('选择文件') self.select_button.clicked.connect(self.select_file) layout.addWidget(self.select_button) self.server_label = QLabel('服务器 IP:') layout.addWidget(self.server_label) self.server_ip = QLineEdit(self) layout.addWidget(self.server_ip) self.server_port_label = QLabel('服务器端口:') layout.addWidget(self.server_port_label) self.server_port = QLineEdit(self) self.server_port.setText('59290') # 默认端口 layout.addWidget(self.server_port) self.algorithm_label = QLabel('选择加密算法:') layout.addWidget(self.algorithm_label) self.algorithm_combo = QComboBox(self) self.algorithm_combo.addItem('AES') layout.addWidget(self.algorithm_combo) self.mode_label = QLabel('选择加密模式:') layout.addWidget(self.mode_label) self.mode_combo = QComboBox(self) self.mode_combo.addItem('CBC') self.mode_combo.addItem('ECB') layout.addWidget(self.mode_combo) self.send_button = QPushButton('发送加密文件') self.send_button.clicked.connect(self.send_file) layout.addWidget(self.send_button) self.setLayout(layout) def select_file(self): options = QFileDialog.Options() filename, _ = QFileDialog.getOpenFileName(self, "选择文件", "", "所有文件 (*);;文本文件 (*.txt)", options=options) if filename: self.file_label.setText(f'选择的文件: {filename}') self.file_path = filename def generate_keys_if_not_exists(self): """生成公钥和私钥,如果文件不存在""" if not os.path.exists('public.pem') or not os.path.exists('private.pem'): print("正在生成公钥和私钥...") self.generate_keys() else: print("公钥和私钥已存在。") def generate_keys(self): """生成公钥和私钥并保存为文件""" key = RSA.generate(2048) # 导出私钥 private_key = key.export_key() with open('private.pem', 'wb') as f: f.write(private_key) print("私钥已保存为 'private.pem'") # 导出公钥 public_key = key.publickey().export_key() with open('public.pem', 'wb') as f: f.write(public_key) print("公钥已保存为 'public.pem'") def load_public_key(self): # 从文件加载接收方公钥(用于加密会话密钥) with open('receiver_public.pem', 'rb') as f: public_key = RSA.import_key(f.read()) return public_key def load_private_key(self): # 从文件加载私钥(用于签名文件) with open('private.pem', 'rb') as f: private_key = RSA.import_key(f.read()) return private_key def encrypt_file(self, filename, public_key): # 为 AES 加密生成随机会话密钥 session_key = get_random_bytes(16) # 选择加密模式 mode = self.mode_combo.currentText() if mode == 'CBC': cipher_aes = AES.new(session_key, AES.MODE_CBC) iv = cipher_aes.iv # 获取 CBC 模式使用的 IV elif mode == 'ECB': cipher_aes = AES.new(session_key, AES.MODE_ECB) iv = None # 加密文件 with open(filename, 'rb') as f: plaintext = f.read() ciphertext = cipher_aes.encrypt(pad(plaintext, AES.block_size)) # 对明文进行填充,以满足块大小要求 # 使用 RSA 加密会话密钥 cipher_rsa = PKCS1_OAEP.new(public_key) encrypted_session_key = cipher_rsa.encrypt(session_key) return encrypted_session_key, iv, ciphertext def sign_file(self, filename, private_key): # 计算文件的 SHA-256 哈希值 hash_obj = SHA256.new() with open(filename, 'rb') as f: while chunk := f.read(4096): hash_obj.update(chunk) # 使用私钥签名哈希值 signer = pkcs1_15.new(private_key) signature = signer.sign(hash_obj) return signature def send_file(self): # 获取服务器地址和端口 host = self.server_ip.text() port = int(self.server_port.text()) # 加载公钥(用于加密会话密钥) public_key = self.load_public_key() # 加载私钥(用于签名文件) private_key = self.load_private_key() # 加密选择的文件 encrypted_session_key, iv, ciphertext = self.encrypt_file(self.file_path, public_key) # 签名文件 signature = self.sign_file(self.file_path, private_key) # 建立 socket 连接 client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client_socket.connect((host, port)) # 发送加密的会话密钥、IV、密文和签名 client_socket.sendall(encrypted_session_key) client_socket.sendall(iv) client_socket.sendall(ciphertext) client_socket.sendall(signature) client_socket.close() print("文件发送成功。") # 提示用户 self.file_label.setText('文件发送成功!') def main(): app = QApplication(sys.argv) ex = FileTransferApp() ex.show() sys.exit(app.exec_()) if __name__ == '__main__': main()