當密鑰已知時,在 AES CBC 中區分正確的 IV 和不正確的 IV
目前,我對所有加密和解密都使用靜態 IV 值,但我希望它對於每個加密/解密請求都是動態的,所以我開始使用新字節
$$ 16 $$它有效。問題是如何檢測和解密舊數據。下面是我要解密的程式碼,我正在傳遞儲存在 keyvault 中的秘密中的靜態 IV。
private static byte[] DecryptFromBytes_Aes(byte[] dataBytes, byte[] key, byte[] iV) { if (dataBytes == null || dataBytes.Length <= 0) throw new ArgumentNullException("DataBytes"); if (key == null || key.Length <= 0) throw new ArgumentNullException("key"); if (iV == null || iV.Length <= 0) throw new ArgumentNullException("iV"); byte[] result = null; using (AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider()) { aesAlg.Key = key; aesAlg.IV = iV; aesAlg.Padding = PaddingMode.PKCS7; ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV); using (MemoryStream memoryStream = new MemoryStream(dataBytes)) { using (CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read)) { byte[] decryptedBytes = new byte[dataBytes.Length]; int read = cryptoStream.Read(decryptedBytes, 0, dataBytes.Length); Array.Resize(ref decryptedBytes, read); result = decryptedBytes; } } } return result; }
您無法可靠地檢查數據是否具有隨機前綴。對於同一個key,數據甚至一般不會unpadding失敗。所以你需要做的是使用不同的協議。
例如,您可以在新加密的文件(當然生成一次)前面有一個 16 字節的完全隨機魔法,然後是版本號和其他數據,包括隨機 IV、密文和 HMAC 以及數據包括四。這樣您就可以檢測到使用了正確的加密(因為意外生成該魔法的機率為 1 in $ 2^{128} $ ) 通過簡單地進行比較。您還使用 HMAC 保護了您的文件的完整性和真實性(這是可選的,並非嚴格要求保密 - 但強烈推薦使用)。
所以那將是:
MAGIC (16 bytes) | VERSION | IV (16 bytes) | CIPHERTEXT | TAG
其中 TAG 是使用 HMAC 在之前的所有內容上生成的身份驗證標籤。
當然,也有很多人已經編寫了這樣的協議,因此您可能需要研究容器格式,例如 CMS(通常取決於公鑰加密/證書)甚至 NaCL。
問題是如何檢測和解密舊數據。下面是我要解密的程式碼,我正在傳遞儲存在 keyvault 中的秘密中的靜態 IV。
答案取決於填充和密鑰的正確性。
- 案例:如果密鑰正確而IV不正確;
請記住,CBC 解密執行為 $$ \begin{align} P_1 =& Dec_k(C_1) \oplus IV\ P_i =& Dec_k(C_i) \oplus C_{i-1},;; 1 < i \leq nb, \end{align} $$
因此,如果 IV 不正確,則第一個塊 $ P_1 $ 是不正確的。我們可以認為這類似於第一個塊中的位翻轉攻擊。下一個區塊 $ P_i $ 將正確解密,因為它們依賴於 $ C_i $ 和 $ C_{i-1} $ 在這種情況下,它們是正確的。只有你的第一個塊是不正確的。**區分這可能很困難,您需要準備一些過濾器以將其與純文字的屬性(**語言或格式)區分開來。需要比較這兩種情況;是靜態IV還是隨機IV。無論哪個通過您的過濾器都可能是正確的情況,這實際上取決於您的數據。
如果明文的第一個塊是純文字並且只包含來自 ASCII 第一部分的字元(即 char < 128 的 int 值),那麼這是一個很好的區分。只需檢查每個 16 字節 < 128。
盡快將所有文件遷移到獨特的格式。
- 案例:如果密鑰不正確,那麼您很可能會收到 PKCS#7 填充錯誤。
填充字節將是明文末尾的以下之一,具體取決於明文的大小。使用填充,大小需要是 AES 塊大小的最小倍數,AES 塊大小為 16 字節。
missing 1 byte - padding bytes : 01 missing 2 byte - padding bytes : 02 02 missing 3 byte - padding bytes : 03 03 03 missing 4 byte - padding bytes : 04 04 04 04 missing 5 byte - padding bytes : 05 05 05 05 05 missing 6 byte - padding bytes : 06 06 06 06 06 06 ... full block - padding bytes : 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 Even if the plaintext is a multiple of 128, a full block is needed so that padding is not ambigious.
檢查填充是否正確。
如果不正確,您可以確定 IV 不正確。如果正確,有一個 $ 1/256 $ IV 生成隨機有效
01
填充的機率,其中 $ 1/(256)^2 $ 機率0202
有效填充,等等。要消除這種可能性,您需要檢查數據。明文的語言或任何其他格式可以幫助您消除誤報。