AES加密算法詳細加密步驟代碼實現--身份證號碼加解密系統

系統概述

本系統是一個基于AES-256-CBC加密算法的身份證號碼加解密工具(手搓底層步驟),針對的是上一篇文章對的AES加密原理的講解,雖說是演示,但功能完善,可單獨提供接口給項目調用,采用Python開發,具有圖形化用戶界面。系統實現了完整的AES-256加密算法,支持多密鑰管理,并提供了安全可靠的身份證號碼加密和解密功能。

源碼請查看頂部綁定資源完整源碼文件

或底部源碼自行拷貝

上一篇文章鏈接:

AES加密算法原理講解--基于AES-256加密算法實現身份證號碼的加解密程序項目講解_aes256 64位key反算密碼如何實現-CSDN博客

主要特性

  • 高強度加密:采用AES-256-CBC加密模式,提供高級別的數據安全保護
  • 完整實現:從底層實現AES算法的所有組件,包括S盒、輪常量、密鑰擴展等
  • 多密鑰支持:支持生成、導入和管理多個加密密鑰
  • 密鑰指紋識別:通過SHA256哈希生成密鑰指紋,確保密鑰匹配
  • 歷史記錄管理:自動保存加解密歷史,避免重復操作
  • 現代化界面:基于CustomTkinter的美觀用戶界面,支持明暗主題切換

技術架構

核心算法組件

1. AES-256核心實現

AES256類是系統的核心加密引擎,實現了完整的AES-256算法:

  • 字節替換(SubBytes):使用標準S盒進行非線性字節替換
  • 行移位(ShiftRows):對狀態矩陣的行進行循環移位
  • 列混淆(MixColumns):通過矩陣乘法實現列間數據擴散
  • 輪密鑰加(AddRoundKey):將輪密鑰與狀態矩陣異或
  • 密鑰擴展:將256位主密鑰擴展為15個128位輪密鑰
2. CBC模式封裝

AES256_CBC類實現了密碼塊鏈接模式:

  • PKCS7填充:自動處理數據塊對齊
  • 初始向量(IV):每次加密生成隨機16字節IV
  • 鏈式加密:前一個密文塊參與下一個明文塊的加密
3. 密鑰管理系統
  • JSON格式存儲:密鑰以JSON格式持久化存儲
  • 時間戳記錄:記錄每個密鑰的生成時間
  • 指紋驗證:使用SHA256前4字節作為密鑰指紋
  • 自動匹配:解密時自動匹配正確的密鑰

系統安裝與運行

環境要求

# 必需的Python包,但是只有最后一個需要安裝,其余的不需要(內置)環境為python3.7以上
import datetime
import json
import os
import base64
import hashlib
import tkinter as tk
from tkinter import messagebox, simpledialog, ttk
import customtkinter as ctk

安裝步驟

  1. 安裝CustomTkinter
  • pip install customtkinter
  1. 運行程序
  • python AES-256-CBC.py(代碼命令)

詳細操作指南

主界面功能

啟動程序后,您將看到簡潔的主界面,包含兩個主要功能按鈕:

  • 加密身份證:進入身份證號碼加密功能
  • 解密身份證:進入密文解密功能

加密操作流程

1. 進入加密界面

點擊"加密身份證"按鈕,進入加密功能界面。界面包含以下區域:

  • 密鑰管理區域:顯示當前密鑰指紋,提供密鑰生成和導入功能
  • 輸入區域:身份證號碼輸入框
  • 輸出區域:顯示加密結果
  • 密鑰歷史區域:顯示所有歷史密鑰,支持雙擊切換

2. 密鑰管理

生成新密鑰

  • 點擊"生成新密鑰"按鈕
  • 系統自動生成256位隨機密鑰
  • 密鑰自動保存到aes_keys.json文件
  • 界面顯示新密鑰的指紋信息

導入自定義密鑰

  • 點擊"導入密鑰"按鈕
  • 在彈出對話框中輸入64位十六進制密鑰(32字節)
  • 系統驗證密鑰格式并檢查是否重復
  • 成功導入后更新當前使用的密鑰

切換歷史密鑰

  • 在密鑰歷史表格中雙擊任意密鑰記錄
  • 系統自動切換到選中的密鑰
  • 當前密鑰指紋顯示更新
3. 執行加密
  1. 輸入身份證號碼
    • 在輸入框中輸入18位身份證號碼
    • 系統自動驗證格式(前17位數字,第18位數字或X)
  2. 點擊加密按鈕
    • 系統生成隨機16字節初始向量(IV)
    • 使用當前密鑰執行AES-256-CBC加密
    • 組合IV、密鑰指紋和密文
    • 進行Base64編碼便于存儲和傳輸
  3. 查看結果
    • 加密成功后,密文顯示在輸出區域
    • 密文自動保存到ciphertext1.txt文件
    • 每個密文占用一行,便于批量管理
4. 加密數據格式

生成的密文采用以下格式:

[16字節IV] + [4字節密鑰指紋] + [實際密文數據]

經過Base64編碼后的最終格式便于存儲和傳輸。

解密操作流程

1. 進入解密界面

點擊"解密身份證"按鈕,進入解密功能界面。界面包含:

  • 密鑰文件路徑顯示:顯示密鑰存儲文件的絕對路徑
  • 當前密鑰指紋顯示:顯示正在使用的密鑰信息
  • 文件操作區域:密文文件加載和輸入清空功能
  • 密文列表:顯示已保存的所有密文
  • 密文輸入區域:手動輸入或顯示選中的密文
  • 解密按鈕區域:默認密鑰和自定義密鑰解密選項
  • 結果輸出區域:顯示解密結果

2. 加載密文數據

從文件加載

  • 點擊"選擇密文文件"按鈕
  • 系統自動讀取ciphertext1.txt文件
  • 所有密文顯示在列表中(顯示前30個字符)
  • 雙擊列表項可將完整密文加載到輸入區域

手動輸入

  • 直接在密文輸入區域粘貼或輸入Base64編碼的密文
  • 支持多行密文輸入
3. 執行解密

使用默認密鑰解密

  1. 確保密文已輸入到輸入區域
  2. 點擊"使用默認密鑰解密"按鈕
  3. 系統自動:
    • 解析密文中的密鑰指紋
    • 在密鑰庫中查找匹配的密鑰
    • 提取IV和實際密文數據
    • 執行AES-256-CBC解密
    • 顯示解密后的身份證號碼

使用自定義密鑰解密

  1. 點擊"使用自定義密鑰解密"按鈕
  2. 在彈出對話框中輸入64位十六進制密鑰
  3. 系統驗證密鑰與密文指紋是否匹配
  4. 匹配成功則執行解密并顯示結果
4. 解密結果處理
  • 成功解密:在結果區域顯示"解密成功!身份證號碼: [號碼]"
  • 自動記錄:解密記錄保存到plaintext_history.json文件
  • 重復檢測:系統檢測是否已解密過相同密文,避免重復記錄
  • 錯誤處理:密鑰不匹配或數據損壞時顯示具體錯誤信息

文件系統說明

核心文件

  1. AES-256-CBC.py:主程序文件,包含所有功能實現
  2. aes_keys.json:密鑰存儲文件,JSON格式
  3. ciphertext1.txt:加密后的密文存儲文件
  4. plaintext_history.json:解密歷史記錄文件

密鑰文件格式

[
??{
????"timestamp": "2024-01-15 10:30:45",
????"key": "64位十六進制密鑰字符串",
????"fingerprint": "8位十六進制指紋"
??}
]

解密歷史格式

[
??{
????"timestamp": "2024-01-15 10:35:20",
????"plaintext": "解密后的身份證號碼",
????"ciphertext": "原始密文",
????"key_fingerprint": "使用的密鑰指紋",
????"key_type": "default或custom"
??}
]

安全特性

加密安全性

  1. AES-256標準:采用美國國家標準技術研究所(NIST)認證的AES-256算法
  2. CBC模式:密碼塊鏈接模式提供更強的安全性
  3. 隨機IV:每次加密使用不同的初始向量,防止相同明文產生相同密文
  4. 密鑰指紋:SHA256哈希確保密鑰完整性驗證

