技術文章

後量子密碼學實戰:使用 Rust 與 Luna HSM 構建企業級 PQC 服務

深入探討如何使用 Rust 與 Thales Luna HSM 構建支援 ML-DSA、ML-KEM、HSS/LMS 的企業級後量子密碼學服務,包含完整架構設計、程式碼實作與效能基準測試

作者:Orson Wang
#PQC #後量子密碼學 #Rust #Luna HSM #ML-DSA #ML-KEM #PKCS11 #密碼學 #企業安全

前言

量子計算威脅現況

2026 年,量子計算的進展已經從理論走向實際威脅。雖然具備完全加密破解能力的量子電腦尚未出現,但「先儲存後破解 (Store Now, Decrypt Later)」的攻擊策略已成為現實威脅:攻擊者現在竊取加密資料,等待未來量子電腦成熟後再進行破解。

關鍵時間點

  • 2024 年 8 月 13 日:NIST 正式發布 FIPS 203 (ML-KEM) 與 FIPS 204 (ML-DSA) 標準
  • 2026 年:企業級 HSM 開始全面支援 PQC 演算法
  • 2030-2035 年:預估為 RSA-2048/ECC P-256 的安全終結時間點

對於需要長期保密的資料(醫療記錄、金融交易、政府機密),遷移至後量子密碼學已刻不容緩

NIST PQC 標準化完成

美國國家標準技術研究所(NIST)經過 8 年的評選過程,最終確定了以下後量子演算法標準:

標準演算法類型安全基礎用途
FIPS 203ML-KEM (Kyber)金鑰封裝機制 (KEM)Module-LWE金鑰交換、加密
FIPS 204ML-DSA (Dilithium)數位簽章Module-LWE身份驗證、簽章
FIPS 205SLH-DSA (SPHINCS+)數位簽章雜湊函數無狀態簽章

這些標準的發布意味著後量子密碼學已從研究階段進入生產部署階段

為什麼選擇 Luna HSM + Rust

硬體安全模組(HSM)的必要性

  1. 實體金鑰保護:私鑰永不離開 FIPS 140-2/3 Level 3 認證硬體
  2. 防篡改機制:物理入侵自動銷毀金鑰
  3. 合規要求:金融、醫療等行業法規強制要求
  4. 效能加速:硬體加速密碼學運算

選擇 Rust 的理由

  1. 記憶體安全:編譯期杜絕 buffer overflow、use-after-free 等漏洞
  2. 平行安全:類型系統保證 thread-safety
  3. 零成本抽象:無 GC overhead,效能媲美 C/C++
  4. 生態成熟:RustCrypto、Tokio、Axum 等高品質密碼學與網路框架

Thales Luna HSM 特色

  • 支援最新 FIPS 203/204 標準(Firmware 7.8.0+)
  • 原生 BIP32/SLIP10 HD 金鑰衍生
  • Luna 專有延伸 API(CA_* 函數)
  • 網路 HSM 與叢集支援

技術架構

系統分層設計

我們的 PQC 服務採用清晰的分層架構,從 API Gateway 到 HSM 硬體的完整封裝:

Mermaid diagram

各層職責

  1. API Gateway Layer: 提供多協議存取介面(REST、gRPC、NATS)
  2. Domain Layer: 業務邏輯、金鑰管理、稽核日誌
  3. HSM Layer: PKCS#11 操作封裝、連接池管理、PQC 專有功能
  4. FFI Layer: 底層 PKCS#11 C API 綁定
  5. Hardware: 實體 HSM 硬體

為什麼自己實作 luna-cryptoki 而不使用現有的 cryptoki crate?

這是一個關鍵的技術決策,我們選擇自行實作 FFI 綁定的原因如下:

1. 現有 cryptoki crate 與 Luna HSM 的相容性問題

Parallax Second 維護的 rust-cryptoki 是 Rust 生態中最成熟的 PKCS#11 綁定,但在與 Luna Network HSM 配合使用時存在嚴重的穩定性問題

已知問題(來自 GitHub Issues):

  • Issue #72: pkcs11.open_session_no_callback 在 Luna Network HSM 上崩潰(SIGSEGV)
  • Issue #50: ctx.open_session 在 Luna HSM 上發生記憶體錯誤

這些問題源於 Luna HSM 對 PKCS#11 標準的特定實作細節,標準 cryptoki crate 無法完全相容。

2. Luna 專有延伸 API 支援

Luna HSM 提供了大量超越 PKCS#11 標準的專有延伸 APICA_* 函數),這些功能對企業級應用至關重要:

延伸類別API 函數用途
PQC 支援CA_ML_DSA_*, CA_ML_KEM_*後量子密碼學操作
HD 金鑰衍生CA_BIP32_*, CA_SLIP10_*原生 BIP32/SLIP10 支援
系統監控CA_GetHSMStats, CA_GetHSMCapabilitySetHSM 健康監控
儲存管理CA_GetHSMStorageInformation, CA_GetTokenStorageInformation容量監控
韌體管理CA_GetFirmwareVersion版本資訊

標準 cryptoki crate 不支援這些延伸,如果使用它,我們將無法:

  • 使用 ML-DSA/ML-KEM 後量子演算法
  • 實作 BIP32 HD 錢包功能
  • 監控 HSM 健康狀態與容量
  • 充分利用 Luna HSM 的進階功能

3. 精細錯誤處理

