Aes

當密鑰已知時,在 AES CBC 中區分正確的 IV 和不正確的 IV

  • December 9, 2021

目前,我對所有加密和解密都使用靜態 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有效填充,等等。要消除這種可能性,您需要檢查數據。明文的語言或任何其他格式可以幫助您消除誤報。

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