題干與適用場景
多租戶設定服務要加密資料庫中的敏感值。每個租戶有獨立邏輯金鑰,平台需要輪換根金鑰、繼續讀取舊密文,並能偵測密文被替換或跨租戶複製。請使用 Go 1.26 crypto/hpke 設計信封格式、加密/解密流程、金鑰版本、上下文綁定與遷移策略。核心考察密碼學 API 的正確組合與生命週期設計,因此歸為 coding。
面試官考察點
第一,能否理解 HPKE 的 KEM、KDF、AEAD 分工,並區分公鑰封裝與對稱資料加密。
第二,能否選擇 Base、PSK 或 Auth 模式,說明認證金鑰與機密性金鑰的責任邊界。
第三,能否把租戶、用途、演算法套件與版本綁定到 info 或 AAD,防止跨上下文解密。
第四,能否設計金鑰輪換、舊版本讀取、撤銷與密文重加密,不把版本號當作秘密。
第五,能否用竄改、重放、隨機數、失敗訊息與互通性測試驗證實作。
回答前需要澄清的問題
- 設定服務只需機密性,還是也需要傳送方認證?
- 接收者公鑰由誰託管,是否有 KMS/HSM 與稽核要求?
- 輪換後舊密文保留多久,是否需要背景重加密?
- 租戶上下文與設定鍵是否屬於可公開的關聯資料?
- 是否需要跨語言解密或離線復原?
- 失敗時要區分金鑰不存在、版本不支援與認證失敗嗎?
30 秒回答框架
「我先固定 RFC 9180 套件與 Go 1.26 版本。服務端為每個租戶保存接收者私鑰,應用用公鑰做 HPKE 封裝;密文記錄套件、key version、租戶與用途元資料,真正的租戶/用途綁定放進 info 與 AEAD AAD。解密按版本讀取舊私鑰,輪換後新寫入使用新版本,背景非同步重加密。若需要傳送方認證再選 Auth 模式;否則不偽造認證語義。測試涵蓋竄改、跨租戶、重放、隨機性、舊版本與跨語言向量。」
分步驟深入解答
第一步:劃分信封加密層
HPKE 透過 KEM 建立共享金鑰,再由 KDF 推導金鑰,AEAD 加密訊息。信封記錄封裝公鑰材料、演算法套件、key version、nonce/序列化密文與公開元資料;根私鑰與接收者私鑰留在 KMS/HSM,不能寫入密文或應用日誌。
第二步:選擇模式與身分語義
Base 模式提供接收者公鑰加密但不認證傳送方;PSK 模式額外要求預共享金鑰;Auth 模式用傳送方金鑰證明來源。不要因為有平台登入身分就宣稱 HPKE 已認證傳送方,登入授權與密碼學模式是不同層。
第三步:定義上下文綁定
info 綁定協定、服務、版本與用途;AAD 綁定租戶 ID、設定鍵、記錄版本等需要完整性保護的元資料。解密時重新計算相同輸入,任何租戶、用途或版本替換都會讓 AEAD 驗證失敗。
envelope = suite_id | key_version | encapsulated_key | aad_fields | ciphertext
info = "config-envelope/v1" | tenant_scope | purpose
aad = tenant_id | config_key | record_version第四步:設計金鑰生命週期
每個 key version 有產生時間、狀態、允許解密範圍與銷毀策略。輪換先發布新公鑰,再切換寫入版本;讀取按 envelope 版本選擇舊私鑰。舊版本進入唯讀窗口,完成重加密與稽核確認後才能撤銷,避免先刪金鑰造成不可復原資料遺失。
第五步:處理重放與序列化
AEAD 能偵測竄改,不會自動阻止把合法舊密文重新寫回。若設定有版本或單調序列,解密後由業務層檢查 expected version;封裝格式使用明確長度與版本欄位,拒絕未知套件、截斷資料與重複欄位。
第六步:設計錯誤邊界
對外可統一回傳「無法解密」,內部稽核記錄結構化原因與 key version,但不能記錄私鑰、明文或完整密文。區分金鑰不存在、格式不支援與認證失敗有助於維運;對不可信呼叫者要避免透過錯誤差異洩露租戶或金鑰存在性。
第七步:建立測試與遷移
測試固定 RFC 向量、隨機性、竄改單一位元組、跨租戶 AAD、舊版本讀取、輪換並發、撤銷後失敗與大訊息分塊。跨語言場景使用共享序列化與測試向量;Go 1.26 之前服務透過相容封裝或升級門禁接入,不把實驗 API 混入生產。
高品質示範回答
「我把 HPKE 當作封裝層:KEM/KDF 建立並推導共享金鑰,AEAD 保護設定明文。信封包含套件、key version、封裝材料與密文;租戶、用途、設定鍵與記錄版本綁定到 info/AAD,防止跨租戶複製。Base 模式只提供接收者機密性,需要傳送方證明時才選 Auth 或上層簽章。輪換採用新版本先寫、舊版本唯讀、背景重加密、確認後撤銷。AEAD 不防重放,所以業務層檢查版本。測試涵蓋竄改、舊版本、撤銷、錯誤訊息與跨語言向量,私鑰只在 KMS/HSM 中。」
常見錯誤
- 把 Base 模式當傳送方認證 → 接收者無法證明傳送者身分 → 選擇 Auth 或額外簽章。
- 只把租戶寫在明文元資料 → 攻擊者可跨租戶替換 → 綁定到
info/AAD 並驗證。 - 輪換後立即刪除舊金鑰 → 歷史資料無法讀取 → 先唯讀相容與重加密,再撤銷。
- 認為 AEAD 自動防重放 → 合法舊密文仍可被重新提交 → 使用業務版本或序列檢查。
- 把私鑰放進設定或日誌 → 加密邊界被破壞 → 使用 KMS/HSM 與最小權限。
- 自訂無版本二進位格式 → 未來無法遷移與拒絕未知套件 → 明確版本、長度與套件欄位。
- 暴露詳細解密錯誤 → 洩露租戶或金鑰存在性 → 外部統一、內部稽核。
- 只測成功路徑 → 竄改與舊版本問題留到生產 → 加入向量、跨上下文與撤銷測試。
追問及應對
追問一:為什麼不用直接 RSA 或 ECDH 加密全部明文?
HPKE 明確組合 KEM、KDF 與 AEAD,適合封裝對稱會話金鑰並處理大訊息;直接用公鑰演算法加密任意明文容易遇到長度、隨機性與模式誤用問題。
追問二:何時選擇 Auth 模式?
當接收者需要密碼學證明某個已知傳送方金鑰參與加密時選擇 Auth;只有接收者機密性需求時不應加入未管理的認證金鑰。
追問三:info 與 AAD 有什麼差別?
info 參與金鑰推導並定義協定上下文;AAD 不加密但由 AEAD 完整性保護,適合綁定隨信封傳輸且解密時必須一致的元資料。
追問四:如何安全重加密?
讀取舊版本並在同一交易或可重試工作流中寫入新版本,保留冪等標記;只有新密文通過解密回讀與稽核校驗後,才推進舊金鑰撤銷。
追問五:如何防止密文替換到另一筆記錄?
把租戶、設定鍵、記錄版本與用途放入 AAD,並在讀取時使用資料庫目前值重建 AAD;替換後認證標籤不匹配,解密失敗。
追問六:HPKE 是否提供前向保密?
具體性質取決於金鑰生命週期與模式。靜態接收者私鑰長期保留時,歷史密文的保護取決於該私鑰;需要更強前向保密時要設計臨時金鑰、輪換、銷毀與協定級會話策略,不能只看 API 名稱。