跳至主要內容

每個物件一把金鑰:NT² Vault 內的信封加密

閱讀時間 8 分鐘 作者 NT²

保管箱可以用一把金鑰加密所有資料,並且仍然宣稱資料經過加密。但我們希望採用更實用的邊界:每個項目與附件都有自己的內容加密金鑰,再由保管箱金鑰保護這些金鑰。

每個物件一把金鑰:NT² Vault 內的信封加密

我們常把加密描述成一個開關:資料不是已加密,就是未加密。但實際設計儲存系統時,底下還有另一個問題:每一把金鑰究竟加密什麼?

最簡單的答案是用一把金鑰處理全部內容。使用者解鎖時取得保管箱金鑰,以該金鑰透過 AES-GCM 加密每個項目與附件,再儲存產生的密文。只要金鑰與初始化向量的處理正確,這確實能保護靜態資料中的明文。

然而,第一次寫入時的簡單,可能把複雜度推給之後的每個操作。輪替金鑰、共用單一項目、只同步一個有變更的附件,或從損壞資料中復原,都會與整座保管箱的加密邊界糾纏在一起。

NT² Vault 改採信封加密。每個項目與附件都有獨立、隨機產生的內容加密金鑰(content encryption key,CEK)。CEK 負責加密該物件的內容;保管箱金鑰不直接加密每一位元組的使用者內容,而是包裝這些 CEK。

這項區分會增加欄位與操作,卻也讓系統獲得更清楚的保護單位:一個物件、一把內容金鑰、一份加密內容。

限制:保管箱不是不可分割的單一資料塊

保管箱在介面上看起來是一個整體,底層卻是由大小、生命週期與目的地各不相同的物件所組成。

一筆登入憑證可能一週修改數次;掃描的護照可能是很少變動的大型附件;一則筆記之後或許要共用,但保管箱內其他內容仍須保持私密。另一台裝置可能只需要取得上次同步後有變更的物件。有些資料適合放在關聯式儲存空間中供查詢,大型二進位密文則適合檔案式儲存空間。

若把所有內容都視為一個保管箱範圍的密文資料塊,就會出現棘手的選擇:

  • 一次小幅編輯可能需要重寫或重新傳輸大型加密單位。
  • 金鑰輪替可能代表必須解密並重新加密每份內容。
  • 共用單一物件時,設計可能被迫暴露遠超過該物件範圍的金鑰。
  • 部分同步會變得困難,因為密碼學邊界與同步邊界並不一致。
  • 資料損毀或實作錯誤可能一次影響保管箱中更大範圍的內容。

將物件分開儲存、卻直接使用同一把保管箱金鑰加密所有內容,可以避免重寫單一大檔案,但更換該金鑰時仍須處理每份密文。NT² Vault 改為讓加密邊界符合產品的工作單位:項目或附件。

設計:下層是資料金鑰,上層是保管箱金鑰

信封加密把兩項工作分開:

  1. 每個物件的 CEK 加密該物件的內容。
  2. 保管箱金鑰加密(也就是包裝)該 CEK。

NT² Vault 建立項目時,用戶端會產生全新的隨機 CEK。系統使用 AES-GCM 與新的初始化向量加密項目的結構化內容,接著以保管箱金鑰執行另一次 AES-GCM 操作,搭配另一個新的 IV 包裝 CEK。

概念上,儲存的項目包含:

  • 項目內容的密文;
  • 內容加密所使用的 IV;
  • 經包裝的 CEK;
  • 包裝 CEK 所使用的 IV;以及
  • 定位與管理記錄所需的非機密欄位。

附件使用相同的金鑰階層。新的 CEK 加密二進位內容,再由保管箱金鑰包裝該 CEK。附件記錄包含定位、驗證與重建加密二進位內容所需的中繼資料,但不會把明文檔案放進資料庫。