數據保護

  1. 本地存儲:所有數據存儲在本地,不涉及網絡傳輸
  2. 密鑰分離:密鑰與密文分別存儲,提高安全性
  3. 格式驗證:嚴格的輸入格式驗證防止無效數據
  4. 錯誤處理:完善的異常處理機制保護系統穩定性

常見問題解答

Q1: 忘記密鑰怎么辦?

:如果忘記了自定義密鑰,可以通過以下方式找回:

  1. 查看aes_keys.json文件中的歷史密鑰
  2. 根據密鑰指紋匹配正確的密鑰
  3. 如果密鑰文件丟失,則無法恢復加密數據

Q2: 密文文件損壞如何處理?

  1. 檢查密文是否為完整的Base64編碼
  2. 確認密文長度是否正確(至少20字節的Base64編碼)
  3. 驗證使用的密鑰是否與加密時一致
  4. 如果數據確實損壞,則無法恢復

Q3: 如何備份重要數據?

:建議定期備份以下文件:

  1. aes_keys.json?- 密鑰文件(最重要)
  2. ciphertext1.txt?- 密文文件
  3. plaintext_history.json?- 解密歷史

Q4: 程序運行出錯怎么辦?

  1. 檢查Python環境和依賴包是否正確安裝
  2. 確認CustomTkinter版本兼容性
  3. 查看錯誤提示信息,通常會指出具體問題
  4. 刪除損壞的配置文件,程序會自動重新創建

使用建議

最佳實踐

  1. 定期備份密鑰:將aes_keys.json文件備份到安全位置
  2. 使用強密鑰:導入自定義密鑰時確保隨機性和復雜度
  3. 驗證結果:加密后立即測試解密確保數據完整性
  4. 安全存儲:將密鑰文件存儲在加密的存儲設備中

性能優化

  1. 批量操作:對于大量數據,建議分批處理
  2. 內存管理:處理大文件時注意內存使用情況
  3. 文件清理:定期清理不需要的歷史記錄文件


注意:本系統僅用于合法的數據保護目的,請遵守相關法律法規,不得用于非法用途。加密的身份證信息應當妥善保管,防止泄露。

源碼:

