Python 混合加密
結合這兩種加密方式感興趣,這在密碼學中稱為 「混合加密系統」(Hybrid Cryptosystem)。
這種方式結合了兩者的優點:
AES 的速度:用來加密真正的巨量資料。
RSA 的安全性:用來安全地傳遞那把 AES 金鑰。
混合加密程式碼實現
自動處理:產生隨機 AES 金鑰 --> 用 AES 加密內容 --> 用 RSA 公鑰加密該 AES 金鑰。
這才是業界標準?
打破長度限制:你現在可以在左側輸入一萬字,RSA 也不會報錯,因為 RSA 只有加密那把小小的 AES 金鑰。
安全傳輸:在現實中,你會把 公鑰 給朋友。朋友用公鑰加密後傳給你一串 Hex。雖然 Hex 裡包含了解密金鑰,但只有你有 私鑰 能把金鑰取出來,其他人拿到 Hex 也沒用。
自動化:使用者不需要手動輸入 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()
沒有留言:
張貼留言