C#中使用AesCryptoServiceProvider加密后解密文件大小不一致问题
AES256-CBC加密解密后文件大小异常问题
我用AES256-CBC加密文件后,解密得到的文件大小和原文件不一致,比如原文件是64920KB,解密后变成65536KB。
加密代码
public static void Encrypt(FileStream fileWriteStream, FileStream fileReadStream, byte[] key, byte[] iv) { const int megabyte = 1024 * 1024; AesCryptoServiceProvider aes = new AesCryptoServiceProvider(); aes.Key = key; aes.IV = iv; aes.Mode = CipherMode.CBC; aes.Padding = PaddingMode.PKCS7; //试过所有填充模式都不行 using (ICryptoTransform encrypt = aes.CreateEncryptor()) { using (CryptoStream cs = new CryptoStream(fileWriteStream, encrypt, CryptoStreamMode.Write)) { using (fileReadStream) { var bytesToRead = megabyte < fileReadStream.Length ? (int)megabyte : (int)fileReadStream.Length; byte[] buffer = new byte[bytesToRead]; fileReadStream.Seek(0, SeekOrigin.Begin); int bytesRead = fileReadStream.Read(buffer, 0, bytesToRead); while (bytesRead > 0) { cs.Write(buffer, 0, bytesToRead); var bytesLeft = fileReadStream.Length - bytesRead; bytesToRead = bytesLeft > megabyte ? megabyte : (int)bytesLeft; bytesRead = fileReadStream.Read(buffer, 0, bytesToRead); } cs.FlushFinalBlock(); } } } }
解密代码
// 用密钥和IV将密文解密为字节数组 public static byte[] DecryptToBytes(byte[] cipherBytes, byte[] key, byte[] iv) { byte[] plainBytes; // 实例化Aes对象用于对称加密 Aes encryptor = Aes.Create(); encryptor.Mode = CipherMode.CBC; // 设置IV encryptor.IV = iv; byte[] aesKey = new byte[32]; Array.Copy(key, 0, aesKey, 0, 32); encryptor.Key = aesKey; // 实例化MemoryStream存储解密后的数据 MemoryStream memoryStream = new MemoryStream(); // 创建解密器 ICryptoTransform aesDecryptor = encryptor.CreateDecryptor(); // 实例化CryptoStream处理数据并写入内存流 CryptoStream cryptoStream = new CryptoStream(memoryStream, aesDecryptor, CryptoStreamMode.Write); try { // 写入密文字节进行解密 cryptoStream.Write(cipherBytes, 0, cipherBytes.Length); // 完成解密过程 cryptoStream.FlushFinalBlock(); // 将解密后的数据转为字节数组 plainBytes = memoryStream.ToArray(); } finally { // 关闭流 memoryStream.Close(); cryptoStream.Close(); } return plainBytes; }
测试代码
// 测试代码 var encryptedFile = @"C:\temp\encrypter\file.msi.encrypted"; var fileWrite = new FileStream(encryptedFile, FileMode.Create); var encryptionKey = new byte[32] { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; var iv = new byte[16] { 128, 0, 112, 0, 96, 0, 80, 0, 64, 0, 48, 0, 32, 0, 16, 0 }; EncryptorUtil.Encrypt(fileWrite, fileStream, encryptionKey, iv); var decryptBytes = EncryptorUtil.DecryptToBytes(System.IO.File.ReadAllBytes(encryptedFile), encryptionKey, iv); System.IO.File.WriteAllBytes(@"C:\temp\encrypter\file.msi", decryptBytes);
问题根源
加密方法的循环逻辑存在错误:每次调用cs.Write(buffer, 0, bytesToRead)时,使用的是预先设定的读取长度而非实际读取到的字节数。当最后一次读取文件内容不足1MB时,缓冲区中残留的旧数据会被一并写入加密流,导致加密文件包含无效数据,解密后文件自然比原文件大。
修正后的加密代码
public static void Encrypt(FileStream fileWriteStream, FileStream fileReadStream, byte[] key, byte[] iv) { const int megabyte = 1024 * 1024; using (Aes aes = Aes.Create()) { aes.Key = key; aes.IV = iv; aes.Mode = CipherMode.CBC; aes.Padding = PaddingMode.PKCS7; using (ICryptoTransform encryptor = aes.CreateEncryptor()) using (CryptoStream cs = new CryptoStream(fileWriteStream, encryptor, CryptoStreamMode.Write)) { byte[] buffer = new byte[megabyte]; int bytesRead; fileReadStream.Seek(0, SeekOrigin.Begin); // 循环读取并写入实际读取到的字节数 while ((bytesRead = fileReadStream.Read(buffer, 0, buffer.Length)) > 0) { cs.Write(buffer, 0, bytesRead); } cs.FlushFinalBlock(); } } }
额外优化建议
- 使用
Aes.Create()替代AesCryptoServiceProvider,前者是官方推荐的工厂方法,会根据系统环境选择最优实现。 - 若传入的密钥已经是32字节(AES256要求),解密方法中无需额外复制密钥,直接赋值即可。
- 处理大文件时,避免用
File.ReadAllBytes一次性加载整个文件到内存,改用流式处理降低内存占用。
流式解密方法示例
public static void Decrypt(FileStream inputStream, FileStream outputStream, byte[] key, byte[] iv) { using (Aes aes = Aes.Create()) { aes.Key = key; aes.IV = iv; aes.Mode = CipherMode.CBC; aes.Padding = PaddingMode.PKCS7; using (ICryptoTransform decryptor = aes.CreateDecryptor()) using (CryptoStream cs = new CryptoStream(outputStream, decryptor, CryptoStreamMode.Write)) { byte[] buffer = new byte[1024 * 1024]; int bytesRead; while ((bytesRead = inputStream.Read(buffer, 0, buffer.Length)) > 0) { cs.Write(buffer, 0, bytesRead); } cs.FlushFinalBlock(); } } }
优化后的测试代码
// 测试代码 var encryptedFile = @"C:\temp\encrypter\file.msi.encrypted"; var originalFile = @"C:\temp\encrypter\original.msi"; var decryptedFile = @"C:\temp\encrypter\file.msi"; var encryptionKey = new byte[32] { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; var iv = new byte[16] { 128, 0, 112, 0, 96, 0, 80, 0, 64, 0, 48, 0, 32, 0, 16, 0 }; // 流式加密 using (var readStream = new FileStream(originalFile, FileMode.Open)) using (var writeStream = new FileStream(encryptedFile, FileMode.Create)) { EncryptorUtil.Encrypt(writeStream, readStream, encryptionKey, iv); } // 流式解密 using (var readStream = new FileStream(encryptedFile, FileMode.Open)) using (var writeStream = new FileStream(decryptedFile, FileMode.Create)) { EncryptorUtil.Decrypt(readStream, writeStream, encryptionKey, iv); }
内容的提问来源于stack exchange,提问作者Michael
相关产品推荐
相关产品推荐