Luna HSM 定義了大量專有錯誤碼(例如 CKR_BIP32_CHILD_INDEX_INVALID, CKR_LUNA_OPERATION_FAILED),需要結構化錯誤處理:

錯誤分類

  • Operation - 操作失敗(包含錯誤碼和描述)
  • KeyNotFound - 金鑰不存在
  • HsmDisconnected - HSM 斷線(可重試)
  • Pin - PIN 相關錯誤

透過錯誤類型判斷是否可重試,實作智能重試、降級策略、精準警示等企業級功能。

4. 性能優化與 Session 管理

Luna HSM 的 Session 管理採用 deadpool 連接池實作,包含:

Session 生命週期管理

  1. 建立:開啟 Session → 登入 → 快取符號表 → 健康檢查
  2. 回收:檢測斷線 → 清理狀態 → 重新登入

關鍵優化

  • 符號快取:避免重複 dlsym 呼叫
  • 健康檢查:自動檢測 HSM 斷線並重建連接
  • 預熱 Pool:啟動時預先建立 50 個 Session
  • 平行安全:支援多執行緒平行存取

5. 完全控制與長期維護

自行實作 FFI 綁定帶來的優勢:

  • 完全掌控:不依賴上游 crate 的更新節奏
  • 快速修復:發現問題可立即修補,無需等待上游
  • 客製化:針對 Luna HSM 特性進行深度優化
  • 穩定性:避免上游 breaking changes 影響生產環境

成本考量

雖然自行實作增加了初期開發成本(約 6,000+ 行程式碼),但從長期來看:

  • 減少了對外部依賴的風險
  • 提高了系統穩定性
  • 降低了未來維護成本

關鍵技術選型

組件技術選擇版本用途
Web 框架Axum0.7REST API 服務
gRPC 框架Tonic + Prost0.12 / 0.13gRPC 服務與 Protobuf 序列化
非同步執行環境Tokio1.36非同步 I/O 與平行控制
連接池deadpool0.10PKCS#11 Session 管理
稽核日誌rusqlite + tracing0.31 / 0.1SOC2 合規日誌
FFI 綁定luna-cryptoki (自定義)0.1Luna HSM PKCS#11 綁定
序列化Serde + JSON/Protobuf1.0資料序列化
Metricsmetrics + prometheus0.22 / 0.14效能監控

為什麼選擇 Axum 而非 Actix-web/Rocket

  • 原生 Tokio 整合:無需額外的執行環境轉換
  • 型別驅動路由:編譯期檢查,減少執行期錯誤
  • 極致效能:Hyper + Tower 的組合,效能優於大多數框架
  • 中介軟體生態:Tower 生態豐富,易於延伸

為什麼使用 deadpool 而非 r2d2/bb8

  • 非同步原生:完全支援 async/await,無阻塞
  • 健康檢查:內建連接健康檢查機制
  • Metrics 友好:易於整合 Prometheus 監控

PQC 演算法實作

ML-DSA (Dilithium) 簽章演算法

ML-DSA (Module-Lattice-Based Digital Signature Algorithm) 是 NIST FIPS 204 標準化的後量子數位簽章演算法,前身為 Dilithium。

安全參數集

模式NIST 安全級別公鑰大小私鑰大小簽章大小等效 RSA 強度
ML-DSA-44Level 21,312 B2,544 B2,420 BRSA-2048
ML-DSA-65Level 31,952 B4,000 B3,293 BRSA-3072
ML-DSA-87Level 52,592 B5,632 B4,595 BRSA-4096

建議:一般應用使用 ML-DSA-65,高安全需求使用 ML-DSA-87

使用流程

基本操作步驟

  1. 建立 Session Pool - 預先建立 50 個 Session 連線
  2. 產生金鑰對 - 指定安全級別(Level 44/65/87)和儲存方式
  3. 執行簽章 - 使用私鑰對訊息簽章(3,293 bytes)
  4. 驗證簽章 - 使用公鑰驗證,防止偽造攻擊

關鍵設計考量

  1. 金鑰生命週期

    • token_object = false: Session 金鑰(程式結束自動銷毀)
    • token_object = true: 持久化金鑰(需手動刪除)
  2. 簽章確定性:ML-DSA 使用 FIPS 204 定義的確定性簽章模式,相同訊息多次簽章會產生不同簽章值(內含隨機數),但都能通過驗證

  3. 錯誤處理:根據錯誤類型決定重試策略(金鑰不存在、HSM 斷線、未預期錯誤)

ML-KEM (Kyber) 金鑰封裝機制

ML-KEM (Module-Lattice-Based Key Encapsulation Mechanism) 是 NIST FIPS 203 標準化的後量子金鑰封裝演算法,前身為 Kyber。

安全參數集

模式NIST 安全級別公鑰大小私鑰大小密文大小共享密鑰等效 AES 強度
ML-KEM-512Level 1800 B1,632 B768 B32 BAES-128
ML-KEM-768Level 31,184 B2,400 B1,088 B32 BAES-192
ML-KEM-1024Level 51,568 B3,168 B1,568 B32 BAES-256

建議:一般應用使用 ML-KEM-768,極高安全需求使用 ML-KEM-1024

KEM 工作原理

Mermaid diagram

使用流程

Alice 端(接收方)

  1. 產生金鑰對 - 產生 ML-KEM-768 公私鑰對
  2. 導出公鑰 - 公鑰大小 1,184 bytes,傳送給 Bob
  3. 解封裝 - 使用私鑰從密文恢復共享密鑰(32 bytes)

