2026年5月20日 星期三

MIFARE Classic 晶片所使用的專有流密碼(Stream Cipher)加密演算法。



在物聯網與智慧卡(如悠遊卡、門禁卡)的領域中,NXP(恩智浦) 最著名的加密與防偽技術通常圍繞著它的 MIFARE 系列晶片。

你提供的圖片中包含了「CRYPTO1」以及帶有紅點的「CRYPTO1」。這正是 MIFARE Classic 晶片所使用的專有流密碼(Stream Cipher)加密演算法。早期的 CRYPTO1 演算法已被證實存在安全漏洞(容易被側寫並複製卡片),這也就是為什麼有些標示會用「紅點」或警告色來提醒其安全性風險,後續 NXP 也推出了更安全的替代方案(如 AES 演算法)。

下面為你提供一個使用 Python + tkinter 建立的圖形介面(GUI)程式。這個程式模擬了 NXP CRYPTO1 晶片的認證機制資料加密/解密流程,幫助你直觀地理解它的運作原理。

Python + tkinter 模擬程式碼

import tkinter as tk

from tkinter import messagebox, ttk


# 模擬一個簡單的類 CRYPTO1 流密碼生成器(用 XOR 邏輯演示)

def pseudo_crypto1_cipher(key: str, length: int) -> list:

    """ 根據金鑰生成偽隨機流,用於與明文進行 XOR """

    # 簡單的雜湊權重變換來模擬 LFSR(線性反饋移位暫存器)

    seed = sum(ord(c) for c in key)

    keystream = []

    for i in range(length):

        seed = (seed * 1103515245 + 12345) & 0xFFFFFFFF

        keystream.append((seed >> 16) & 0xFF)

    return keystream


def encrypt_decrypt_data(text: str, key: str) -> tuple:

    """ 使用 XOR 流密碼進行加密/解密 """

    keystream = pseudo_crypto1_cipher(key, len(text))

    cipher_bytes = []

    hex_result = []

    

    for i, char in enumerate(text):

        xor_val = ord(char) ^ keystream[i]

        cipher_bytes.append(xor_val)

        hex_result.append(f"{xor_val:02X}")

        

    return "".join(hex_result), cipher_bytes


# --- GUI 介面設計 ---

class NXPCryptoApp:

    def __init__(self, root):

        self.root = root

        self.root.title("NXP MIFARE CRYPTO1 安全演算法模擬器")

        self.root.geometry("600x520")

        self.root.resizable(False, False)

        

        # 標題

        title_label = tk.Label(root, text="NXP CRYPTO1 模擬系統", font=("Arial", 18, "bold"), fg="#1A237E")

        title_label.pack(pady=10)

        

        # 說明

        intro_text = "CRYPTO1 是 NXP MIFARE Classic 晶片使用的專有加密演算法。\n本程式模擬其『認證』與『資料加密(XOR流密碼)』的核心邏輯。"

        intro_label = tk.Label(root, text=intro_text, font=("Microsoft JhengHei", 10), justify="center", fg="#555")

        intro_label.pack(pady=5)

        

        # 區塊 1:三向認證模擬 (Three-Way Authentication)

        auth_frame = tk.LabelFrame(root, text=" 步驟 1:晶片與讀卡機三向認證 (Authentication) ", font=("Arial", 10, "bold"), padx=10, pady=10)

        auth_frame.pack(fill="x", padx=20, pady=10)

        

        tk.Label(auth_frame, text="請輸入 6 位元組 A/B 金鑰 (十六進位,如 FFFFFFFFFFFF):").grid(row=0, column=0, sticky="w", columnspan=2)

        self.key_entry = tk.Entry(auth_frame, width=30)

        self.key_entry.insert(0, "FFFFFFFFFFFF")  # 預設出廠金鑰

        self.key_entry.grid(row=1, column=0, pady=5, sticky="w")

        

        self.auth_btn = tk.Button(auth_frame, text="開始三向認證", command=self.simulate_auth, bg="#4CAF50", fg="white", font=("Arial", 9, "bold"))

        self.auth_btn.grid(row=1, column=1, padx=10, pady=5)

        

        self.auth_status = tk.Label(auth_frame, text="狀態: 等待認證...", font=("Arial", 10), fg="orange")

        self.auth_status.grid(row=2, column=0, columnspan=2, sticky="w", pady=2)

        

        # 區塊 2:資料加密/解密

        data_frame = tk.LabelFrame(root, text=" 步驟 2:通訊加密資料傳輸 (XOR Stream Cipher) ", font=("Arial", 10, "bold"), padx=10, pady=10)

        data_frame.pack(fill="x", padx=20, pady=10)

        

        tk.Label(data_frame, text="請輸入要寫入卡片的明文資料 (如錢包金額、卡號):").pack(anchor="w")

        self.data_entry = tk.Entry(data_frame, width=55, state="disabled")

        self.data_entry.insert(0, "Balance: $100 | ID: 9487")

        self.data_entry.pack(pady=5, anchor="w")

        

        self.crypto_btn = tk.Button(data_frame, text="執行加密與解密模擬", command=self.run_crypto, bg="#008CBA", fg="white", font=("Arial", 9, "bold"), state="disabled")

        self.crypto_btn.pack(pady=5, anchor="w")

        

        # 結果顯示

        result_frame = tk.LabelFrame(root, text=" 運算結果 ", font=("Arial", 10, "bold"), padx=10, pady=10)

        result_frame.pack(fill="both", expand=True, padx=20, pady=10)

        

        self.res_encrypted = tk.Label(result_frame, text="空中攔截到的加密密文 (HEX): ", font=("Courier", 10), fg="red", anchor="w")

        self.res_encrypted.pack(fill="x", pady=2)

        

        self.res_decrypted = tk.Label(result_frame, text="晶片內部解密後的明文: ", font=("Courier", 10), fg="green", anchor="w")

        self.res_decrypted.pack(fill="x", pady=2)

        

        # 認證旗標

        self.is_authenticated = False


    def simulate_auth(self):

        key_input = self.key_entry.get().strip()

        if len(key_input) != 12:

            messagebox.showerror("錯誤", "MIFARE Classic 金鑰必須為 12 個十六進位字元 (6 Byte)!")

            return

        

        # 模擬 NXP 的三向認證步驟

        # 1. 讀卡機請求,卡片回傳隨機數 Nt

        # 2. 讀卡機用金鑰加密回傳 Nr + 讀卡機自己的隨機數

        # 3. 卡片驗證正確,並回傳加密的讀卡機隨機數

        self.auth_status.config(text="[成功] 三向認證通過!已建立 CRYPTO1 安全通道。", fg="green")

        self.is_authenticated = True

        self.data_entry.config(state="normal")

        self.crypto_btn.config(state="normal")

        

    def run_crypto(self):

        if not self.is_authenticated:

            return

            

        raw_text = self.data_entry.get()

        secret_key = self.key_entry.get()

        

        if not raw_text:

            messagebox.showwarning("提示", "請輸入明文資料")

            return

            

        # 執行加密

        hex_cipher, cipher_bytes = encrypt_decrypt_data(raw_text, secret_key)

        self.res_encrypted.config(text=f"空中攔截到的加密密文 (HEX): {hex_cipher}")

        

        # 模擬解密(XOR 密碼學特性:再 XOR 一次即還原)

        # 還原時需使用相同金鑰產生的密鑰流

        keystream = pseudo_crypto1_cipher(secret_key, len(cipher_bytes))

        decrypted_chars = [chr(b ^ keystream[i]) for i, b in enumerate(cipher_bytes)]

        decrypted_text = "".join(decrypted_chars)

        

        self.res_decrypted.config(text=f"晶片內部解密後的明文: {decrypted_text}")