flowchart LR
    VK[記憶體中的保管箱金鑰] -->|AES-GCM 包裝| ICK[項目 CEK]
    VK -->|AES-GCM 包裝| ACK[附件 CEK]
    ICK -->|AES-GCM 加密| IP[項目內容密文]
    ACK -->|AES-GCM 加密| AB[附件二進位密文]

解鎖保管箱後,保管箱金鑰會在記憶體中可供使用。開啟物件時,系統依反方向處理這個階層:

  1. 讀取物件經包裝的 CEK 與包裝 IV。
  2. 以保管箱金鑰解開 CEK。
  3. 使用該 CEK 與內容 IV 解密物件。
  4. 不把明文與工作中的金鑰寫入持久儲存空間。

這是一個金鑰階層,而不是一串密碼。使用者不必為每個項目管理一組密碼。應用程式在本機產生並管理 CEK,而保管箱金鑰則是授權存取這些金鑰的根。

為什麼 AES-GCM 會出現兩次

AES-GCM 提供認證加密。它不只隱藏明文,也能驗證密文是否在未被察覺的情況下遭到修改。這項特性對兩個加密層都很重要。

在內容層,認證有助於偵測被修改的項目內容或附件區塊;在包裝層,它有助於偵測被修改的 CEK 信封。損壞的金鑰信封應安全地拒絕解密,而不是悄悄產生看似合理、實際錯誤的明文。

使用同一把金鑰進行 AES-GCM 加密時,每次操作都必須使用全域唯一的 IV。內容加密與金鑰包裝是不同操作,因此各自使用新的 IV。IV 不需要保密,可以與密文一同儲存,但絕非可有可無的簿記。若以同一把 AES-GCM 金鑰重複使用 IV,機密性與完整性都可能受到破壞。

項目放在 SQLite,附件密文放在 BlobStore

金鑰階層也與儲存階層相配合。

結構化項目記錄與附件中繼資料位於保管箱的本機 SQLite 資料庫。SQLite 適合處理關聯與查詢,例如哪些附件屬於某個項目、哪些資料有變更、哪些已封存,以及分頁清單應顯示哪些資料列。

大型加密附件位元組的需求不同。在瀏覽器中,NT² Vault 將附件密文儲存為來源私有檔案系統(Origin Private File System,OPFS)內的檔案,並透過 BlobStore 邊界存取。桌面版則可在本機應用程式檔案之上提供相同的 BlobStore 行為。

因此,資料庫保存具權威性的中繼資料,包括附件識別碼、所屬項目、大小與密碼學信封欄位;BlobStore 保存密文位元組。兩邊都不會保存靜態的明文附件。

這項分離避免大型二進位物件被迫塞進關聯式資料列,同時保留可查詢、可進行交易處理的中繼資料。它也把平台差異隔離在單一儲存介面之下:瀏覽器使用 OPFS、桌面應用程式使用本機檔案時,加密模型不必跟著改變。

最重要的是,儲存位置的區隔不會削弱加密邊界。只有附件加密檔、沒有經包裝的 CEK,無法揭露檔案內容;只有中繼資料、沒有保管箱金鑰,也無法解開 CEK。這些部分只有在獲授權的金鑰階層中才有作用。

輪替金鑰,不必重寫每份內容

信封加密讓金鑰輪替更容易處理,因為內容加密與根金鑰保護是兩項分開的操作。

保管箱金鑰需要變更時,系統可以用舊保管箱金鑰解開各個 CEK,再以新保管箱金鑰重新包裝。大型項目內容與附件加密檔不必只因上層金鑰變更,就全部解密再重新加密。

這不代表輪替毫無成本。每個信封仍須正確處理,整個操作也需要審慎的失敗處理。不過,需要碰觸的資料量取決於小型包裝金鑰的數量,而不是所有加密附件的總大小。

對包含大量相片、PDF 或其他大型檔案的保管箱而言,這項差異尤其重要。重新包裝小型 CEK,與串流處理、解密及重新加密數 GB 的內容,是截然不同的作業。