Bob 端(發送方)

  1. 封裝 - 使用 Alice 公鑰產生密文(1,088 bytes)和共享密鑰(32 bytes)
  2. 加密資料 - 使用共享密鑰進行 AES-GCM 加密

進階用法:若公鑰儲存在 HSM 中,可直接使用 handle,避免傳輸公鑰 bytes

ML-KEM 安全性考量

  1. Nonce 唯一性:使用共享密鑰時,必須確保 nonce 不重複(使用計數器或隨機數)
  2. 密鑰使用次數:建議定期輪換金鑰對(如每 1,000,000 次封裝操作)
  3. 私鑰保護:私鑰永不離開 HSM,只能用於解封裝操作

HSS/LMS 一次性簽章

HSS (Hierarchical Signature System) 與 LMS (Leighton-Micali Signature) 是基於雜湊函數的後量子簽章演算法,已納入 NIST SP 800-208 標準。

特性與適用場景

特性說明
安全基礎雜湊函數(SHA-256/SHA-512)- 抗量子攻擊
有狀態私鑰每次簽章後狀態改變(一次性簽章)
簽章次數由樹高 H 決定:2^H 次簽章
後量子安全完全基於雜湊函數,無需額外假設
驗證速度極快(僅需雜湊運算)
簽章大小較大(數 KB),與樹高相關

適用場景

  • 韌體簽章:BIOS、IoT 韌體(簽章次數有限)
  • 安全啟動:Secure Boot 驗證
  • 軟體更新:APK、OTA 更新包簽章
  • 程式碼簽章:發布前簽署可執行檔
  • 不適用:高頻簽章場景(如 TLS handshake)

樹高配置與簽章次數

LMS 類型樹高 H最大簽章次數公鑰大小簽章大小
LMS_SHA256_M32_H5532~60 B~1,300 B
LMS_SHA256_M32_H10101,024~60 B~2,600 B
LMS_SHA256_M32_H151532,768~60 B~4,000 B
LMS_SHA256_M32_H20201,048,576~60 B~5,500 B
LMS_SHA256_M32_H252533,554,432~60 B~7,000 B

HSS 多層樹(提升簽章次數):

HSS 配置總簽章次數說明
1-level (H=10)1,024單層樹
2-level (H=10, H=10)1,048,576兩層樹:1024 × 1024
2-level (H=15, H=15)1,073,741,824兩層樹:32768 × 32768

實作範例