import datetime
import json
import os
import base64
import hashlib
import tkinter as tk
from tkinter import messagebox, simpledialog, ttk
import customtkinter as ctk# 明文保存文件路徑 - 用于存儲解密后的明文記錄
PLAINTEXT_FILE = "plaintext_history.json"# 設置CustomTkinter的外觀模式和默認顏色主題
ctk.set_appearance_mode("System")  # 系統模式,自動適應明暗主題
ctk.set_default_color_theme("blue")  # 使用藍色主題# ====================== AES-256 完整實現 ======================
# ----------------------- 常量定義 -----------------------
# 加密字節代換表(S盒),AES標準定義的非線性替換表,用于加密時的字節替換
# 每個字節(0x00-0xFF)對應一個替換值,提供非線性變換特性
S_BOX = (0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
)# 解密字節代換表(逆S盒),用于解密時的字節逆替換
# 與S_BOX互為逆操作,確保sbox[inv_sbox[x]] = x
INV_S_BOX = (0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB,0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB,0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06,0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B,0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E,0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B,0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F,0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF,0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D
)# 輪常量表(Round Constants),用于密鑰擴展算法中生成輪密鑰
# 每個元素對應GF(2?)上的x^(i-1)值,用于消除密鑰的對稱性
RCON = (0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36)# 加密列混淆左乘矩陣(標準AES定義)
# 用于加密時對每列進行矩陣乘法,實現擴散效果
MIX_MATRIX = [[0x02, 0x03, 0x01, 0x01],[0x01, 0x02, 0x03, 0x01],[0x01, 0x01, 0x02, 0x03],[0x03, 0x01, 0x01, 0x02]
]
# 解密列混淆左乘矩陣(標準AES逆矩陣)
# 用于解密時恢復原始列數據
INV_MIX_MATRIX = [[0x0E, 0x0B, 0x0D, 0x09],[0x09, 0x0E, 0x0B, 0x0D],[0x0D, 0x09, 0x0E, 0x0B],[0x0B, 0x0D, 0x09, 0x0E]
]# ----------------------- 核心算法類 -----------------------
class AES256:def __init__(self, key):# 初始化時生成輪密鑰,key為32字節(256位)原始密鑰self.round_keys = self.key_expansion(key)@staticmethoddef sub_bytes(s):"""加密字節替換:使用S盒替換狀態矩陣中的每個字節"""for i in range(4):  # 遍歷4行for j in range(4):  # 遍歷4列s[i][j] = S_BOX[s[i][j]]  # 查表替換@staticmethoddef inv_sub_bytes(s):"""解密字節逆替換:使用逆S盒恢復原始字節"""for i in range(4):for j in range(4):s[i][j] = INV_S_BOX[s[i][j]]@staticmethoddef shift_rows(s):"""加密行移位:對每行進行循環左移操作"""# 第0行不移位s[1] = s[1][1:] + s[1][:1]  # 第1行左移1字節s[2] = s[2][2:] + s[2][:2]  # 第2行左移2字節s[3] = s[3][3:] + s[3][:3]  # 第3行左移3字節@staticmethoddef inv_shift_rows(s):"""解密行逆移位:恢復原始行位置"""# 第0行不變s[1] = s[1][3:] + s[1][:3]  # 第1行右移1字節(等同左移3字節)s[2] = s[2][2:] + s[2][:2]  # 第2行右移2字節(等同左移2字節)s[3] = s[3][1:] + s[3][:1]  # 第3行右移3字節(等同左移1字節)def mix_columns(self, s):"""加密列混淆:對每列進行矩陣乘法"""for i in range(4):  # 處理每一列col = [s[0][i], s[1][i], s[2][i], s[3][i]]  # 提取列數據new_col = [0] * 4  # 初始化新列# 矩陣乘法(4x4矩陣 * 4x1列向量)for row in range(4):for elem in range(4):# 累加伽羅瓦域乘法結果new_col[row] ^= self.ffmul(MIX_MATRIX[row][elem], col[elem])# 更新狀態矩陣s[0][i] = new_col[0]s[1][i] = new_col[1]s[2][i] = new_col[2]s[3][i] = new_col[3]# 下面為手動展開計算可以消除循環判斷的開銷。# for i in range(4):#     s0 = s[0][i]#     s1 = s[1][i]#     s2 = s[2][i]#     s3 = s[3][i]#     s[0][i] = self.ffmul(0x02, s0) ^ self.ffmul(0x03, s1) ^ s2 ^ s3#     s[1][i] = s0 ^ self.ffmul(0x02, s1) ^ self.ffmul(0x03, s2) ^ s3#     s[2][i] = s0 ^ s1 ^ self.ffmul(0x02, s2) ^ self.ffmul(0x03, s3)#     s[3][i] = self.ffmul(0x03, s0) ^ s1 ^ s2 ^ self.ffmul(0x02, s3)def inv_mix_columns(self, s):"""解密列混淆:使用逆矩陣恢復原始列數據"""for i in range(4):  # 處理每一列col = [s[0][i], s[1][i], s[2][i], s[3][i]]new_col = [0] * 4for row in range(4):for elem in range(4):new_col[row] ^= self.ffmul(INV_MIX_MATRIX[row][elem], col[elem])# 更新狀態矩陣s[0][i] = new_col[0]s[1][i] = new_col[1]s[2][i] = new_col[2]s[3][i] = new_col[3]# for i in range(4):#     s0 = s[0][i]#     s1 = s[1][i]#     s2 = s[2][i]#     s3 = s[3][i]#     s[0][i] = self.ffmul(0x0e, s0) ^ self.ffmul(0x0b, s1) ^ self.ffmul(0x0d, s2) ^ self.ffmul(0x09, s3)#     s[1][i] = self.ffmul(0x09, s0) ^ self.ffmul(0x0e, s1) ^ self.ffmul(0x0b, s2) ^ self.ffmul(0x0d, s3)#     s[2][i] = self.ffmul(0x0d, s0) ^ self.ffmul(0x09, s1) ^ self.ffmul(0x0e, s2) ^ self.ffmul(0x0b, s3)#     s[3][i] = self.ffmul(0x0b, s0) ^ self.ffmul(0x0d, s1) ^ self.ffmul(0x09, s2) ^ self.ffmul(0x0e, s3)@staticmethoddef ffmul(a, b):"""伽羅瓦域乘法(GF(2?)):計算a和b在有限域上的乘積"""p = 0for _ in range(8):  # 遍歷b的每一位if b & 1:  # 如果最低位為1p ^= a  # 異或累加a <<= 1  # 左移相當于乘以xif a & 0x100:  # 處理模溢出a ^= 0x11b  # 異或不可約多項式x? + x? + x3 + x + 1(0x11b)b >>= 1  # 處理下一位return pdef key_expansion(self, key):"""密鑰擴展:將32字節密鑰擴展為15個輪密鑰(每個16字節)"""key_bytes = list(key)  # 將密鑰轉換為字節列表nk = 8  # AES-256的初始密鑰字數(256位=8字)nr = 14  # AES-256的總輪數# 初始密鑰復制expanded_key = key_bytes.copy()# 擴展循環(生成后續輪密鑰)for i in range(nk, 4 * (nr + 1)):temp = expanded_key[4 * i - 4: 4 * i]  # 獲取前4字節# 每8個字的特殊處理(AES-256特有)if i % nk == 0:# RotWord:循環左移1字節temp = temp[1:] + temp[:1]# SubWord:S盒替換temp = [S_BOX[b] for b in temp]# 異或輪常數temp[0] ^= RCON[i // nk - 1]elif nk == 8 and i % nk == 4:# 中間輪的特殊處理(每8個字進行一次S盒替換)temp = [S_BOX[b] for b in temp]# 生成新字:與前nk個字異或new_word = [expanded_key[4 * (i - nk)] ^ temp[0],expanded_key[4 * (i - nk) + 1] ^ temp[1],expanded_key[4 * (i - nk) + 2] ^ temp[2],expanded_key[4 * (i - nk) + 3] ^ temp[3]]expanded_key.extend(new_word)  # 添加到擴展密鑰# 分割為15個輪密鑰(每個16字節)return [expanded_key[i * 16: (i + 1) * 16] for i in range(nr + 1)]def encrypt_block(self, plaintext):"""加密單個數據塊(16字節)"""# 將輸入字節轉換為4x4狀態矩陣state = [list(plaintext[i:i + 4]) for i in range(0, 16, 4)]# 初始輪密鑰加self.add_round_key(state, self.round_keys[0])# 主輪次(共14輪)for i in range(1, 14):self.sub_bytes(state)  # 字節替換self.shift_rows(state)  # 行移位self.mix_columns(state)  # 列混淆self.add_round_key(state, self.round_keys[i])  # 輪密鑰加# 最終輪(無列混淆)self.sub_bytes(state)self.shift_rows(state)self.add_round_key(state, self.round_keys[14])# 將狀態矩陣轉換回字節序列return bytes(sum(state, []))def decrypt_block(self, ciphertext):"""解密單個數據塊(16字節)"""state = [list(ciphertext[i:i + 4]) for i in range(0, 16, 4)]# 初始輪密鑰加(使用最后一個輪密鑰)self.add_round_key(state, self.round_keys[14])  # 輪密鑰加self.inv_shift_rows(state)  # 逆行移位self.inv_sub_bytes(state)  # 逆字節替換# 主輪次(逆序處理)for i in range(13, 0, -1):self.add_round_key(state, self.round_keys[i])  # 輪密鑰加self.inv_mix_columns(state)  # 逆列混淆self.inv_shift_rows(state)  # 逆行移位self.inv_sub_bytes(state)  # 逆字節替換# 最終輪密鑰加self.add_round_key(state, self.round_keys[0])return bytes(sum(state, []))@staticmethoddef add_round_key(s, k):"""輪密鑰加:將輪密鑰與狀態矩陣異或"""for i in range(4):for j in range(4):# 按列順序訪問輪密鑰s[i][j] ^= k[i + j * 4]# ----------------------- CBC 模式封裝 -----------------------
class AES256_CBC:def __init__(self, key):# 初始化AES-256核心算法實例self.aes = AES256(key)  # 傳入密鑰初始化加密器@staticmethoddef pkcs7_pad(data):"""PKCS7填充:將數據填充至16字節的倍數"""pad_len = 16 - (len(data) % 16)  # 計算需要填充的字節數return data + bytes([pad_len] * pad_len)  # 填充重復的字節值為pad_len@staticmethoddef pkcs7_unpad(data):"""PKCS7去除填充:驗證并去除填充數據"""pad_len = data[-1]  # 最后一個字節為填充長度return data[:-pad_len]  # 去除填充部分def encrypt(self, plaintext, iv):"""CBC模式加密:處理整個明文并生成密文"""padded = self.pkcs7_pad(plaintext)  # 填充數據# 將數據分割為16字節的塊blocks = [padded[i:i + 16] for i in range(0, len(padded), 16)]cipher_blocks = []  # 存儲加密后的塊prev = iv  # 初始向量作為首個塊的異或值for block in blocks:# CBC模式核心:與前一個密文塊(或IV)異或后再加密xored = bytes([b1 ^ b2 for b1, b2 in zip(prev, block)])encrypted = self.aes.encrypt_block(xored)cipher_blocks.append(encrypted)prev = encrypted  # 更新前一個塊為當前密文return b''.join(cipher_blocks)  # 拼接所有密文塊def decrypt(self, ciphertext, iv):"""CBC模式解密:處理密文并恢復原始明文"""# 分割密文為16字節塊blocks = [ciphertext[i:i + 16] for i in range(0, len(ciphertext), 16)]plain_blocks = []prev = iv  # 初始向量用于首個塊for block in blocks:# 解密當前塊decrypted = self.aes.decrypt_block(block)# 與前一個密文塊異或得到原始明文塊plain = bytes([b1 ^ b2 for b1, b2 in zip(prev, decrypted)])plain_blocks.append(plain)prev = block  # 更新前一個塊為當前密文(注意是原始密文,非解密結果)# 拼接并去除填充return self.pkcs7_unpad(b''.join(plain_blocks))# ====================== 應用程序接口 ======================
KEY_FILE = "aes_keys.json"  # JSON格式存儲多密鑰
CIPHER_FILE = "ciphertext1.txt"  # 密文存儲文件名def generate_aes_key():"""生成并保存隨機AES-256密鑰到JSON文件"""import datetimekey = os.urandom(32)print(f'當前使用的初始密鑰為:{key.hex()}')timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")key_hex = key.hex()fingerprint = hashlib.sha256(key).digest()[:4].hex()# 讀取現有密鑰或初始化空列表try:with open(KEY_FILE, "r") as f:keys = json.load(f)except (FileNotFoundError, json.JSONDecodeError):keys = []# 添加新密鑰條目keys.append({"timestamp": timestamp,"key": key_hex,"fingerprint": fingerprint})# 保存到文件with open(KEY_FILE, "w") as f:json.dump(keys, f, indent=2)return keydef import_custom_key(key_str):"""導入自定義密鑰到JSON文件"""# 驗證輸入格式:必須是64位十六進制字符(32字節)if len(key_str) != 64 or not all(c in "0123456789abcdef" for c in key_str):raise ValueError("密鑰必須是64位十六進制字符")  # 64位十六進制也就是32字節# 將十六進制字符串轉換為字節對象(32字節)key = bytes.fromhex(key_str)# 生成時間戳(用于記錄密鑰創建時間)timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")# 生成密鑰指紋(SHA256哈希前4字節的十六進制)fingerprint = hashlib.sha256(key).digest()[:4].hex()# 讀取現有密鑰文件try:with open(KEY_FILE, "r") as f:keys = json.load(f)  # 嘗試加載JSON格式的密鑰列表except (FileNotFoundError, json.JSONDecodeError):keys = []  # 文件不存在或格式錯誤時初始化空列表# 檢查密鑰是否已存在(通過十六進制字符串比對)if any(entry["key"] == key_str for entry in keys):raise ValueError("該密鑰已存在")# 添加新密鑰條目到列表keys.append({"timestamp": timestamp,  # 記錄創建時間"key": key_str,  # 原始十六進制密鑰字符串"fingerprint": fingerprint  # 指紋用于快速識別})print(f'當前使用的初始密鑰為:{key_str}')# 寫回更新后的密鑰列表到文件with open(KEY_FILE, "w") as f:json.dump(keys, f, indent=2)  # 帶縮進的JSON格式便于閱讀return key  # 返回字節類型的密鑰對象供后續使用def load_aes_key():"""加載最新密鑰,沒有則自動生成返回:bytes: 最新密鑰的字節形式(32字節)處理邏輯:1. 檢查密鑰文件是否存在,不存在則生成新密鑰2. 讀取并解析JSON格式的密鑰文件3. 異常處理:文件損壞時刪除并生成新密鑰4. 按時間戳降序排列,返回最新密鑰"""if not os.path.exists(KEY_FILE):return generate_aes_key()  # 無密鑰文件時生成新密鑰try:with open(KEY_FILE, "r") as f:keys = json.load(f)  # 加載JSON格式的密鑰列表if not keys:  # 空文件檢查return generate_aes_key()# 按時間戳降序排序(最新密鑰在前)keys_sorted = sorted(keys, key=lambda x: x["timestamp"], reverse=True)return bytes.fromhex(keys_sorted[0]["key"])  # 轉換最新密鑰為字節except Exception as e:  # 捕獲JSON解析錯誤等異常messagebox.showwarning("錯誤", f"密鑰文件損壞: {str(e)}")os.remove(KEY_FILE)  # 刪除損壞文件return generate_aes_key()  # 生成替代密鑰def get_all_keys():"""獲取所有密鑰信息返回:list: 包含所有密鑰字典的列表,每個字典包含:- timestamp: 生成時間字符串- key: 64位十六進制密鑰字符串- fingerprint: 4字節指紋的十六進制異常處理:- 文件不存在返回空列表- JSON解析失敗視為空列表"""try:with open(KEY_FILE, "r") as f:return json.load(f)  # 直接返回解析后的密鑰列表except (FileNotFoundError, json.JSONDecodeError):  # 處理文件異常return []  # 返回空列表保持程序健壯性def get_key_fingerprint(key):"""生成密鑰指紋:SHA256哈希的前4字節參數:key (bytes): 原始密鑰字節返回:bytes: 4字節指紋(用于密文組合)說明:- print用于調試顯示當前指紋- 前4字節在保證唯一性的前提下縮短數據長度"""print(f'當前指紋為:{hashlib.sha256(key).digest()[:4].hex()}')  # 調試輸出return hashlib.sha256(key).digest()[:4]  # 取哈希值前4字節作為指紋def encrypt_id_number(plaintext, key):"""加密身份證號:生成IV并返回Base64編碼的完整密文"""iv = os.urandom(16)  # 生成16字節隨機初始向量,每塊為16字節,所以生成16字節的iv,用于與第一塊異或print(f'本次加密的初始化向量為:{iv.hex()}')cipher = AES256_CBC(key)ciphertext = cipher.encrypt(plaintext.encode(), iv)  # 執行加密# 組合IV、密鑰指紋和密文combined = iv + get_key_fingerprint(key) + ciphertextprint(f'未進行base64編碼前的組合:{combined.hex()}')return base64.b64encode(combined).decode()  # Base64編碼便于存儲def decrypt_id_number(ciphertext_b64):"""解密Base64編碼的密文:驗證指紋并返回明文"""combined = base64.b64decode(ciphertext_b64)  # 解碼# 拆分各部分:前16字節IV,接下來4字節指紋,剩余為密文iv, fingerprint, ciphertext = combined[:16], combined[16:20], combined[20:]keys = get_all_keys()for entry in keys:if bytes.fromhex(entry["fingerprint"]) == fingerprint:  # 匹配指紋cipher = AES256_CBC(bytes.fromhex(entry["key"]))key = bytes.fromhex(entry["key"])  # 所用密鑰return cipher.decrypt(ciphertext, iv).decode(), key  # 執行解密轉換為字符串并返回結果,同時返回密鑰raise ValueError("未找到匹配的密鑰")def decrypt_with_key(ciphertext_b64, key):"""使用指定密鑰解密Base64編碼的密文:驗證指紋并返回明文"""combined = base64.b64decode(ciphertext_b64)  # 解碼# 拆分各部分:前16字節IV,接下來4字節指紋,剩余為密文iv, fingerprint, ciphertext = combined[:16], combined[16:20], combined[20:]# 驗證密鑰指紋匹配if fingerprint != get_key_fingerprint(key):raise ValueError("密鑰與密文不匹配")cipher = AES256_CBC(key)plaintext = cipher.decrypt(ciphertext, iv)  # 執行解密return plaintext.decode()  # 轉換為字符串# ====================== GUI 界面部分 ======================
class MainPage(ctk.CTkFrame):'''主界面'''def __init__(self, master, show_encrypt, show_decrypt):super().__init__(master)# 創建標題標簽title_label = ctk.CTkLabel(self,text="身份證號加解密系統",font=ctk.CTkFont(family="微軟雅黑", size=24, weight="bold"),text_color=("gray10", "gray90"))title_label.pack(pady=30)# 創建按鈕容器button_frame = ctk.CTkFrame(self, fg_color="transparent")button_frame.pack(pady=20)# 加密按鈕encrypt_btn = ctk.CTkButton(button_frame,text="🔒 加密身份證",command=show_encrypt,width=200,height=40,font=ctk.CTkFont(size=14),fg_color=("blue", "blue"),hover_color=("darkblue", "darkblue"),corner_radius=10)encrypt_btn.pack(pady=10)# 解密按鈕decrypt_btn = ctk.CTkButton(button_frame,text="🔓 解密身份證",command=show_decrypt,width=200,height=40,font=ctk.CTkFont(size=14),fg_color=("green", "green"),hover_color=("darkgreen", "darkgreen"),corner_radius=10)decrypt_btn.pack(pady=10)class KeyManagementMixin:"""密鑰管理功能混入類功能:- 提供密鑰生成、導入的GUI控件- 管理密鑰顯示和狀態更新- 集成到需要密鑰管理功能的頁面中特性:- 可復用組件,通過繼承方式為其他界面添加密鑰管理能力- 自動同步密鑰狀態到主應用實例"""def create_key_controls(self, parent):"""創建密鑰管理界面組件參數:parent: 父容器控件構建:1. 創建包含兩個操作按鈕的水平工具欄(生成/導入)2. 創建密鑰指紋顯示標簽3. 布局到父容器中"""key_frame = ctk.CTkFrame(parent, fg_color=("gray90", "gray15"), corner_radius=10)# 密鑰操作按鈕容器(水平排列)btn_frame = ctk.CTkFrame(key_frame, fg_color="transparent")# 生成新密鑰按鈕ctk.CTkButton(btn_frame,text="生成新密鑰",command=self.generate_new_key,width=120,height=35,font=ctk.CTkFont(size=14),fg_color=("blue", "blue"),hover_color=("darkblue", "darkblue"),corner_radius=8).pack(side="left", padx=5)# 導入密鑰按鈕ctk.CTkButton(btn_frame,text="導入密鑰",command=self.import_key_dialog,width=120,height=35,font=ctk.CTkFont(size=14),fg_color=("green", "green"),hover_color=("darkgreen", "darkgreen"),corner_radius=8).pack(side="left", padx=5)btn_frame.pack(pady=10)# 密鑰指紋顯示標簽self.fingerprint_label = ctk.CTkLabel(key_frame,text="",font=ctk.CTkFont(size=14),anchor="w")self.fingerprint_label.pack(anchor="w", padx=10, pady=5)# 將密鑰管理面板打包到父容器key_frame.pack(fill="x", padx=10, pady=10)def generate_new_key(self):"""執行密鑰生成流程流程:1. 調用generate_aes_key生成新密鑰(同時寫入文件)2. 更新主應用實例的當前密鑰3. 刷新界面顯示4. 彈出操作成功提示"""new_key = generate_aes_key()  # 生成并持久化新密鑰self.master.key = new_key  # 更新主應用的密鑰引用self.update_key_display(new_key)  # 刷新指紋顯示messagebox.showinfo("成功", "新密鑰已生成并保存!")  # 用戶反饋def import_key_dialog(self):"""處理密鑰導入操作流程:1. 彈出輸入對話框獲取密鑰字符串2. 輸入為空時直接返回3. 調用import_custom_key驗證并存儲密鑰4. 成功更新主應用密鑰,失敗顯示錯誤詳情"""key_str = simpledialog.askstring("導入密鑰", "請輸入64位十六進制密鑰:")  # 64位十六進制也就是32字節if not key_str: return  # 用戶取消輸入try:# 轉換輸入為小寫并驗證格式key = import_custom_key(key_str.lower())  # 可能拋出ValueErrorself.master.key = key  # 更新主應用密鑰self.update_key_display(key)  # 刷新顯示messagebox.showinfo("成功", "密鑰導入成功!")except Exception as e:# 顯示具體錯誤信息(如格式錯誤、已存在等)messagebox.showerror("錯誤", f"密鑰導入失敗:{str(e)}")def update_key_display(self, key):"""更新密鑰指紋顯示參數:key: bytes類型密鑰(32字節)操作:1. 計算密鑰的SHA256指紋(取前4字節)2. 轉換為十六進制字符串3. 更新標簽文本"""fingerprint = get_key_fingerprint(key).hex()  # 獲取4字節指紋的hex字符串self.fingerprint_label.config(text=f"當前密鑰指紋:{fingerprint}")  # 更新顯示class EncryptPage(KeyManagementMixin, ctk.CTkFrame):"""加密功能主界面,繼承密鑰管理功能和Frame容器特性"""def __init__(self, master, key, go_back):# 初始化父類框架和混入類super().__init__(master, fg_color="transparent")# 保持對主應用窗口的引用self.master = master# 存儲當前使用的密鑰(bytes類型)self.key = key# 構建界面元素self.build_ui(go_back)# 初始化顯示當前密鑰信息self.update_key_display(key)def build_ui(self, go_back):"""構建界面布局"""# 返回按鈕(右上角定位)ctk.CTkButton(self,text="← 返回",command=go_back,width=100,height=30,corner_radius=8,fg_color=("gray60", "gray30"),hover_color=("gray50", "gray40")).pack(anchor="ne", padx=10)# 創建密鑰管理控件(來自KeyManagementMixin)self.create_key_controls(self)# 輸入區域容器input_frame = ctk.CTkFrame(self, fg_color="transparent")# 身份證號標簽ctk.CTkLabel(input_frame,text="身份證號碼(18位):",font=ctk.CTkFont(size=14)).pack(anchor="w")# 帶實時驗證的輸入框self.entry = ctk.CTkEntry(input_frame,width=300,height=35,placeholder_text="請輸入18位身份證號",font=ctk.CTkFont(size=14),corner_radius=8)self.entry.pack(pady=5)# 加密按鈕ctk.CTkButton(input_frame,text="加密",command=self.encrypt,width=120,height=35,font=ctk.CTkFont(size=14),fg_color=("blue", "blue"),hover_color=("darkblue", "darkblue"),corner_radius=8).pack(pady=10)input_frame.pack(pady=10)# 輸出區域self.output = ctk.CTkTextbox(self,height=100,width=600,font=ctk.CTkFont(size=13),corner_radius=8,border_width=1)self.output.pack(pady=10)self.output.configure(state="disabled")# 創建密鑰歷史面板self.create_key_history()def create_key_history(self):"""初始化密鑰歷史記錄面板"""# 創建帶標題的容器框架self.history_frame = ctk.CTkFrame(self,fg_color=("gray90", "gray15"),corner_radius=10)# 添加標題標簽ctk.CTkLabel(self.history_frame,text="密鑰歷史(雙擊選擇)",font=ctk.CTkFont(size=16, weight="bold")).pack(pady=(10, 5), padx=10, anchor="w")# 由于CustomTkinter沒有直接對應的Treeview組件,我們使用原生tkinter的Treeview# 但是調整其樣式以匹配CustomTkinter的外觀self.tree = tk.ttk.Treeview(self.history_frame,columns=("timestamp", "fingerprint", "key_preview"),show="headings",selectmode="browse",height=6)# 列配置self.tree.column("timestamp", width=180, anchor="w")self.tree.column("fingerprint", width=100, anchor="w")self.tree.column("key_preview", width=120, anchor="w")# 表頭文本設置self.tree.heading("timestamp", text="生成時間")self.tree.heading("fingerprint", text="指紋")self.tree.heading("key_preview", text="密鑰預覽")# 創建垂直滾動條scrollbar = tk.ttk.Scrollbar(self.history_frame,orient="vertical",command=self.tree.yview)self.tree.configure(yscrollcommand=scrollbar.set)# 布局表格和滾動條self.tree.pack(side="left", fill="both", expand=True, padx=10, pady=10)scrollbar.pack(side="right", fill="y", pady=10)self.history_frame.pack(fill="both", expand=True, padx=10, pady=10)# 綁定鼠標雙擊事件self.tree.bind("<Double-1>", self.on_key_selected)# 初始加載歷史數據self.update_key_history()def on_key_selected(self, event):"""處理密鑰選擇事件"""# 獲取選中的第一行(唯一選擇)item = self.tree.selection()[0]# 從條目tag屬性獲取完整HEX密鑰key_hex = self.tree.item(item, "tags")[0]try:# 轉換HEX字符串為字節對象self.master.key = bytes.fromhex(key_hex)# 更新當前頁面顯示self.update_key_display(self.master.key)# 設置選中狀態(藍色高亮)self.tree.selection_set(item)# 聚焦到選中行(灰色背景)self.tree.focus(item)# 操作成功提示messagebox.showinfo("成功", "已切換加密密鑰!")except Exception as e:# 捕獲轉換失敗等異常messagebox.showerror("錯誤", f"密鑰加載失敗: {str(e)}")def update_key_display(self, key):"""更新密鑰信息顯示"""# 生成4字節指紋(HEX字符串)fingerprint = hashlib.sha256(key).digest()[:4].hex()# 截取前8位字符+省略號key_preview = key.hex()[:8] + "..."# 更新標簽顯示self.fingerprint_label.configure(text=f"當前加密密鑰:\n指紋: {fingerprint}\n密鑰預覽: {key_preview}")def update_key_history(self):"""刷新密鑰歷史記錄"""# 清空現有條目for item in self.tree.get_children():self.tree.delete(item)# 獲取所有密鑰并按時間倒序排列keys = sorted(get_all_keys(), key=lambda x: x["timestamp"], reverse=True)# 遍歷插入新數據for entry in keys:# 生成密鑰預覽(前8位+省略號)key_preview = f"{entry['key'][:8]}..."# 插入新行,tag存儲完整HEX密鑰self.tree.insert("",  # 根節點"end",  # 插入位置values=(  # 三列數據entry["timestamp"],entry["fingerprint"],key_preview),tags=(entry["key"],)  # 隱藏數據存儲)def generate_new_key(self):"""生成新密鑰(覆蓋父類方法)"""super().generate_new_key()  # 調用父類生成邏輯app = self.winfo_toplevel()  # 獲取Application實例app.load_key()  # 重新加載最新密鑰self.key = app.key  # 同步當前頁面引用self.update_key_history()  # 刷新歷史記錄self.update_key_display(app.key)  # 更新顯示def import_key_dialog(self):"""導入密鑰(覆蓋父類方法)"""super().import_key_dialog()  # 調用父類導入邏輯app = self.winfo_toplevel()  # 獲取Application實例app.load_key()  # 重新加載密鑰self.update_key_history()  # 刷新歷史面板self.update_key_display(app.key)  # 更新顯示def validate_input(self, text):"""實時驗證身份證輸入參數:text: 當前輸入框內容返回:bool: 是否有效"""# 長度超過18無效# if len(text) > 18:#     return False# 空輸入允許(中間輸入狀態)# if len(text) == 0:#     return True# 前17位必須為數字# if not text[:17].isdigit():#     return False# 第18位校驗(數字或X)# if len(text) == 18 and not (text[17].isdigit() or text[17].lower() == 'x'):#     return Falsereturn Truedef encrypt(self):"""執行加密操作"""# 獲取輸入并轉為大寫id_num = self.entry.get().upper()# 最終長度驗證if len(id_num) != 18:messagebox.showerror("錯誤", "請輸入有效的18位身份證號碼")returnif not id_num[:17].isdigit():messagebox.showerror("錯誤", "前17位必須為數字")returnif not (id_num[17].isdigit() or id_num[17] in ['X', 'x']):messagebox.showerror("錯誤", "第18位必須為數字或X")returntry:# 獲取Application實例(替代直接使用self.master,解決CTkFrame沒有key屬性的問題)app = self.winfo_toplevel()# 使用Application實例中的密鑰進行加密ciphertext = encrypt_id_number(id_num, app.key)# 追加寫入密文文件,每個密文占一行with open(CIPHER_FILE, "a") as f:f.write(ciphertext + "\n")# 顯示操作結果,包括生成的密文self.show_output(f"加密成功!密文已保存\n{ciphertext}")except Exception as e:# 捕獲并顯示加密過程中的任何錯誤messagebox.showerror("錯誤", str(e))def show_output(self, text):"""更新輸出區域內容"""self.output.configure(state="normal")self.output.delete("1.0", "end")self.output.insert("end", text)self.output.configure(state="disabled")class DecryptPage(ctk.CTkFrame):"""解密功能主界面功能:- 顯示密鑰存儲路徑- 加載并選擇加密文件- 支持默認密鑰和自定義密鑰解密- 顯示解密結果- 保存解密記錄到JSON文件"""PLAINTEXT_FILE = "plaintext_history.json"  # 明文保存文件路徑def check_ciphertext_exists(self, ciphertext):"""檢查密文是否已存在于歷史記錄中參數:ciphertext: 要檢查的密文返回:bool: 如果存在返回True,否則返回False"""try:# 檢查明文歷史記錄文件是否存在if not os.path.exists(self.PLAINTEXT_FILE):return False# 讀取歷史記錄文件內容with open(self.PLAINTEXT_FILE, "r") as f:history = json.load(f)# 遍歷歷史記錄,檢查密文是否存在for record in history:if record.get("ciphertext") == ciphertext:return True# 未找到匹配的密文return Falseexcept Exception:# 發生任何錯誤時返回False,確保程序繼續運行return Falsedef save_plaintext_record(self, plaintext, key_fingerprint, key_type, ciphertext):"""保存明文記錄到JSON文件參數:plaintext: 解密后的明文key_fingerprint: 使用的密鑰指紋key_type: 密鑰類型("default"或"custom")ciphertext: 原始密文"""try:# 獲取當前時間并格式化為指定格式current_time = datetime.datetime.now()# 將時間格式化為 "YYYY-MM-DD HH:MM:SS" 格式formatted_time = current_time.strftime("%Y-%m-%d %H:%M:%S")# 創建包含所有必要信息的記錄字典record = {"timestamp": formatted_time,  # 格式化的時間戳"plaintext": plaintext,  # 解密后的明文"ciphertext": ciphertext,  # 原始密文"key_fingerprint": key_fingerprint,  # 使用的密鑰指紋"key_type": key_type  # 密鑰類型(默認或自定義)}# 讀取現有歷史記錄或創建新的記錄列表if os.path.exists(self.PLAINTEXT_FILE):# 如果文件存在,讀取現有記錄with open(self.PLAINTEXT_FILE, "r") as f:history = json.load(f)else:# 如果文件不存在,創建空列表history = []# 將新記錄添加到歷史記錄列表中history.append(record)# 將更新后的歷史記錄寫回文件,使用縮進格式化JSONwith open(self.PLAINTEXT_FILE, "w") as f:json.dump(history, f, indent=2)except Exception as e:# 如果保存過程中出現錯誤,顯示錯誤消息messagebox.showerror("錯誤", f"保存明文記錄失敗: {str(e)}")def __init__(self, master, key, go_back):"""初始化解密頁面參數:master: 父容器(應用主窗口)key: 初始密鑰(bytes)go_back: 返回主界面的回調函數"""super().__init__(master, fg_color="transparent")self.last_custom_key = None  # 緩存最后一次成功使用的自定義密鑰# 顯示密鑰文件絕對路徑ctk.CTkLabel(self,text=f"密鑰文件路徑: {os.path.abspath(KEY_FILE)}",font=ctk.CTkFont(size=12),anchor="w").pack(anchor="nw", padx=10, pady=5)self.cipher_list = []  # 存儲從文件加載的原始密文數據self.key = key  # 當前使用的默認密鑰self.fingerprint_label = None  # 指紋顯示標簽的引用占位self.build_ui(go_back)  # 構建界面元素self.update_fingerprint(self.key)  # 初始化顯示默認密鑰指紋def build_ui(self, go_back):"""構建界面布局"""# 返回按鈕(右上角定位)ctk.CTkButton(self,text="← 返回",command=go_back,width=100,height=30,corner_radius=8,fg_color=("gray60", "gray30"),hover_color=("gray50", "gray40")).pack(anchor="ne", padx=10)# 密鑰指紋顯示標簽self.fingerprint_label = ctk.CTkLabel(self,text="",font=ctk.CTkFont(size=14),anchor="w")self.fingerprint_label.pack(anchor="nw", padx=10, pady=5)# 操作按鈕容器input_frame = ctk.CTkFrame(self, fg_color="transparent")# 文件選擇按鈕ctk.CTkButton(input_frame,text="選擇密文文件",command=self.load_file,width=120,height=35,font=ctk.CTkFont(size=14),fg_color=("blue", "blue"),hover_color=("darkblue", "darkblue"),corner_radius=8).pack(side="left", padx=5)# 清空輸入按鈕ctk.CTkButton(input_frame,text="清空輸入",command=self.clear_input,width=120,height=35,font=ctk.CTkFont(size=14),fg_color=("gray60", "gray30"),hover_color=("gray50", "gray40"),corner_radius=8).pack(side="left", padx=5)input_frame.pack(pady=10)# 密文列表框list_frame = ctk.CTkFrame(self, fg_color=("gray90", "gray15"), corner_radius=10)list_frame.pack(pady=10, padx=20, fill="x")ctk.CTkLabel(list_frame,text="已保存的密文:",font=ctk.CTkFont(size=14)).pack(anchor="w", padx=10, pady=5)# 使用傳統Listbox,因為CustomTkinter沒有直接對應的組件self.listbox = tk.Listbox(list_frame,height=6,width=70,bg=("gray95" if ctk.get_appearance_mode() == "light" else "gray20"),fg=("black" if ctk.get_appearance_mode() == "light" else "white"),font=("Segoe UI", 10),borderwidth=0,highlightthickness=1,highlightcolor=("gray70" if ctk.get_appearance_mode() == "light" else "gray40"))self.listbox.bind("<<ListboxSelect>>", self.select_cipher)self.listbox.pack(pady=5, padx=10, fill="x")# 密文輸入/展示區域input_area_frame = ctk.CTkFrame(self, fg_color="transparent")input_area_frame.pack(pady=10, fill="x", padx=20)ctk.CTkLabel(input_area_frame,text="密文輸入:",font=ctk.CTkFont(size=14)).pack(anchor="w")self.input = ctk.CTkTextbox(input_area_frame,height=60,  # 進一步減小高度width=600,font=ctk.CTkFont(size=13),corner_radius=8,border_width=1)self.input.pack(pady=5, fill="x")# 操作按鈕容器button_frame = ctk.CTkFrame(self, fg_color="transparent")button_frame.pack(pady=10)# 默認密鑰解密按鈕ctk.CTkButton(button_frame,text="使用默認密鑰解密",command=self.decrypt,width=180,height=35,font=ctk.CTkFont(size=14),fg_color=("blue", "blue"),hover_color=("darkblue", "darkblue"),corner_radius=8).pack(side="left", padx=10)# 自定義密鑰解密按鈕ctk.CTkButton(button_frame,text="使用自定義密鑰解密",command=self.decrypt_with_custom_key,width=180,height=35,font=ctk.CTkFont(size=14),fg_color=("green", "green"),hover_color=("darkgreen", "darkgreen"),corner_radius=8).pack(side="left", padx=10)# 結果輸出區域output_frame = ctk.CTkFrame(self, fg_color="transparent")output_frame.pack(pady=10, fill="x", padx=20)ctk.CTkLabel(output_frame,text="解密結果:",font=ctk.CTkFont(size=14)).pack(anchor="w")self.output = ctk.CTkTextbox(output_frame,height=170,width=600,font=ctk.CTkFont(size=13),corner_radius=8,border_width=1)self.output.pack(pady=5, fill="x")self.output.configure(state="disabled")def update_fingerprint(self, key):"""更新當前密鑰指紋顯示"""fingerprint = get_key_fingerprint(key).hex()self.fingerprint_label.configure(text=f"當前密鑰指紋: {fingerprint}")def decrypt_with_custom_key(self):"""使用自定義密鑰解密流程"""ciphertext = self.input.get("1.0", "end").strip()if not ciphertext:messagebox.showerror("錯誤", "請輸入或選擇要解密的密文")returnif not self.last_custom_key:self.last_custom_key = self._get_valid_custom_key()if not self.last_custom_key:return# 檢查密文是否已在歷史記錄中存在if self.check_ciphertext_exists(ciphertext):# 顯示提示信息,告知用戶密文已解密過messagebox.showinfo("提示", "當前密文已解密過,請查看歷史記錄")try:# 仍然解密以顯示結果,但不保存記錄plaintext = decrypt_with_key(ciphertext, self.last_custom_key)# 更新密鑰指紋顯示self.update_fingerprint(self.last_custom_key)# 顯示解密結果self.show_output(f"解密成功!\n身份證號碼: {plaintext}")except Exception as e:# 解密失敗時清除無效的自定義密鑰緩存self.last_custom_key = None# 恢復默認密鑰顯示self.update_fingerprint(self.key)# 顯示錯誤信息self.show_output(f"解密失敗: {str(e)}")# 提前返回,不保存記錄(避免重復記錄)returntry:# 使用自定義密鑰解密plaintext = decrypt_with_key(ciphertext, self.last_custom_key)# 獲取密鑰指紋的十六進制表示fingerprint = get_key_fingerprint(self.last_custom_key).hex()# 更新密鑰指紋顯示self.update_fingerprint(self.last_custom_key)# 顯示解密結果self.show_output(f"解密成功!\n身份證號碼: {plaintext}")# 保存解密記錄到JSON文件self.save_plaintext_record(plaintext, fingerprint, "custom", ciphertext)except Exception as e:# 解密失敗時清除無效的自定義密鑰緩存self.last_custom_key = None# 恢復默認密鑰顯示self.update_fingerprint(self.key)# 顯示錯誤信息self.show_output(f"解密失敗: {str(e)}")def _get_valid_custom_key(self):"""獲取有效自定義密鑰"""while True:key_str = simpledialog.askstring("自定義密鑰", "請輸入64位十六進制密鑰:")if not key_str:return Nonetry:if len(key_str) != 64 or not all(c in "0123456789abcdef" for c in key_str.lower()):raise ValueError("密鑰必須是64位十六進制字符")return bytes.fromhex(key_str.lower())except Exception as e:messagebox.showerror("輸入錯誤", f"無效密鑰: {str(e)}")continuedef load_file(self):"""加載密文文件到列表控件"""try:with open(CIPHER_FILE, "r") as f:self.cipher_list = [line.strip() for line in f if line.strip()]self.listbox.delete(0, "end")for c in self.cipher_list:self.listbox.insert("end", f"{c[:30]}...")except Exception as e:messagebox.showerror("錯誤", f"文件讀取失敗: {str(e)}")def select_cipher(self, event):"""處理列表項選擇事件"""idx = self.listbox.curselection()if not idx:returnfull_text = self.cipher_list[idx[0]]self.input.delete("1.0", "end")self.input.insert("1.0", full_text)def clear_input(self):"""清空輸入框內容"""self.input.delete("1.0", "end")def decrypt(self):"""使用默認密鑰的解密流程"""# 獲取輸入框中的密文并去除首尾空白ciphertext = self.input.get("1.0", "end").strip()# 檢查密文是否為空if not ciphertext:messagebox.showerror("錯誤", "請輸入或選擇要解密的密文")return# 檢查密文是否已在歷史記錄中存在if self.check_ciphertext_exists(ciphertext):# 顯示提示信息,告知用戶密文已解密過messagebox.showinfo("提示", "當前密文已解密過,請查看歷史記錄")try:# 仍然解密以顯示結果,但不保存記錄plaintext, used_key = decrypt_id_number(ciphertext)# 更新當前使用的密鑰self.key = used_key# 更新密鑰指紋顯示self.update_fingerprint(self.key)# 顯示解密結果self.show_output(f"解密成功!\n身份證號碼: {plaintext}")except Exception as e:# 解密失敗時更新顯示并顯示錯誤信息self.update_fingerprint(self.key)self.show_output(f"解密失敗: {str(e)}")# 提前返回,不保存記錄(避免重復記錄)returntry:# 使用默認密鑰解密plaintext, used_key = decrypt_id_number(ciphertext)# 更新當前使用的密鑰self.key = used_key# 獲取密鑰指紋的十六進制表示fingerprint = get_key_fingerprint(used_key).hex()# 更新密鑰指紋顯示self.update_fingerprint(self.key)# 顯示解密結果self.show_output(f"解密成功!\n身份證號碼: {plaintext}")# 保存解密記錄到JSON文件self.save_plaintext_record(plaintext, fingerprint, "default", ciphertext)except Exception as e:# 解密失敗時更新顯示并顯示錯誤信息self.update_fingerprint(self.key)self.show_output(f"解密失敗: {str(e)}")def show_output(self, text):"""更新結果輸出區域"""self.output.configure(state="normal")self.output.delete("1.0", "end")self.output.insert("1.0", text)self.output.configure(state="disabled")class Application(ctk.CTk):"""主應用程序類,繼承自CustomTkinter的CTk窗口"""def __init__(self):"""初始化應用程序實例"""super().__init__()  # 調用父類CTk的構造函數# 配置窗口self.title("身份證號加解密系統 v3.0")self.geometry("800x650")# 設置主題ctk.set_appearance_mode("system")  # 系統主題(自動適應明暗)ctk.set_default_color_theme("blue")  # 使用藍色主題# 配置窗口樣式self.configure(fg_color=("gray95", "gray10"))  # 背景顏色(亮/暗模式)# 加載密鑰self.key = load_aes_key()# 初始化界面self.init_ui()def init_ui(self):"""初始化用戶界面組件"""# 創建主容器self.container = ctk.CTkFrame(self, fg_color="transparent")self.container.pack(fill="both", expand=True, padx=20, pady=20)# 創建主頁面實例self.main_page = MainPage(self.container, self.show_encrypt, self.show_decrypt)self.encrypt_page = Noneself.decrypt_page = None# 顯示主頁面self.show_main()def show_main(self):"""顯示主頁面"""self._hide_pages()self.main_page.pack(fill="both", expand=True)def show_encrypt(self):"""顯示加密頁面"""self._hide_pages()self.encrypt_page = EncryptPage(self.container, self.key, self.show_main)self.encrypt_page.pack(fill="both", expand=True)def show_decrypt(self):"""顯示解密頁面"""self._hide_pages()self.decrypt_page = DecryptPage(self.container, self.key, self.show_main)self.decrypt_page.pack(fill="both", expand=True)def _hide_pages(self):"""隱藏所有Frame類型的子組件"""for widget in self.container.winfo_children():widget.pack_forget()def load_key(self):"""重新加載當前密鑰"""self.key = load_aes_key()def generate_new_key(self):"""生成全新密鑰并更新狀態"""generate_aes_key()self.load_key()if __name__ == "__main__":"""程序入口點"""app = Application()  # 創建應用程序實例app.mainloop()  # 啟動Tkinter事件循環

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/98043.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/98043.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/98043.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

