從主密鑰生成 2 個獨立密鑰
場景是這樣的:我需要 2 個用於不同目的的密鑰(加密 + 加密、加密 + mac 或其他)。因為重複使用相同的密鑰不是一個好習慣,所以我希望這兩個密鑰是獨立的。但是記住兩個不同的密鑰很麻煩(請不要質疑這個),所以我認為應該有一些方法可以從一個通用主密鑰生成這些密鑰。
我能找到的最接近這項工作的加密工具是 KDF。然而,KDF 通常需要一個額外的輸入:鹽。我應該隨機生成並記住鹽,還是簡單地使用諸如 SHA512 之類的雜湊函式並將其輸出分成 2 個鍵?
我認為在這種情況下,無需擔心可能從派生密鑰中恢復主密鑰,因為派生密鑰不亞於主密鑰。派生密鑰的洩露與主密鑰的洩露一樣糟糕。相反,重要性集中在兩個派生密鑰之間的獨立性上,因為至少有一些加密和 mac 方案,當它們一起使用時,如果密鑰不獨立,就會完全破壞。
- 鹽的目的是限制對手可以在多個目標之間分攤的成本。 鹽不必是隨機的。它只需要每個使用者都是唯一的。
如果兩個使用者共享一個鹽(可能是一個空鹽),那麼找到他們至少一個密鑰的工作可以與一台並行機器上的Oechslin 彩虹表共享,這樣在一個並行機器上找到至少一個他們的密鑰的預期成本批量多目標攻擊大約是單目標攻擊預期成本的一半,而找到至少一個密鑰的預期時間最多是單目標攻擊預期時間的八分之一*。*
一般來說,如果有 $ n $ 可能的鍵,和 $ t $ 目標,然後您將計算並行化 $ p \geq t^2 $ ,那麼找到至少一個的期望成本是 $ n/t $ 找到第一個的預期時間是 $ n/pt $ ,最多約 $ n/t^3 $ .
如果您使用 256 位密鑰,那麼使這一點變得重要所需的使用者數量是不可能的,因此在這種情況下您可以安全地使用空鹽。鹽只對≤128 位的密鑰很重要。(這就是為什麼 AES-128 應該已經被認為具有 <128 位的安全級別,以及為什麼無論如何你都應該使用 AES-256。)
如果您有一個密鑰唯一的使用者 ID 的概念,您可以將它與您的應用程序名稱連接起來作為鹽,而不需要儲存。如果您沒有唯一使用者 ID 的概念,則使用隨機鹽會降低攻擊者在兩個攻擊目標之間共享工作的可能性。鹽分越長,使對手可以共享工作的碰撞機率就越低。使用 256 位鹽,除非您的實現被破壞,否則永遠不會發生衝突。
- KDF 的第二個目的是將高熵但可能不均勻的秘密映射到統一的秘密。 如果您的主密鑰來自 Diffie-Hellman 密鑰協議,並且是殘基類的某個唯一代表以大安全素數為模的某個唯一代表的位串編碼,或者是橢圓曲線上一個點的字節串編碼,那麼主密鑰在位串之間不是均勻分佈的,但確實具有**高熵。KDF 平滑了位串上的分佈,因此它實際上是均勻的。
- 密碼散列(scrypt、argon2等)的目的是利用所有可用資源來提高對散列的單次評估的成本,而暴力攻擊必須重複執行此操作。** 願意在散列上花費 1 秒嗎?強制對手計算 200 萬次(比如)HMAC-SHA256 計算,而不是每次猜測一次。願意在散列上花費 1 GB RAM?迫使對手在每個並行散列電路中送出 1 GB RAM 的區域——如果它不是記憶體硬的,否則可能會專用於更多的並行散列電路,比如 PBKDF2——或者如果他們只能花費兩倍的時間散列適合 512 MB RAM等。 如果你不能提高可能性的數量對於秘密,例如,如果您的秘密是由人類選擇的,您至少可以提高在蠻力攻擊中測試每種可能性的成本。
這些注意事項獨立適用:
- 有人工選擇的密碼嗎?可能有 ≪128 位熵。使用帶有鹽的 argon2id 之類的密碼雜湊來 (a) 提高每次猜測的成本,(b) 將不統一的位串映射為統一的位串,以及 (b) 防止對手在多個目標之間共享工作。確保如果使用者更改了密碼,salt 也會更改,所以如果它是確定性選擇的,它不能只是一個應用程序名稱和使用者 ID——它還必須包括一個修訂號。
- 有一個機器生成的令人難忘的 diceware 密碼,從 $ {\sim}2^{128} $ 可能性?使用帶有鹽的 HKDF 之類的 KDF 來 (a) 將 128 位熵的非均勻位串轉換為均勻位串,以及 (b) 防止對手在多個目標之間共享工作。如果僅在互動式應用程序中使用密碼雜湊來提高每次猜測的成本並沒有什麼壞處,但這不是必需的。
- 有一個共享的秘密編碼 $ x $ 根據 X25519 密鑰協議在 Curve25519 上座標,因此 $ x^3 + 486662 x^2 + x $ 是二次餘數模 $ 2^{255} - 19 $ ? 使用 HKDF 之類的 KDF 將其變成統一的隨機位串。在這種情況下,加鹽不會造成傷害,但這不是必需的。
編輯添加:(來自SEJPM的評論) $ mk $ 需要高熵(實際上是 128 位以上)。
如果你相信隨機預言模型,那麼你不需要記住任何鹽。讓 $ H $ 你是 KDF(建模為隨機預言機),你的主密鑰是 $ mk $ ,則可以生成兩個密鑰 $ k_1=H(1\mathbin|mk),k_2=H(2\mathbin|mk) $ .
如果您不喜歡隨機預言機模型,並且假設您的主密鑰大小合適,您可以使用分組密碼作為偽隨機函式 (PRF) 並生成兩個密鑰 $ k_1=\mathit{PRF}{mk}(1), k_2=\mathit{PRF}{mk}(2) $ .
正如您假設主密鑰是私有的,那麼這兩種方法都應該沒問題。兩者都會為您提供獨立的密鑰(至少獨立於所有計算受限的對手的眼睛)。