From 51adade26176f116d9f511541c0274dc6348eb46 Mon Sep 17 00:00:00 2001 From: pyxhe2owb <1303560711@qq.com> Date: Thu, 26 Dec 2024 19:37:02 +0800 Subject: [PATCH] ADD file via upload --- client.py | 192 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 192 insertions(+) create mode 100644 client.py diff --git a/client.py b/client.py new file mode 100644 index 0000000..bcb6571 --- /dev/null +++ b/client.py @@ -0,0 +1,192 @@ +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()