LangChain: Models, Prompts 模型和提示詞

獲取openapikey #!pip install python-dotenv #!pip install openai import osimport openai ? from dotenv import load_dotenv, find_dotenv _ load_dotenv(find_dotenv()) # read local .env file openai.api_key os.environ[OPENAI_API_KEY] # account for deprecat…

ACMESSL自動續簽教程

目錄 1、選擇申請證書 ?編輯2、選擇CA機構 ?編輯3、選擇自動驗簽 ?編輯4、證書續簽設置 5、自動發布設置 本教程實現ACMESSL自動續簽&#xff0c;請按照此教程實現。 1、選擇申請證書 點擊快捷入口或者訂單或證書列表中的【創建證書】按鈕&#xff1a; 2、選擇CA機構 …

基于飛算JavaAI的在線圖書借閱平臺設計實現

項目概述與需求分析 1.1 項目背景與意義 隨著數字化時代的快速發展&#xff0c;傳統圖書館管理模式已無法滿足現代讀者的需求。在線圖書借閱平臺通過互聯網技術將圖書資源數字化&#xff0c;為讀者提供便捷的檢索、借閱和管理服務&#xff0c;有效解決了傳統圖書館開放時間有…

通過API接口管理企業微信通訊錄案例

1.開始前需要登錄企業微信管理員后臺&#xff0c;開啟通訊錄同步&#xff0c;同時添加企業可信IP地址&#xff0c;記錄下Secret信息和企業ID&#xff0c;后面的程序會用到這兩個參數。2.下面是用python寫的創建企業微信賬號的具體案例。#!/usr/bin/env python3 # -*- coding: u…