它也為物件層級的共用或複寫保留空間,不必把整座保管箱當成揭露單位。CEK 本身並不是完整的共用協定——仍需要綁定接收者的加密與授權——但它是正確的起始邊界。

以物件大小為邊界的部分同步

本機優先軟體不應把單一欄位的編輯變成整座保管箱大小的上傳。每物件密文為同步提供了自然單位。

項目變更時,其加密記錄可以獨立同步。加入附件時,中繼資料與加密檔可以透過各自適合的管道傳輸,不必綑綁其他無關的保管箱內容。已經擁有其他所有物件的裝置,不需要再次取得它們。

這既是效能特性,也是安全特性。較小的單位讓重試、完整性檢查、衝突處理與失敗診斷更具體。附件傳輸失敗可以維持為附件傳輸問題,而不是變成單一巨型保管箱檔案的模糊失敗。

取捨:更多中繼資料,更清楚的影響範圍

任何抽象都不是免費的。相較於單一金鑰方案,每物件信封加密需要儲存更多資訊:

  • 每個物件各自的 CEK;
  • 每次加密使用的內容 IV;
  • 經包裝的金鑰密文;
  • 包裝 IV;以及
  • 足以安全解析信封的版本與中繼資料。

建立或開啟物件時,也需要多一次密碼學操作。備份必須保留信封欄位;資料遷移必須理解其格式;測試必須涵蓋損壞的密文、遺失的加密檔、無效的包裝與中斷的寫入。

這些成本值得承擔,因為新增的結構具有實際意義。它縮小每把內容金鑰的影響範圍,明確呈現物件與其加密材料的關係,讓根金鑰變更可以處理信封而非大量內容,也讓加密邊界與共用、同步、儲存及復原邊界一致。

信封加密不是遭入侵執行環境的萬靈丹。控制已解鎖應用程式的攻擊者可能使用保管箱金鑰解開許多 CEK。它的價值是減少不必要的儲存與金鑰管理耦合,而不是承諾入侵永遠不會擴散。

我們拒絕儲存的內容

兩項規則比任何圖表都更能清楚界定邊界。

第一,NT² Vault 不會持久儲存明文項目內容或明文附件。可供搜尋與操作的中繼資料必須限縮範圍,敏感內容在靜態儲存時維持為密文。使用者執行操作時暫時需要的明文應留在記憶體中,而不是寫入 SQLite、OPFS 或伺服器端資料庫。

第二,NT² Vault 不會讓整座保管箱共用一把 CEK。把保管箱範圍的內容金鑰稱為「CEK」,並不會創造物件邊界,只是替保管箱金鑰問題換個名稱。每個項目與附件都會取得自己的內容金鑰。

保管箱金鑰扮演強大但專注的角色:保護金鑰信封。如此便能分別思考存取根、單一物件的金鑰,以及該物件的密文。

小型階層,實用結果

優良的加密架構並不在於加入更多密碼學名詞,而是選擇能經得起真實產品操作的邊界。

項目會獨立變更;附件可能很大;同步只處理部分資料;共用應少於整座保管箱;金鑰有時需要輪替;儲存空間也可能只在單一物件上失敗。相較於整座保管箱共用一份密文或一把內容金鑰,每物件 CEK 更符合這些事實。

保管箱金鑰仍然至關重要。如何取得這把金鑰,以及哪些輔助材料留在裝置上,是設計中的另一個部分;若想了解本機 salt 的邊界,請閱讀為何 KDF salt 留在你的裝置上

信封加密為 NT² Vault 帶來一項實用規則:使用符合內容範圍、且最小的持久金鑰來加密內容,再由保管箱的存取根保護這些金鑰。

你不必自行管理這套階層。開啟 NT² Vault,或前往 se.nt2.me,即可建立一座把加密邊界直接納入儲存模型的本機優先保管箱。

最後更新 2026-07-25

相關故事