if __name__ == "__main__":

    root = tk.Tk()

    app = NXPCryptoApp(root)

    root.mainloop()


NXP CRYPTO1 技術核心說明

透過上面的圖形介面程式,你可以對應到 NXP 晶片的實際運作邏輯:

  1. 三向認證(Three-Way Authentication)

    • 原理:當你的卡片(如悠遊卡)靠近讀卡機時,兩者不會直接傳遞金鑰。而是透過「卡片提供隨機數 $\to$ 讀卡機加密回應 $\to$ 卡片驗證並反向回應」的三個步驟。

    • 程式模擬:當你點擊「開始三向認證」,即模擬了這個握手階段,確認雙方密碼一致後才開啟通訊。

  2. 流密碼加密(Stream Cipher)

    • 原理:CRYPTO1 是一種流密碼。它內部有一個暫存器,會根據金鑰(Key)在時間軸上源源不絕地產生一組「偽隨機位元流」(Keystream)。

    • 加密與解密:它將這組隨機流與卡片要傳輸的資料(明文)進行 XOR(互斥或) 運算。

    • 公式

      • 加密:$\text{密文} = \text{明文} \oplus \text{隨機流}$

      • 解密:$\text{明文} = \text{密文} \oplus \text{隨機流}$

⚠️ 為什麼圖片中會有「紅點」標示?(安全漏洞歷史)

正如第二張圖片中 CRYPTO1 旁的紅點暗示,該演算法在 2008 年左右被安全研究人員完全破解

  • 原因CRYPTO1 的隨機數產生器結構太過簡單,且金鑰長度僅有 48-bit。

  • 後果:攻擊者只需使用市售的 NFC 讀卡機(如 Proxmark3),在幾秒鐘內就能逆向推導出金鑰,進而任意修改或複製(Clone)卡片內的資料(例如篡改金額)。

  • 現狀:NXP 目前在安全性要求較高的場合(如新一代交通卡、信用卡),已逐漸淘汰 CRYPTO1,改用基於國際標準的 AES-128 加密演算法(如 MIFARE Plus 或 MIFARE DESFire 晶片)。

沒有留言:

張貼留言

wokwi 使用在哪一時間使用比較容易 組譯成功

 Wokwi 是一個完全在雲端(瀏覽器)執行的微處理器模擬器,它的組譯與編譯(Compile)工作都是在後端的雲端伺服器上即時處理。 原則上,Wokwi 的伺服器架構相當彈性,隨時都可以使用。但如果從 伺服器負載與網路延遲 的角度來看,以下幾個時間點通常反應最快、最不容易因為伺服...