HSS/LMS 金鑰對產生與簽章流程

  1. 初始化 HSM 連線池

    • 載入 Luna Cryptoki 函式庫
    • 建立 50 個平行 Session 池
    • 使用環境變數 HSM_PIN 認證
  2. 產生 HSS 金鑰對

    • 參數:TwoLevel_H10_H10(1,048,576 次簽章)
    • 金鑰標籤:firmware_signing_key
    • 持久化儲存(token_object: true
  3. 查詢剩餘簽章次數

    • 呼叫 get_hss_remaining_signatures()
    • 初始值:1,048,576 次
  4. 簽章韌體

    • 輸入:韌體檔案的 SHA-256 雜湊值
    • 呼叫 hss_lms_sign()
    • 輸出:簽章 bytes
  5. 驗證簽章

    • 呼叫 hss_lms_verify()
    • 確認簽章有效性
  6. 追蹤狀態變化

    • 簽章後剩餘次數:1,048,575(減少 1 次)
    • HSM 自動更新內部狀態

狀態管理與備份

關鍵警告:HSS/LMS 私鑰是有狀態的,每次簽章後狀態會改變。如果:

  1. 備份舊狀態後繼續簽章
  2. 稍後恢復舊備份
  3. 重複使用相同的一次性私鑰

會導致安全性完全崩潰(簽章可被偽造)

正確備份策略:Luna HSM依照FIPS規格要求,無法備份

Luna HSM 自動狀態保護

  • HSM 自動追蹤 HSS/LMS 私鑰狀態
  • 防止狀態回溯攻擊
  • 當簽章次數耗盡時自動拒絕簽章

RESTful API 設計

API 端點規劃

我們的 PQC 服務提供完整的 RESTful API,符合 OpenAPI 3.0 規範:

基礎 URL: https://api.example.com/api/v1

PQC 金鑰管理

方法端點功能請求體回應
POST/pqc/generate產生 PQC 金鑰對PqcGenerateKeyInputPqcGenerateKeyOutput
GET/pqc/public-key取得公鑰-PqcPublicKeyOutput
DELETE/pqc/keys/{key_id}刪除金鑰-SuccessResponse

PQC 簽章操作

方法端點功能請求體回應
POST/pqc/signML-DSA/HSS 簽章PqcSignInputPqcSignOutput
POST/pqc/verify驗證簽章PqcVerifyInputPqcVerifyOutput

PQC 金鑰封裝

方法端點功能請求體回應
POST/pqc/encapsulateML-KEM 封裝MlKemEncapsulateInputMlKemEncapsulateOutput
POST/pqc/decapsulateML-KEM 解封裝MlKemDecapsulateInputMlKemDecapsulateOutput

API 調用範例

基本流程

  1. 產生金鑰對 (POST /pqc/generate)

    • 輸入:label、algorithm(ML_DSA_65/ML_KEM_768 等)、token_object
    • 輸出:key_id、public_key(Base64)、HSM handles
  2. 簽章 (POST /pqc/sign)

    • 輸入:label、algorithm、data(Base64)
    • 輸出:signature(Base64,3,293 bytes)、signed_at
  3. 驗證簽章 (POST /pqc/verify)

    • 輸入:label、algorithm、data、signature
    • 輸出:valid(true/false)、verified_at
  4. ML-KEM 封裝 (POST /pqc/encapsulate)

    • 輸入:label、algorithm
    • 輸出:ciphertext(1,088 bytes)、shared_secret(32 bytes)
    • 共享密鑰僅出現一次,需立即使用或安全儲存
  5. ML-KEM 解封裝 (POST /pqc/decapsulate)

    • 輸入:label、algorithm、ciphertext
    • 輸出:shared_secret(32 bytes)

錯誤處理

標準錯誤回應格式

{
  "error": {
    "code": "KEY_NOT_FOUND",
    "message": "找不到金鑰: my_ml_dsa_key",
    "details": {
      "label": "my_ml_dsa_key",
      "suggestion": "請檢查金鑰標籤是否正確,或使用 key_id 查找"
    },
    "request_id": "req_1234567890"
  }
}

錯誤碼對照表

錯誤碼HTTP 狀態碼說明處理建議
KEY_NOT_FOUND404金鑰不存在檢查 label/key_id
INVALID_ALGORITHM400不支援的演算法查看支援的演算法列表
HSM_DISCONNECTED503HSM 斷線稍後重試
SIGNATURE_INVALID400簽章驗證失敗檢查資料與簽章
PIN_LOCKED403HSM PIN 鎖定聯絡管理員
RATE_LIMIT_EXCEEDED429請求速率超限降低請求頻率
INTERNAL_ERROR500內部錯誤檢查日誌,聯絡支援

API 認證與授權

支援的認證方式

  1. API Token(推薦):
curl -H "Authorization: Bearer YOUR_API_TOKEN" ...
  1. mTLS (Mutual TLS):
curl --cert client.crt --key client.key --cacert ca.crt ...

權限模型

角色權限
admin所有操作(包含金鑰管理)
operator簽章/驗證/封裝/解封裝
viewer僅查詢公鑰與狀態

企業級特性

SOC2 稽核日誌

企業合規性要求對所有密碼學操作進行稽核,我們實作了符合 SOC2 標準的稽核系統:

稽核日誌設計

獨立稽核資料庫 (audit.db):

CREATE TABLE audit_logs (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    timestamp TEXT NOT NULL,           -- ISO 8601 格式
    session_id TEXT NOT NULL,          -- 關聯請求
    actor_id TEXT,                     -- 使用者/服務帳號
    actor_ip TEXT NOT NULL,            -- 客戶端 IP
    action TEXT NOT NULL,              -- 操作類型
    resource_type TEXT NOT NULL,       -- 資源類型
    resource_id TEXT,                  -- 資源 ID
    algorithm TEXT,                    -- 使用的演算法
    status TEXT NOT NULL,              -- Success/Failure/Warning
    error_code TEXT,                   -- 錯誤碼(如有)
    metadata TEXT,                     -- JSON 格式的額外資訊
    hmac_chain TEXT NOT NULL,          -- 防篡改 HMAC 鏈
    created_at TEXT DEFAULT (datetime('now'))
);

CREATE INDEX idx_audit_timestamp ON audit_logs(timestamp);
CREATE INDEX idx_audit_actor ON audit_logs(actor_id);
CREATE INDEX idx_audit_action ON audit_logs(action);

防篡改機制

稽核日誌使用 HMAC 鏈式防篡改設計:

Log Entry 1:  data_1 → HMAC(key, data_1) = hash_1
Log Entry 2:  data_2 + hash_1 → HMAC(key, data_2 + hash_1) = hash_2
Log Entry 3:  data_3 + hash_2 → HMAC(key, data_3 + hash_2) = hash_3
...

實作邏輯

AuditLogger 結構

  • db:SQLite 連線池
  • hmac_key:HMAC 金鑰(儲存在 HSM 中)
  • last_hmac:最新記錄的 HMAC 值(用 RwLock 保護平行存取)

記錄事件流程 (log_event):

  1. 序列化事件為 JSON
  2. 讀取上一筆記錄的 HMAC 值
  3. 計算目前記錄的 HMAC(使用 HSM 中的金鑰):HMAC(event_data + prev_hmac)
  4. 原子寫入資料庫(包含所有欄位與 HMAC 鏈)
  5. 更新記憶體中的 last_hmac

驗證完整性流程 (verify_integrity):

  1. 從資料庫讀取所有日誌(按 ID 升冪排序)
  2. 逐筆驗證:
    • 重新計算預期 HMAC
    • 比對資料庫中儲存的 HMAC
    • 若不符,回傳 false(日誌被篡改)
  3. 所有記錄驗證通過,回傳 true

稽核事件範例

{
  "timestamp": "2026-02-03T14:30:00.123Z",
  "session_id": "sess_abc123",
  "actor_id": "user_john_doe",
  "actor_ip": "192.168.1.100",
  "action": "pqc_sign",
  "resource_type": "private_key",
  "resource_id": "my_ml_dsa_key",
  "algorithm": "ML_DSA_65",
  "status": "Success",
  "metadata": {
    "data_length": 1024,
    "signature_length": 3293,
    "request_id": "req_xyz789"
  },
  "hmac_chain": "a1b2c3d4e5f6..."
}

Session Pool 與效能優化

deadpool 連接池配置

FfiSessionManager 實作 (deadpool Manager trait):

建立 Session (create):

  1. 開啟新 PKCS#11 Session
  2. 使用 PIN 登入 HSM(RW Session 需要)
  3. 封裝為 FfiSession 物件回傳

回收 Session (recycle):

  1. 健康檢查:產生 16 bytes 隨機數測試 Session 是否有效
  2. Session 正常 → 回傳 Ok(可重用)
  3. HSM 斷線錯誤 → 回傳 StaticError(需重建)

建立連接池 (create_session_pool):

  1. 初始化 FFI 上下文(載入 Cryptoki 函式庫)
  2. 建立 FfiSessionManager
  3. 配置 deadpool:
    • max_size:連接池大小
    • runtime:Tokio 非同步執行環境
  4. 回傳連接池實例

配置建議

場景Pool SizeSession 類型
低流量 API10-20RW (讀寫)
中等流量30-50RW
高流量50-100RW + RO (只讀) 混合
批次處理100-200專用 Pool

效能優化技巧

1. 符號快取(Symbol Caching)

問題:每次 FFI 調用都執行 dlsym 查找函數符號,耗時 ~10-50 µs

解決方案:一次性載入所有 PKCS#11 函數指標並快取

  • 建立 FfiSymbols 結構儲存函數指標(C_Initialize, C_Sign, C_Verify 等)
  • 初始化時使用 library.get() 載入所有符號
  • 後續調用直接使用快取的函數指標

效能提升:每次操作節省 ~10-50 µs

2. 批次操作

批次簽章策略 (batch_sign):

  1. 從連接池取得單一 Session
  2. 循環處理多個訊息簽章(共享同一個 Session)
  3. 減少 Session 取得/釋放的開銷

3. 預熱(Warm-up)

預熱連接池流程 (warmup_pool):

  1. 應用啟動時預先建立所有 Session(達到 max_size
  2. 測試每個 Session(產生隨機數驗證連線)
  3. 釋放 Session 回連接池
  4. 避免首次請求的冷啟動延遲

錯誤處理與韌性

Circuit Breaker 模式

Circuit Breaker 機制(防止 HSM 故障時雪崩效應):

三種狀態

  • Closed(關閉):正常運作,所有請求通過
  • Open(開啟):達到失敗閾值,拒絕所有請求(快速失敗)
  • HalfOpen(半開):超時後嘗試恢復,允許部分請求測試

運作邏輯

  1. Closed 狀態

    • 正常處理請求
    • 失敗時記錄錯誤計數
    • 達到閾值(如 5 次)→ 切換到 Open
  2. Open 狀態

    • 直接拒絕請求(不呼叫 HSM)
    • 超時後(如 30 秒)→ 切換到 HalfOpen
  3. HalfOpen 狀態

    • 允許請求通過測試
    • 成功 → 切換回 Closed
    • 失敗 → 切換回 Open

使用範例

  • 初始化:CircuitBreaker::new(failure_threshold: 5, timeout: 30s)
  • 包裹 HSM 操作:circuit_breaker.call(|| session.ml_dsa_sign(...))

重試策略

use tokio::time::{sleep, Duration};

pub async fn retry_with_backoff<F, T, E>(
    mut f: F,
    max_retries: u32,
) -> Result<T, E>
where
    F: FnMut() -> Result<T, E>,
    E: std::error::Error,
{
    let mut attempt = 0;

    loop {
        match f() {
            Ok(result) => return Ok(result),
            Err(e) if attempt < max_retries => {
                attempt += 1;
                let backoff = Duration::from_millis(100 * 2_u64.pow(attempt));
                tracing::warn!(
                    "操作失敗,{}ms 後重試(第 {}/{} 次): {}",
                    backoff.as_millis(),
                    attempt,
                    max_retries,
                    e
                );
                sleep(backoff).await;
            }
            Err(e) => return Err(e),
        }
    }
}

效能基準測試

單一操作延遲

在 AMD AI+ 395 + Thales Luna A790 環境下的測試結果:

操作平均延遲中位數P95P99吞吐量
ML-DSA-44 簽章1.8 ms1.7 ms2.3 ms3.1 ms~550 ops/sec
ML-DSA-65 簽章2.5 ms2.4 ms3.2 ms4.5 ms~400 ops/sec
ML-DSA-87 簽章4.1 ms4.0 ms5.3 ms7.2 ms~240 ops/sec
ML-DSA-44 驗證0.9 ms0.8 ms1.2 ms1.7 ms~1,100 ops/sec
ML-DSA-65 驗證1.3 ms1.2 ms1.7 ms2.4 ms~770 ops/sec
ML-DSA-87 驗證2.0 ms1.9 ms2.6 ms3.6 ms~500 ops/sec
ML-KEM-512 封裝0.8 ms0.7 ms1.0 ms1.4 ms~1,250 ops/sec
ML-KEM-768 封裝1.2 ms1.1 ms1.5 ms2.1 ms~830 ops/sec
ML-KEM-1024 封裝1.7 ms1.6 ms2.2 ms3.0 ms~590 ops/sec
ML-KEM-512 解封裝0.9 ms0.8 ms1.1 ms1.5 ms~1,110 ops/sec
ML-KEM-768 解封裝1.3 ms1.2 ms1.6 ms2.2 ms~770 ops/sec
ML-KEM-1024 解封裝1.8 ms1.7 ms2.3 ms3.2 ms~550 ops/sec
HSS/LMS (H=10) 簽章5.2 ms5.0 ms6.8 ms9.1 ms~190 ops/sec
HSS/LMS (H=10) 驗證0.5 ms0.4 ms0.7 ms0.9 ms~2,000 ops/sec

觀察

  • ML-DSA 簽章比驗證慢 ~2-3 倍
  • ML-KEM 封裝與解封裝效能接近
  • HSS/LMS 驗證極快(僅需雜湊運算)

API 介面效能對比

同樣的 ML-DSA-65 簽章操作,透過不同 API 介面的延遲:

介面平均延遲吞吐量適用場景
gRPC UDS (Unix Domain Socket)50-100 µs10,000-20,000 ops/sec本機微服務間通訊
gRPC TCP (localhost)100-500 µs2,000-10,000 ops/sec同機器跨容器
gRPC TCP (區域網路)500-2,000 µs500-2,000 ops/sec跨機器微服務
REST HTTP (localhost)1-5 ms200-1,000 ops/sec外部 API、測試
NATS (異步消息)200-500 µs2,000-5,000 ops/sec異步任務隊列

建議

  • 高頻內部調用:優先使用 gRPC UDS
  • 跨機器調用:使用 gRPC TCP (HTTP/2 多路複用)
  • 外部 API:使用 REST HTTP (易於整合)
  • 異步處理:使用 NATS (解耦、高可用)

平行效能測試

測試場景:100 個平行客戶端,每個發送 1,000 次 ML-DSA-65 簽章請求

Session Pool Size平均延遲P95 延遲吞吐量CPU 使用率
10125 ms380 ms800 ops/sec45%
3048 ms142 ms2,080 ops/sec72%
50 (推薦)32 ms95 ms3,125 ops/sec85%
10030 ms88 ms3,333 ops/sec88%
20029 ms85 ms3,448 ops/sec90%

結論

  • Pool Size = 50 達到最佳性價比
  • 超過 100 後,邊際收益遞減
  • HSM 硬體本身成為瓶頸(~3,500 ops/sec)

與傳統演算法對比

演算法簽章延遲驗證延遲簽章大小抗量子攻擊
ML-DSA-652.5 ms1.3 ms3,293 B✅ 是
RSA-30728.2 ms0.3 ms384 B❌ 否
ECDSA P-2561.1 ms1.3 ms64 B❌ 否
EdDSA Ed255190.8 ms1.2 ms64 B❌ 否

重要觀察

  • ML-DSA-65 簽章延遲僅為 RSA-3072 的 30%(更快!)
  • ML-DSA-65 驗證延遲與 ECDSA/EdDSA 相當
  • 簽章大小是主要劣勢(3 KB vs 64-384 B)

部署與運維

Docker 容器化部署

多階段建置策略

  1. Stage 1 (Builder)

    • 基礎映像:rust:1.85-slim
    • 安裝建置依賴(ca-certificates、libssl-dev)
    • 預先下載 Cargo 依賴(利用 Docker 快取)
    • 編譯 Release 版本
  2. Stage 2 (Runtime)

    • 基礎映像:debian:bookworm-slim
    • 僅包含執行時依賴
    • 建立非 root 用戶(安全性)
    • 暴露端口:8080(REST)、50051(gRPC)、9100(Metrics)
    • 健康檢查:30 秒間隔

Docker Compose 部署配置

關鍵配置項

  • Volume 掛載:Luna Client 庫(只讀)、Chrystoki.conf、稽核日誌
  • 環境變數:HSM_PIN、SLOT_ID、SESSION_POOL_SIZE(50)
  • 資源限制:CPU 4 核、記憶體 4 GB(限制)、2 核/2 GB(預留)
  • 重啟策略:unless-stopped(除非手動停止)
  • 日誌輪替:最大 100 MB,保留 10 個檔案
  • 網路隔離:獨立 crypto-network

整合監控服務

  • Prometheus(指標收集)

  • Grafana(視覺化)

  • Alertmanager(警示) - prometheus-data:/prometheus ports: - “9090:9090” command: - ‘—config.file=/etc/prometheus/prometheus.yml’ - ‘—storage.tsdb.path=/prometheus’ - ‘—storage.tsdb.retention.time=30d’ networks: - crypto-network

    Grafana 視覺化

    grafana: image: grafana/grafana:latest container_name: grafana volumes: - ./monitoring/grafana/dashboards:/etc/grafana/provisioning/dashboards:ro - ./monitoring/grafana/datasources:/etc/grafana/provisioning/datasources:ro - grafana-data:/var/lib/grafana ports: - “3000:3000” environment: - GF_SECURITY_ADMIN_PASSWORD=admin networks: - crypto-network

volumes: crypto-audit: driver: local crypto-logs: driver: local prometheus-data: driver: local grafana-data: driver: local

networks: crypto-network: driver: bridge


**啟動服務**:

```bash
# 建立 .env 檔案
cat > .env << EOF
HSM_PIN=your-secret-pin
EOF

# 啟動所有服務
docker compose up -d

# 查看日誌
docker compose logs -f crypto-service

# 健康檢查
curl http://localhost:8080/health
curl http://localhost:9100/metrics  # Prometheus metrics

監控整合

Prometheus 配置 (monitoring/prometheus.yml):

global:
  scrape_interval: 15s
  evaluation_interval: 15s

scrape_configs:
  - job_name: 'crypto-service'
    static_configs:
      - targets: ['crypto-service:9100']
    scrape_interval: 15s
    metrics_path: /metrics

關鍵監控指標

Metric 名稱類型說明
crypto_service_requests_totalCounter總請求數(按 endpoint、method、status)
crypto_service_request_duration_secondsHistogram請求延遲分佈
crypto_service_pqc_operations_totalCounterPQC 操作計數(按 algorithm、operation)
crypto_service_hsm_session_pool_sizeGaugeSession Pool 大小
crypto_service_hsm_session_pool_idleGauge閒置 Session 數量
crypto_service_hsm_errors_totalCounterHSM 錯誤計數(按 error_type)
crypto_service_audit_logs_totalCounter稽核日誌寫入數

警示規則範例 (monitoring/alerts.yml):

groups:
  - name: crypto_service
    rules:
      # HSM 斷線警示
      - alert: HSMDisconnected
        expr: rate(crypto_service_hsm_errors_total{error_type="hsm_disconnected"}[5m]) > 0
        for: 1m
        labels:
          severity: critical
        annotations:
          summary: "HSM 已斷線"
          description: "過去 5 分鐘內偵測到 HSM 斷線錯誤"

      # 高錯誤率警示
      - alert: HighErrorRate
        expr: rate(crypto_service_requests_total{status="error"}[5m]) > 10
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "錯誤率過高"
          description: "過去 5 分鐘平均錯誤率超過 10 req/sec"

      # Session Pool 耗盡
      - alert: SessionPoolExhausted
        expr: crypto_service_hsm_session_pool_idle == 0
        for: 2m
        labels:
          severity: warning
        annotations:
          summary: "Session Pool 耗盡"
          description: "所有 HSM Session 都在使用中,可能需要增加 pool size"

Kubernetes 部署

Deployment 關鍵配置

項目配置
副本數3(高可用)
節點選擇器hsm.luna.enabled: "true"(專用節點)
端口8080(HTTP)、50051(gRPC)、9100(Metrics)
環境變數HSM_PIN(Secret)、SESSION_POOL_SIZE(50)
Volume 掛載Luna Client、Chrystoki.conf、應用配置、稽核儲存(PVC)
資源配置Request: 2 核/2 GB,Limit: 4 核/4 GB
健康檢查Liveness: 30 秒,Readiness: 10 秒

Service 配置

  • 類型:ClusterIP(內部服務)
  • 端口映射:80→8080(HTTP)、50051(gRPC)、9100(Metrics)

關鍵考量

  1. 節點親和性:僅部署到已安裝 Luna Client 的節點
  2. 秘密管理:HSM PIN 儲存在 Kubernetes Secret 中
  3. 持久化儲存:稽核日誌使用 PVC(PersistentVolumeClaim)
  4. Prometheus 整合:透過 annotations 自動服務發現

最佳實踐與陷阱

金鑰管理最佳實踐

推薦做法

1. 金鑰類型選擇

  • 開發/測試:使用 Session 金鑰(token_object = false,程式結束自動清除)
  • 生產環境:使用 Token 金鑰(token_object = true,持久化)

2. 金鑰標籤命名規範

// 生產環境:Token 金鑰(持久化到 HSM)
let (pub_handle, priv_handle) = session.generate_ml_dsa_keypair(
    MlDsaParam::Level65,
    "prod_signing_key_2026",
    true,   // token_object = true
).await?;

3. 使用描述性的金鑰標籤

//  好的標籤:包含用途、演算法、日期
"api_auth_ml_dsa_65_2026_02"
"firmware_sign_hss_lms_2026"
"kem_session_ml_kem_768_20260203"

//  差的標籤
"key1"
"test"
"my_key"

4. 定期輪換金鑰

  • 建議每 90 天輪換一次
  • 流程:產生新金鑰 → 更新配置 → 等待舊金鑰閒置 → 刪除舊金鑰

5. 匯出公鑰進行備份

  • 公鑰可匯出並安全分享
  • 私鑰永不離開 HSM

DON’T(避免的做法)

1. 不要在 HSM 中儲存過多金鑰

  • Luna HSM 儲存容量有限
  • 應定期清理不再使用的金鑰
  • 金鑰數量與查詢時間成正比

2. 不要重複使用相同標籤

  • 可能導致 find_key_by_label() 找到舊金鑰
  • 應先刪除舊金鑰或使用不同標籤(加入日期)

3. 不要忽略金鑰使用次數限制(HSS/LMS)

  • HSS/LMS 金鑰簽章次數有上限(由樹高決定)
  • 應定期檢查並提前輪換

4. 不要硬編碼 HSM PIN

  • 硬編碼在程式碼中極度危險
  • 從環境變數讀取
  • 更好:從 Secret Manager(Vault/AWS Secrets Manager)讀取

安全考量

1. 網路隔離

Mermaid diagram

Firewall 規則

  • 只允許 Crypto Service IP 存取 HSM(Port 1792)
  • 拒絕其他來源的連線

2. mTLS 認證

gRPC Server 配置要點

  • 載入伺服器憑證和私鑰
  • 配置客戶端 CA 憑證(驗證客戶端身份)
  • 啟用雙向 TLS 認證 .add_service(HsmServiceServer::new(service)) .serve(addr) .await?;

#### 3. API 速率限制

```rust
use tower::limit::RateLimitLayer;
use std::time::Duration;

let rate_limit = RateLimitLayer::new(
    100,                          // 每秒最多 100 請求
    Duration::from_secs(1),
);

let app = Router::new()
    .route("/api/v1/pqc/sign", post(pqc_sign))
    .layer(rate_limit);

4. 輸入驗證

//  驗證資料大小
const MAX_MESSAGE_SIZE: usize = 1024 * 1024;  // 1 MB

pub async fn pqc_sign(
    Json(input): Json<PqcSignInput>,
) -> Result<Json<PqcSignOutput>, ApiError> {
    // 驗證資料大小
    if input.data.len() > MAX_MESSAGE_SIZE {
        return Err(ApiError::PayloadTooLarge);
    }

    // 驗證演算法
    if !matches!(input.algorithm, PqcAlgorithm::MlDsa44 |
                 PqcAlgorithm::MlDsa65 | PqcAlgorithm::MlDsa87) {
        return Err(ApiError::UnsupportedAlgorithm);
    }

    // 執行簽章
    let result = domain::handlers::pqc::pqc_sign(&core, input).await?;
    Ok(Json(result))
}

效能調優

1. Session Pool 大小調整

經驗法則

Pool Size = (預期 QPS × 平均操作延遲) × 1.5

範例:
- 預期 QPS: 1,000
- ML-DSA-65 簽章延遲: 2.5 ms = 0.0025 sec
- Pool Size = 1000 × 0.0025 × 1.5 = 3.75 ≈ 4

但考慮突發流量,建議設定為 10-20

動態調整

// 監控 Pool 使用率
let pool_usage = (pool.status().size - pool.status().available) as f64
                 / pool.status().size as f64;

if pool_usage > 0.8 {
    eprintln!("Session Pool 使用率過高: {:.1}%", pool_usage * 100.0);
    // 考慮增加 Pool Size 或延伸服務
}

2. 快取公鑰

use moka::future::Cache;

pub struct PublicKeyCache {
    cache: Cache<String, Vec<u8>>,  // label -> public_key_bytes
}

impl PublicKeyCache {
    pub fn new() -> Self {
        let cache = Cache::builder()
            .max_capacity(1000)
            .time_to_live(Duration::from_secs(3600))  // 1 小時
            .build();

        Self { cache }
    }

    pub async fn get_or_fetch(
        &self,
        session: &FfiSession,
        label: &str,
    ) -> Result<Vec<u8>, Pkcs11Error> {
        if let Some(cached) = self.cache.get(label).await {
            return Ok(cached);
        }

        let pub_handle = session.find_key_by_label(label.as_bytes(), CKO_PUBLIC_KEY)?;
        let pub_key_bytes = session.get_ml_dsa_public_key(pub_handle).await?;

        self.cache.insert(label.to_string(), pub_key_bytes.clone()).await;

        Ok(pub_key_bytes)
    }
}

3. 批次處理

//  效率低:逐個簽章
for message in messages {
    let sig = session.ml_dsa_sign(priv_handle, message, param).await?;
    signatures.push(sig);
}

//  效率高:批次簽章(共用 Session)
let session = pool.get().await?;
let mut signatures = Vec::with_capacity(messages.len());

for message in messages {
    let sig = session.ml_dsa_sign(priv_handle, message, param).await?;
    signatures.push(sig);
}
drop(session);  // 一次性釋放 Session

未來展望

混合密碼學方案

雙重簽章憑證(Composite Signatures):

Certificate {
    tbsCertificate: {
        subject: "CN=example.com",
        subjectPublicKeyInfo: {
            algorithm: id-composite-key,
            subjectPublicKey: (ECC P-256 公鑰, ML-DSA-65 公鑰)
        }
    },
    signatureAlgorithm: id-composite-signature,
    signature: (ECDSA 簽章, ML-DSA-65 簽章)
}

優勢

NIST 第四輪候選演算法

演算法類型狀態預計標準化
FALCON簽章標準化中 (FIPS 206)2026 Q3
BIKEKEM第四輪候選2027+
HQCKEM第四輪候選2027+

FALCON 特色

  • 簽章大小極小(~666 B for FALCON-512)
  • 驗證極快
  • 適合資源受限環境(IoT)

量子安全通訊協議

TLS 1.3 PQC 支援RFC 9370):

ClientHello:
  - supported_groups: x25519_mlkem768, secp256r1_mlkem768
  - signature_algorithms: ecdsa_secp256r1_mlkem768

ServerHello:
  - key_share: x25519_mlkem768
  - signature: ecdsa_secp256r1_mlkem768

混合金鑰交換

  • X25519 (ECDH) + ML-KEM-768
  • 即使一方被破解,另一方仍提供保護

結語與資源

關鍵要點

  1. 後量子威脅真實存在:「先儲存後破解」攻擊已在進行中
  2. NIST 標準已完成:ML-DSA/ML-KEM 已正式標準化(FIPS 203/204)
  3. Luna HSM + Rust = 最佳組合:硬體安全 + 記憶體安全
  4. 自定義 FFI 綁定必要:解決相容性問題,支援 Luna 專有延伸
  5. 企業級特性完整:SOC2 稽核、Session Pool、Circuit Breaker
  6. 效能媲美傳統演算法:ML-DSA-65 簽章比 RSA-3072 更快

專案資源

參考文件

延伸閱讀


本文完成於 2026-02-03,基於 Thales Luna HSM Firmware 7.9.1、Rust 1.85 與 NIST FIPS 203/204 標準撰寫。

如有任何問題或建議,歡迎透過聯絡我們 頁面與我們聯繫。