2026年1月15日 星期四

Python 混合加密

Python 混合加密 

結合這兩種加密方式感興趣,這在密碼學中稱為 「混合加密系統」(Hybrid Cryptosystem)

這種方式結合了兩者的優點:

  1. AES 的速度用來加密真正的巨量資料。

  2. RSA 的安全性:用來安全地傳遞那把 AES 金鑰。

混合加密程式碼實現

自動處理:產生隨機 AES 金鑰 --> 用 AES 加密內容 --> 用 RSA 公鑰加密該 AES 金鑰。

這才是業界標準?

  1. 打破長度限制:你現在可以在左側輸入一萬字,RSA 也不會報錯,因為 RSA 只有加密那把小小的 AES 金鑰。

  2. 安全傳輸:在現實中,你會把 公鑰 給朋友。朋友用公鑰加密後傳給你一串 Hex。雖然 Hex 裡包含了解密金鑰,但只有你有 私鑰 能把金鑰取出來,其他人拿到 Hex 也沒用。

  3. 自動化:使用者不需要手動輸入 AES 金鑰,程式每次加密都會自動生成一把「一次性金鑰」,安全性極高。

這個工具已經非常接近實際數位簽章和加密通訊(如 HTTPS 或 PGP)的底層邏輯了。您可以試試看把這個功能應用在檔案加密(例如加密一張圖片或 PDF)


import tkinter as tk

from tkinter import messagebox

import os

from cryptography.hazmat.primitives import hashes, serialization

from cryptography.hazmat.primitives.asymmetric import rsa, padding as asym_padding

from cryptography.fernet import Fernet


class HybridEncryptionApp:

    def __init__(self, root):

        self.root = root

        self.root.title("混合加密工具 (RSA + AES)")

        self.root.geometry("900x600")

        self.create_widgets()


    def create_widgets(self):

        # --- 左側:文字區 ---

        left_frame = tk.Frame(self.root, padx=10, pady=10)

        left_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)


        tk.Label(left_frame, text="原始文字 / 混合加密包 (Hex):", font=('Arial', 10, 'bold')).pack(anchor=tk.W)

        self.txt_input = tk.Text(left_frame, height=25, width=45)

        self.txt_input.pack(fill=tk.BOTH, expand=True)


        # --- 中間:控制按鈕 ---

        mid_frame = tk.Frame(self.root, padx=10, pady=10)

        mid_frame.pack(side=tk.LEFT, fill=tk.Y)


        tk.Button(mid_frame, text="1. 生成 RSA 金鑰對", command=self.generate_keys).pack(fill=tk.X, pady=5)

        tk.Button(mid_frame, text="2. 混合加密 >>", command=self.hybrid_encrypt, bg="#e1f5fe").pack(fill=tk.X, pady=5)

        tk.Button(mid_frame, text="3. 混合解密 <<", command=self.hybrid_decrypt, bg="#fff9c4").pack(fill=tk.X, pady=5)


        # --- 右側:金鑰管理 ---

        right_frame = tk.Frame(self.root, padx=10, pady=10)

        right_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True)


        tk.Label(right_frame, text="RSA 私鑰 (解密用):").pack(anchor=tk.W)

        self.txt_priv = tk.Text(right_frame, height=12, width=45, font=('Courier New', 8))

        self.txt_priv.pack(fill=tk.X)


        tk.Label(right_frame, text="RSA 公鑰 (加密用):").pack(anchor=tk.W, pady=(10,0))

        self.txt_pub = tk.Text(right_frame, height=8, width=45, font=('Courier New', 8))

        self.txt_pub.pack(fill=tk.X)


    def generate_keys(self):

        private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)

        

        priv_pem = private_key.private_bytes(

            encoding=serialization.Encoding.PEM,

            format=serialization.PrivateFormat.PKCS8,

            encryption_algorithm=serialization.NoEncryption()

        ).decode()

        

        pub_pem = private_key.public_key().public_bytes(

            encoding=serialization.Encoding.PEM,

            format=serialization.PublicFormat.SubjectPublicKeyInfo

        ).decode()


        self.txt_priv.delete(1.0, tk.END); self.txt_priv.insert(tk.END, priv_pem)

        self.txt_pub.delete(1.0, tk.END); self.txt_pub.insert(tk.END, pub_pem)


    def hybrid_encrypt(self):

        """混合加密:AES 加密內容 + RSA 加密 AES 金鑰"""

        try:

            pub_data = self.txt_pub.get(1.0, tk.END).strip().encode()

            rsa_pub_key = serialization.load_pem_public_key(pub_data)

            

            # 1. 產生臨時的 AES 金鑰

            aes_key = Fernet.generate_key()

            f = Fernet(aes_key)

            

            # 2. 用 AES 加密內容

            message = self.txt_input.get(1.0, tk.END).strip().encode()

            encrypted_content = f.encrypt(message)

            

            # 3. 用 RSA 加密這把 AES 金鑰

            encrypted_aes_key = rsa_pub_key.encrypt(

                aes_key,

                asym_padding.OAEP(mgf=asym_padding.MGF1(hashes.SHA256()), algorithm=hashes.SHA256(), label=None)

            )

            

            # 4. 合併結果 (RSA 加密金鑰長度固定為 256 bytes)

            # 格式:[金鑰長度(4 bytes)] + [加密後的金鑰] + [加密後的內容]

            combined = len(encrypted_aes_key).to_bytes(4, 'big') + encrypted_aes_key + encrypted_content

            

            self.txt_input.delete(1.0, tk.END)

            self.txt_input.insert(tk.END, combined.hex())

            messagebox.showinfo("成功", "混合加密完成!內容已包含加密金鑰。")

        except Exception as e:

            messagebox.showerror("錯誤", f"加密失敗: {e}")


    def hybrid_decrypt(self):

        """混合解密:RSA 解密出 AES 金鑰 + AES 解密內容"""

        try:

            priv_data = self.txt_priv.get(1.0, tk.END).strip().encode()

            rsa_priv_key = serialization.load_pem_private_key(priv_data, password=None)

            

            combined = bytes.fromhex(self.txt_input.get(1.0, tk.END).strip())

            

            # 1. 拆分資料

            key_len = int.from_bytes(combined[:4], 'big')

            encrypted_aes_key = combined[4:4+key_len]

            encrypted_content = combined[4+key_len:]

            

            # 2. 用 RSA 私鑰解密出 AES 金鑰

            aes_key = rsa_priv_key.decrypt(

                encrypted_aes_key,

                asym_padding.OAEP(mgf=asym_padding.MGF1(hashes.SHA256()), algorithm=hashes.SHA256(), label=None)

            )

            

            # 3. 用還原的 AES 金鑰解密內容

            f = Fernet(aes_key)

            decrypted_content = f.decrypt(encrypted_content)

            

            self.txt_input.delete(1.0, tk.END)

            self.txt_input.insert(tk.END, decrypted_content.decode())

        except Exception as e:

            messagebox.showerror("錯誤", "解密失敗!請檢查私鑰或加密封包。")


if __name__ == "__main__":

    root = tk.Tk()

    app = HybridEncryptionApp(root)

    root.mainloop()


沒有留言:

張貼留言

CRC(循環冗餘檢查)

  CRC(循環冗餘檢查) 完整的 CRC(循環冗餘檢查)逐步演示器 。它支援自定義 生成多項式 與 資料位元流 ,並透過「下一步」按鈕展示二進制長除法(XOR 運算)的過程。 二進制長除法模擬 : CRC 的核心是模二除法(Modulo-2 Division),實務上就是不斷進...