Encryption

從主密鑰派生多個 AES 密鑰

  • February 24, 2021

我需要有關此問題的密碼學建議。

Kamus 是一項為在 Kubernetes 上執行的應用程序加密機密的服務。當使用 AES(實際上是 Rijndael)對稱加密時,Kamus 使用單個密鑰來加密所有應用程序的秘密。

假設我想從通用密鑰創建一個每個應用程序唯一的密鑰 - 這樣為特定應用程序加密的秘密將無法使用另一個應用程序的密鑰解密(使用 KMS 時就是這種情況)。我正在尋找一種算法來從應用程序名稱(準確地說是服務帳戶名稱)“派生”一個密鑰,例如:

f(key, name) = key

有我可以使用的算法嗎?這裡最好的方法是什麼?

從主密鑰生成多個密鑰

您正在尋找基於 HMAC 的密鑰派生函式 (HKDF) rfc5869 。HMAC 安全證明使用了底層雜湊的壓縮函式本身就是一個 PRF 的事實。

HKDF 遵循“extract-then-expand”範式,其中 KDF 在邏輯上由兩個模組組成。第一階段獲取輸入密鑰材料並從中“提取”一個固定長度的偽隨機密鑰 K。第二階段將密鑰 K“擴展”為幾個額外的偽隨機密鑰(KDF 的輸出)。

提取物

$$ \text{HKDF-Extract}(salt, IKM) \to PRK, $$在哪裡 $ PRK $ 是一個偽隨機密鑰。

如果輸入密鑰材料(IKM)已經是隨機密鑰,如您的情況,則不需要提取,擴展就足夠了。HKDF 可以在沒有鹽的情況下使用,但是,使用鹽可以增強 HKDF 並支持與源無關的提取。兩種不同的鹽 $ IKM $ 導致根本上兩種不同的 $ PRK $ s。而且,一般來說, $ x $ 不同的鹽有相同的 $ IKM $ 結果從根本上 $ x $ 不同的 $ PRK $ s。

展開

$$ \text{KDF-Expand}(PRK, info, L) \to OKM, $$其中 OKM 是輸出鍵控材料。L 是所需的密鑰長度。

該資訊可用於特定於應用程序的標籤以派生不同的密鑰。

$$ \text{KDF-Expand}(\text{Inittal Key}, \text{“application 1”}, 128) \to OKM_1 $$ $$ \text{KDF-Expand}(\text{Inittal Key}, \text{“application 2”}, 256) \to OKM_2 $$


生成相同密鑰的機率是多少,即碰撞

但是,如果我們將其建模為統一隨機函式,則很難直接在 HKDF 上討論 $ f $ , 在哪裡 $ f(x) $ 是每個組合輸入的統一隨機 HKDF 值 ( $ x = salt || IKM $ ) 然後我們可以回到生日碰撞。

讓 $ P(C; n, k) $ 表示通常的碰撞機率 $ n $ 有的人 $ k $ 可能的生日。而且,通常的方法是從補碼計算 $ P(D; n, k) = 1 - P(C; n, k) $ ,也就是說所有的生日都是不同的。然後我們可以近似為

$$ \begin{equation} P(C; n, k) = 1 - P(D; n, k) \leq \frac{n^2}{k}. \end{equation} $$在哪裡 $ n \leq k/2 $ . 細節無處不在,因此被跳過。

我們有兩個案例;

  1. 在生成碰撞 $ x $ s。如果 IKM 設置為固定,您也可以將其視為鹽碰撞。為了 $ n $ 輸入 $ x_1,x_2,\ldots,x_n $ 碰撞機率為 $ P(C; n, k) $ . 當這種情況發生時,這是條件機率而不是輸出 $ f(x_1),f(x_2), \ldots, f(x_n) $ 將與機率 1 發生碰撞。
  2. 如果輸入 $ x_i $ s 是不同的,那麼這有 $ P(D; n, k) = 1 - P(C; n, k) $ 可能性。現在,有條件地,我們可以在輸出上發生碰撞 $ f(x_1),f(x_2), \ldots, f(x_n) $ 和 $ P(C; n, k) $ 可能性。

現在總結以上,那麼我們有;

$$ P(C; n, k) + (1 - P(C; n, k)) \cdot P(C; n, k) \ = 2 P(C; n, k) - P(C; n, k)^2 \leq 2 \frac{n^2}{k} $$

所以,這只是通常碰撞攻擊的兩倍。如果你不打算生成 $ 2^{64} $ 128 位密鑰的密鑰對您來說不是問題。這種情況可能是多目標攻擊的問題。這就是您需要使用 AES-256 的原因。

你可能會注意到 $ 2^{64} $ 128 等於 2,這是因為機率界不適合 $ n \approx \sqrt{k} $ ,但是當輸入通過時有更嚴格的界限 $ \sqrt{k} $ 它迅速接近 1。

需要注意的是,50% 的機率在對手的意義上太高了。應該比這更早停止。如果您使用 AES-256,則應該使用它(或具有 256 位密鑰的 ChaCha20),那麼產生衝突的數量超出了我們的範圍。


**注意:**還有舊的KDF1 和 KDF2

$$ K_i = \operatorname{KDF}(K_{master}, i) = \operatorname{H}(K_{master} \mathbin| c) $$在哪裡 $ c $ 是 4 字節編​​碼的 $ i $ , 它通常與 MD5、SHA-1 和 SHA-256 一起使用。


帶有 python hkdf範例程式碼,其中包含輸出 x-or 上的彈出計數;

from hkdf import hkdf_extract,hkdf_expand
from binascii import unhexlify,b2a_hex
import sys

def bxor(b1, b2): # use xor for bytes
   parts = []
   for b1, b2 in zip(b1, b2):
       parts.append(bytes([b1 ^ b2]))
   return b''.join(parts)

prk = hkdf_extract(unhexlify(b"8e94ef805b93e683ff18"), b"asecretpassword")
key1 = hkdf_expand(prk, b"application 1", 16)
key2 = hkdf_expand(prk, b"application 2", 16)

print (b2a_hex(key1))
print (b2a_hex(key2))

#count the number of differnt bits by x-or and popup count.
print (bin(int.from_bytes(bxor(key1,key2), byteorder=sys.byteorder))[2:].count('1'))

輸出

b'd6208cd3e14955c6ae0dc7f5ecd38a68'
b'3b310a2e8cc9f4854237e966d289d9ba'
64

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