You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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();
        }
    }
}

额外优化建议

  1. 使用Aes.Create()替代AesCryptoServiceProvider,前者是官方推荐的工厂方法,会根据系统环境选择最优实现。
  2. 若传入的密钥已经是32字节(AES256要求),解密方法中无需额外复制密钥,直接赋值即可。
  3. 处理大文件时,避免用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 21:45:09