使用單個長期密鑰進行文件加密的注意事項
我正在考慮設計自己的容器文件格式,允許我在其中儲存文件以及縮略圖或其他元數據。其中一些文件是機密文件,因此必須加密。基本上,我的目標是為我的文件容器實現機密性、真實性和完整性。但是,可能有數百萬個容器並且只有一個長期機密(即主密鑰文件),我該如何正確地做到這一點?
我想我正在尋找的是 AEAD(AD = 文件頭),例如,我可以使用 AES-256-CBC + HMAC-SHA256 或 AES-256-GCM。
我遇到的問題是 IV/nonce。由於我的設計中只有一個長期秘密,我明白我必須使用上述任何一種方法來確保每個容器的 IV/nonce 的唯一性。
- 為每個容器使用一個簡單的序列號並將其放在(經過身份驗證的)文件頭中是否足夠?
- 我應該將 IV/nonce 拆分為固定部分和順序部分(在 RFC5116 中提到)嗎?
- 不同的做法?
我還在考慮使用 HKDF 從主密鑰和與每個文件容器關聯的 GUID 中為每個容器派生密鑰材料。然後我會將 GUID 儲存在純文件頭中。但話又說回來,我可以簡單地將 GUID 用作 IV/nonce。為每個容器創建單獨的密鑰材料是否有好處?
更新
每個容器的單獨鍵似乎是要走的路。但是,簡單地使用主密鑰來加密容器密鑰並不能解決 IV 問題。請看以下提案:
文件頭
$ H: Plaintext\ file\ header $
$ G: GUID\ associated\ with\ the\ payload\ (included\ in\ H) $
有效載荷
$ P: Plaintext $
$ C: Ciphertext $
$ IV_p: Payload\ IV $
$ K_p: Payload\ key $
$ C = AES(IV_p, K_p, P) $
使用者密鑰和 MAC
$ S_i: A\ secret\ stored\ in\ a\ file $
$ IV_i: IV\ for\ slot\ i $
$ K_i: Key\ for\ slot\ i $
$ K_{M_i}: HMAC\ secret\ for\ slot\ i $
$ M_i: HMAC\ for\ slot\ i $
$ K_{P_i}: Payload\ key\ material\ encrypted\ with\ K_i $
$ (IV_i, K_i, K_{M_i}) = HKDF(G, S_i) $
$ K_{P_i} = AES(IV_i, K_i, IV_p\ ||\ K_p) $
$ M_i = HMAC(K_{M_i}, H\ ||\ C\ ||\ K_{P_i}) $
容器文件格式
$ H\ ||\ C\ ||\ (K_{P_i}, M_i) $
有了這個設計,我
- 使用 HKDF 從密鑰文件中獲取我需要的盡可能多的密鑰材料(解決 IV 問題)
- 以後可以根據需要添加或刪除任意數量的使用者密鑰
- 可以通過與每個使用者密鑰關聯的 HMAC 檢測篡改
- 不需要儲存容器密鑰的雜湊值(就像 LUKS 那樣),因為 HMAC 保證了解密密鑰的完整性
你會認為這是一個聲音設計嗎?
為每個容器使用一個簡單的序列號並將其放在(經過身份驗證的)文件頭中是否足夠?
是的,但確保它是獨一無二的可能比你想像的要棘手。儲存計數器既容易出錯,也可能會影響性能。如果您失去了包含該數字的 .lock 文件(或類似文件)怎麼辦?
我應該將 IV/nonce 拆分為固定部分和順序部分(在 RFC5116 中提到)嗎?
如果你願意,只要它保持獨特。如果您有多個設備,每個設備都有其唯一的固定 ID,則標準的這一部分似乎特別重要。在這種情況下,固定 ID 可以防止設備出現相同的隨機數。
我個人認為你不應該首先使用相同的密鑰。我不認為 RFC 5116 是一個強大的標準,我當然不會使用它來從中汲取密碼學思想。尤其是身份驗證標籤是密文一部分的部分對我來說完全是倒退(因為它刪除了用於大多數身份驗證加密模式的 AES-CTR 的線上屬性)。
不同的做法?
通常為每個文件生成一個對稱密鑰,然後可以由主密鑰包裝。優點是您可以解密數據密鑰並添加其他可能檢索數據密鑰的密鑰。您也可以通過這種方式滾動到新密鑰。換句話說,它簡化了密鑰管理。使用 KDF 時,這種密鑰管理更難完成。
但話又說回來,我可以簡單地將 GUID 用作 IV/nonce。為每個容器創建單獨的密鑰材料是否有好處?
是的,如果隨機數重複出現,您將不太容易受到災難性故障的影響。
請注意,您可能還希望防止文件被交換。