硬件開發_基于物聯網的自動售賣機系統

一.系統概述 物聯網自動售賣機系統的主要功能如下&#xff1a; 核心控制器&#xff1a;采用STM32單片機作為系統核心&#xff0c;負責整體數據處理和各設備的統一控制。商品選擇&#xff1a;支持語音識別及按鍵方式&#xff0c;方便用戶在售賣機內選擇商品。語音播報&#xff1…

AGENTS.md: AI編碼代理的開放標準

每個項目都有一個 README.md 文件供人類閱讀。但隨著 AI 編碼代理和 AI 輔助開發的興起,我們需要一個新標準:AGENTS.md。這個 Markdown 文件定義了代理如何構建、測試和協作。 這就是 AGENTS.md 的作用。 它是一個簡單的 Markdown 文件,告訴 AI 助手如何在你的項目中操作:…

如何解決 OutOfMemoryError 內存溢出 —— 原因、定位與解決方案

網羅開發&#xff08;小紅書、快手、視頻號同名&#xff09;大家好&#xff0c;我是 展菲&#xff0c;目前在上市企業從事人工智能項目研發管理工作&#xff0c;平時熱衷于分享各種編程領域的軟硬技能知識以及前沿技術&#xff0c;包括iOS、前端、Harmony OS、Java、Python等方…

