簡體   English   中英

如何在不寫入文件的情況下使用 AES CBC 模式進行鏈式加密

[英]How to chain-encrypt using AES CBC mode without writing to file

我需要加密大量連續的字節,不適合單字節數組。

已經有一些類似的問題,但沒有一個答案對我有用:

stackoverflow.com/questions/5090233/how-to-encrpyt-decrypt-data-in-chunks stackoverflow.com/questions/45735983/encrypting-files-with-aes-c-sharp-in-chunks stackoverflow.com/questions/ 27645527/aes-encryption-on-large-files

如果 output 長度低於限制,則以下代碼有效(Key 和 IV 被硬編碼用於測試):

byte[] encrypt(byte[] input, byte[] iv = null)
{
    var aes = new AesManaged();
    aes.KeySize = 128;
    aes.Key = new byte[16] { 0x0F, 0xD4, 0x33, 0x82, 0xF4, 0xDF,
        0x62, 0xA5, 0x55, 0x7C, 0x6E, 0x92, 0xC5, 0x64, 0x67, 0xA9 };
    aes.IV = (iv != null) ? iv :
        new byte[16] { 0xB3, 0x87, 0xDA, 0xA0, 0x47, 0x7C,
        0x52, 0x76, 0xCB, 0x3A, 0x69, 0x9B, 0x0F, 0x82, 0xAF, 0xA7 };

    using (var stream = new MemoryStream())   // size limit is 2 GB
    using (var cryptoStream = new CryptoStream(stream,
            aes.CreateEncryptor(), CryptoStreamMode.Write))
    {
        cryptoStream.Write(input, 0, input.Length);
        cryptoStream.FlushFinalBlock();
        return stream.ToArray();    // max number of bytes = int.MaxValue
    }
}

一種替代方法是使用 FileStream 而不是 MemoryStream,但我更喜歡在 memory 中獲取結果。

我正在嘗試實現鏈式操作,將輸入划分為 [AES BlockSize 的倍數] 的塊,並在輸入每個塊后捕獲加密的 output。

根據我的閱讀,每個結果的最后一個字節應該用作下一次加密的 IV,但這不起作用。 為簡單起見,塊大小等於 BlockSize:

byte[] subArray(byte[] source, int start, int length = -1)
{
    if (length == -1) length = source.Length - start;
    var target = new byte[length];
    Buffer.BlockCopy(source, start, target, 0, length);
    return target;
}
var encr0 = encrypt(subArray(input, 0,         blockSize * 2));
var encr1 = encrypt(subArray(input, 0,         blockSize));
var encr2 = encrypt(subArray(input, blockSize, blockSize),
                    subArray(encr1, blockSize, 16));
Assert.IsTrue(encr2.SequenceEqual(subArray(encr0, blockSize)));  // FAILS

我做錯了什么?

encrypt()方法默認使用CBC模式。 在這種模式下,一個塊的密文用作下一個塊的 IV(隨機 IV 應用於第一個塊)。
在發布的代碼中,解密失敗,因為encr2使用了不正確的 IV。 正確的 IV 是subArray(encr1, 0, blockSize) (即第一個塊的密文)而不是subArray(encr1, blockSize, 16)
解決此問題后,將不再發生異常。

另一個問題是encrypt()隱式執行PKCS#7 填充(默認)。 PKCS#7 填充,即使最后一個明文塊已完全填充。 在這種情況下,將附加一個完整的填充塊(由 16 個 AES 的 0x10 值組成)。
encrypt()中的填充導致不在末尾的明文塊也被錯誤地填充為完整的填充塊。 這會導致錯誤的密文塊,當encr0encr1encr2 (例如十六進制編碼)為 output 時可以輕松檢查。

為了避免這些錯誤的填充塊,必須為所有明文塊禁用encrypt()中的填充,除了最后一個定期填充的塊(如果不完整,則填充,如果完整,則附加完整的填充塊)。


編輯:對於任意塊大小(塊大小的倍數),必須將subArray(encr1, chunkSize - blockSize, blockSize)用作encr1的 IV。 如果 chunksize 等於 blocksize(如此處假設的那樣),這將簡化為subArray(encr1, 0, blockSize)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM