[英]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()
中的填充導致不在末尾的明文塊也被錯誤地填充為完整的填充塊。 這會導致錯誤的密文塊,當encr0
、 encr1
和encr2
(例如十六進制編碼)為 output 時可以輕松檢查。
為了避免這些錯誤的填充塊,必須為所有明文塊禁用encrypt()
中的填充,除了最后一個定期填充的塊(如果不完整,則填充,如果完整,則附加完整的填充塊)。
編輯:對於任意塊大小(塊大小的倍數),必須將subArray(encr1, chunkSize - blockSize, blockSize)
用作encr1
的 IV。 如果 chunksize 等於 blocksize(如此處假設的那樣),這將簡化為subArray(encr1, 0, blockSize)
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.