阿里云服務器配置ssl-docker nginx

# 切換到您當前的目錄 cd /AAAAAAAAAAAA# 創建存放nginx配置、證書和日志的目錄結構 mkdir -p nginx-config/conf.d nginx-ssl nginx-logs# 為掛載做準備&#xff0c;您可能需要將當前dist目錄內容移動到新的html目錄 # 首先查看當前dist目錄的內容 ls -la dist/# 如果html目錄…

2025全球生成式引擎優化(GEO)服務商發展趨勢與企業賦能白皮書

引言&#xff1a;人工智能技術的迅猛發展&#xff0c;特別是在生成式AI領域的突破&#xff0c;正以前所未有的力量重塑商業世界的競爭格局。對于尋求提升在線可見性、優化品牌互動及實現可持續增長的企業而言&#xff0c;生成式引擎優化&#xff08;GEO&#xff09;已然成為數字…

海康威視工業相機SDK開發實戰:使用C/C++實現軟件觸發圖像采集(含詳細中文注釋代碼)

一、前言 在機器視覺、自動化檢測、智能制造等領域&#xff0c;工業相機是獲取圖像數據的核心設備。海康威視作為國內領先的機器視覺廠商&#xff0c;其工業相機產品線豐富&#xff0c;廣泛應用于各類工業場景。 本文將帶你從零開始&#xff0c;使用 海康MVS SDK&#xff08;Ma…

