Nonce

如何使用 AEAD 密碼防止意外的 nonce 重用

  • May 24, 2019

我正在嘗試在我的 node.js 應用程序中正確實現 ChaCha20-Poly1305(…加密很難)。我知道密碼需要為每條消息使用唯一的密鑰/隨機數對,否則安全性會崩潰。

隨機數不必是隨機的或不可預測的,所以一個簡單的計數器就足夠了。我的問題是我無法弄清楚如何實現一個有效的計數器,該計數器將與我的應用程序在同一台機器上同時執行的多個實例一起工作,並保證不會重複使用隨機數。

基本上,我想知道如何避免這種 footgun

我的一些想法:

  • 使用時間戳。顯然不是一個好主意
  • 使用redis INCR。複雜的開發環境(我現在需要在我開發的每台電腦上安裝 redis),而且我仍然沒有強有力的保證,即在意外關閉的情況下我不會得到重複值(即使使用 Redis AOF)。
  • 每次創建 nonce 時寫入文件或數據庫表。這應該可以,但是性能不會很好,而且我可能仍然會在意外關機的情況下陷入困境。
  • 使用 UUIDv1 或 v4 類型的東西(來自此評論)。最初 v1 看起來很完美(保證唯一性),但它與系統 MAC 地址相關,所以當我啟動應用程序的多個副本時,我可能會扼殺任何類型的保證。然後是 v4,它應該很好,但是因為 nonce 只有 96 位,我需要截斷 ID 並增加我的衝突機率(實際上 v1 也是如此)。如果我走這條路,我在看nanoid
  • 定期輪換密鑰。我意識到無論如何都需要這樣做,但我想盡量減少它需要發生的頻率。
  • 類似於 Twitter 的雪花。flake-idgen似乎非常適合這個(保證唯一性,由機器/工人或實例 ID 分區,除了確定實例 ID 之外不需要協調,生成足夠短的 ID)。
  • 使用 XChaCha20-Poly1305。出於這個原因,在libsodium 文件中特別推薦它(nonce 足夠大,您可以向它拋出隨機值而不必擔心)。但是,它還不是一個標準(還不是?),它需要引入 libsodium 來進行加密,而不是依賴節點內置的 OpenSSL 包裝器。這使開發複雜化(處理本地綁定)和/或破壞安全性(在 js/WebAssembly 中執行加密的持續時間問題……遠遠超過我的工資等級)。

我錯過了一些明顯的東西嗎?人們通常如何解決這類問題?現在,我喜歡 flake-idgen,但它似乎沒有受到太多審查,所以似乎有可能導致重複 id 的極端情況(閏秒、閏年、意外的伺服器時鐘重置、惡意 NTP 伺服器等)。

**更新:**好的,所以共識似乎是只使用一個隨機的隨機數,不要太擔心它。對於我的規模,我認為這會很好。

我在測試 flake-idgen 時發現了一些問題,所以我認為我不會真正使用它(儘管它看起來仍然是一個很酷的項目)。

我的替代計劃是編寫一個計數器實現,它生成一個 64 位 BigInt 計數器(在節點 12 中添加了支持)+ 一個 16 位實例 ID + 可能是 16 個隨機位以供娛樂。每增加一次 X 後,我都會將計數器保存到磁碟,這樣我就不會一直寫入磁碟。在伺服器意外關閉的情況下,系統將從磁碟文件中讀取並將 X + 1 添加到目前計數器以確保沒有衝突。

此實現未解決的問題:如何處理環繞?如果伺服器被重置並且沒有可讀取的磁碟文件會發生什麼?

感謝您對此的幫助,如果有人想發布“僅使用隨機”作為答案,我很樂意接受。

如果沒有有關您的應用程序的更多資訊,很難提供明確的答案(這將使 Crypto SE 的問題偏離主題)。但是許多系統使用的一種相關技術是具有兩種類型鍵的層次結構:

  • 短期數據加密密鑰(又名 DEK),在狹窄範圍內隨機生成(例如,您的應用程序的單獨執行)並用於加密實際數據;
  • 用於加密 DEK的長期密鑰加密密鑰(又名 KEK 或主密鑰)。

然後,這個想法是與每條消息的密文一起包含對用於加密消息的加密 DEK 的副本或引用。閱讀器要解密消息,首先解密其 DEK,然後解密密文。這通常稱為信封加密,隱喻每個密文都包含在包含其加密 DEK 的“信封”中。

信封加密通常與密鑰管理系統(KMS) 結合使用,這是一種強化服務,它“擁有”主密鑰並代表經過身份驗證和授權的客戶端執行加密/解密操作。這個想法是您的應用程序實例實際上並沒有獲得主密鑰的副本。相反,他們必須向 KMS 進行身份驗證並請求它代表他們執行主密鑰操作。(當然,您需要仔細考慮這對性能的影響——理想情況下,您希望 KMS 加密/解密請求與使用 DEK 加密/解密的數據量的比例很小。)

這種架構流行的一個原因是有實現 KMS 功能的雲服務和軟體產品:

這與您關於 nonce 管理的問題相關聯的方式是,如果您擁有此基礎架構(您可能獨立想要),則 nonce 管理問題會大大簡化,因為在您即將加密但您不能保證的任何情況下您可以產生一個獨特的隨機數,你可以產生一個新的 DEK。例如,您的應用程序的每個實例可能只是在啟動時這樣做,並保留一個保證在程序中唯一的計數器。

如果您有興趣,雲供應商會提供有用的概念文件:

引用自:https://crypto.stackexchange.com/questions/70686