C#中CryptoStream.Close()向关联MemoryStream写入额外块的问题
为什么调用CryptoStream.Close()会让AES加密结果多16字节?
问题核心在于AES的填充机制和CryptoStream的生命周期行为:
- 默认填充模式的影响
AES默认使用PaddingMode.PKCS7填充。PKCS7的规则是:如果数据长度刚好是块大小(此处为16字节)的整数倍,会额外添加一个完整的填充块(每个字节的值等于填充的字节数,即0x10);如果数据长度不足块大小,则填充至块大小。
当你调用cryptoStream.Close()(或using语句自动释放CryptoStream时),加密器会自动触发最终块的填充与加密,原本16字节的明文会被加上16字节的填充,加密后得到32字节密文。
而仅调用Flush()时,只是将当前缓冲中的加密数据写入MemoryStream,不会触发填充逻辑——Flush仅处理已写入的数据,不负责结束加密流程,因此只输出原始16字节明文对应的16字节密文。
- 代码结果验证
从测试结果能看到:
- 调用Close的结果(A)前16字节和仅Flush的结果(B)完全一致,这部分是原始16字节明文的加密结果;
- 后面的16字节是PKCS7填充块(16个0x10)加密后的结果。
- 解决方案
根据需求选择对应处理方式:
- 不需要填充(数据长度固定为块大小):显式设置填充模式为
PaddingMode.None,无论是否调用Close,都不会添加填充,结果始终为16字节:var myAes = Aes.Create(); myAes.BlockSize = 128; myAes.IV = new byte[16]; myAes.Key = Encoding.ASCII.GetBytes(password); myAes.Padding = PaddingMode.None; // 禁用填充 - 正确处理填充(兼容任意长度数据):不要手动调用
Close,改用FlushFinalBlock()结束加密流程,它会自动处理填充并完成加密,同时using语句会自动清理资源:
注意:调用using var memoryStream = new MemoryStream(); using var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write); cryptoStream.Write(data, 0, data.Length); cryptoStream.FlushFinalBlock(); // 替代Flush+Close,正确处理填充 byte[] cipher = memoryStream.ToArray();FlushFinalBlock()后,不能再向CryptoStream写入数据。
内容的提问来源于stack exchange,提问作者Adam Streck
相关产品推荐
相关产品推荐