Modbus RTU 協議介紹

Modbus RTU 協議介紹 異步串行傳輸方式&#xff0c;采用二進制格式&#xff0c;適用于串行通訊&#xff08;如RS-485&#xff09;&#xff0c;效率高&#xff0c;是工業現場的主流選擇。 主站是Master&#xff0c;從站是Slave。 Modbus RTU 協議格式 幀結構 地址碼&#xf…

TCP/IP函數——sendmsg

sendmsg() 是 POSIX 標準中一個高級套接字發送函數,屬于系統調用(由操作系統內核實現),定義在 <sys/socket.h> 頭文件中。它的核心特點是支持復雜消息結構,不僅能發送常規數據,還能附加控制信息(如輔助數據、IP 選項等),適用于 TCP、UDP 等多種協議,功能比 sen…

運動控制中的插值運動(插補運動):原理、實現與應用

在自動化設備中,從起點到終點的精準軌跡控制是核心需求。當目標軌跡是直線、圓弧或復雜曲線時,僅通過離散的目標點無法實現平滑運動,這就需要插值運動(Interpolation Motion)技術 —— 通過控制算法在已知路徑點之間計算出連續的中間點,使運動部件沿預定軌跡平滑移動。本…

GMT——用于人形全身控制的通用運動跟蹤:兩階段師生訓練框架下,全身基于單一策略,且自適應采樣、MoE架構

前言 如此文《KungfuBot——基于物理約束和自適應運動追蹤的人形全身控制PBHC&#xff0c;用于學習打拳或跳舞(即RL下的動作模仿和運控)》的開頭所說 如此&#xff0c;便關注到最新出來的三個工作 第一個是GMT: General Motion Tracking for Humanoid Whole-Body Control第二個…

matlab版本粒子群算法(PSO)在路徑規劃中的應用

基于粒子群優化&#xff08;PSO&#xff09;算法的路徑規劃 MATLAB代碼實現 1. 初始化環境和參數 % 初始化環境參數 mapSize [10, 10]; % 地圖大小 startPoint [1, 1]; % 起點 endPoint [9, 9]; % 終點 obstacles [3, 3; 5, 5; 7, 7]; % 障礙物位置% PSO參數 numParticles …

Go語言面試:傳值與傳引用的區別及選擇指南

在Go語言中&#xff0c;函數參數的傳遞方式有兩種&#xff1a;傳值&#xff08;pass-by-value&#xff09;和傳引用&#xff08;pass-by-reference&#xff09;。理解這兩種方式的區別及其適用場景&#xff0c;是成為Go語言開發高手的必備技能。本文將深入探討Go語言中傳值與傳…

數據無言,網關有聲 耐達訊自動化RS485轉Profinet讓千年液位數據“開口說話”

在能源行業的數字化轉型浪潮中&#xff0c;你是否曾面臨這樣的困境&#xff1a; 現場大量采用RS485接口的液位計&#xff0c;數據孤立如信息孤島&#xff0c;無法接入Profinet高速網絡&#xff1f; 模擬信號傳輸距離受限&#xff0c;抗干擾能力弱&#xff0c;導致液位測量誤差…

出口退稅新政大提速:企業如何抓住政策紅利,提升最高13%純利?

近年來&#xff0c;出口退稅政策的優化與升級&#xff0c;正在成為外貿企業提升資金周轉率和利潤率的關鍵。國家稅務總局發布的 2022年第9號公告&#xff08;簡稱“9號公告”&#xff09;落地執行已兩年&#xff0c;外貿行業普遍感受到退稅速度顯著加快&#xff0c;平均退稅周期…

使用pytorch創建/訓練/推理OCR模型

一、任務描述 從手寫數字圖像中自動識別出對應的數字&#xff08;0-9&#xff09;” 的問題&#xff0c;屬于單標簽圖像分類任務&#xff08;每張圖像僅對應一個類別&#xff0c;即 0-9 中的一個數字&#xff09; 1、任務的核心定義&#xff1a;輸入與輸出 輸入&#xff1a;28…

新啟航開啟深孔測量新紀元:激光頻率梳技術攻克光學遮擋,達 130mm 深度 2μm 精度

摘要&#xff1a;本文聚焦于深孔測量領域&#xff0c;介紹了一種創新的激光頻率梳技術。該技術成功攻克傳統測量中的光學遮擋難題&#xff0c;在深孔測量深度達 130mm 時&#xff0c;可實現 2μm 的高精度測量&#xff0c;為深孔測量開啟了新的發展篇章。關鍵詞&#xff1a;激光…