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

.NET 7文件加密正确实现方案?RijndaelManaged已过时

.NET 7 AES文件加解密问题修复

问题背景

在.NET 7解决方案中实现自定义文件加解密时,采用Aes.Create()替代已过时的RijndaelManaged,但出现以下问题:

  • 加解密过程偶尔抛出异常
  • 所有类型文件(文本、图片、二进制文件)解密后均损坏,无法恢复原始数据

代码错误分析

你的代码存在以下关键问题:

  • Aes实例被提前释放:GetAES方法中用using包裹Aes.Create(),导致返回的Aes对象已被Dispose,后续调用加密/解密方法时会出现异常或行为异常。
  • Salt读取不完整:解密时仅调用一次Read读取salt,无法保证一次性读取全部32字节,会导致密钥/IV推导错误。
  • 未处理加密最终块:加密时未调用CryptoStream.FlushFinalBlock(),最后一块带填充的加密数据未写入输出流,造成文件截断损坏。
  • 冗余的手动Close调用:所有Stream已通过using自动管理生命周期,手动调用Close()属于多余操作,可能引发资源冲突。
  • 空catch吞掉异常:异常被无处理捕获,无法定位问题根源,阻碍调试。
  • 填充模式选择不当:PaddingMode.Zeros会破坏末尾含0的二进制文件,标准PaddingMode.PKCS7更安全可靠。

修正后的完整代码

共用Aes初始化方法

private static Aes GetAES(string password, byte[] salt)
{
    byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
    Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(passwordBytes, salt, 50000, HashAlgorithmName.SHA256);

    Aes aes = Aes.Create();
    aes.KeySize = 256;
    aes.BlockSize = 128;
    aes.Padding = PaddingMode.PKCS7; // 使用标准PKCS7填充
    aes.Mode = CipherMode.CBC;
    aes.Key = key.GetBytes(aes.KeySize / 8);
    aes.IV = key.GetBytes(aes.BlockSize / 8);

    return aes;
}

加密方法

public static void EncryptFile(string sourcePath, string destinationPath, string password)
{
    if (string.IsNullOrWhiteSpace(password)) return;

    using FileStream outputStream = File.OpenWrite(destinationPath);
    byte[] salt = RandomNumberGenerator.GetBytes(32);
    outputStream.Write(salt, 0, salt.Length);

    using Aes aes = GetAES(password, salt); // 用using管理Aes生命周期
    using CryptoStream cryptoStream = new CryptoStream(outputStream, aes.CreateEncryptor(), CryptoStreamMode.Write);
    using FileStream inputStream = File.OpenRead(sourcePath);

    byte[] buffer = new byte[1024 * 1024];
    int readPosition;
    while ((readPosition = inputStream.Read(buffer, 0, buffer.Length)) > 0)
    {
        cryptoStream.Write(buffer, 0, readPosition);
    }

    cryptoStream.FlushFinalBlock(); // 必须调用,确保最后一块加密数据写入
}

解密方法

public static void DecryptFile(string sourcePath, string destinationPath, string password)
{
    if (string.IsNullOrWhiteSpace(password)) return;

    using FileStream inputStream = File.OpenRead(sourcePath);
    byte[] salt = new byte[32];
    int totalRead = 0;
    // 循环读取确保salt完全读取
    while (totalRead < salt.Length)
    {
        int read = inputStream.Read(salt, totalRead, salt.Length - totalRead);
        if (read == 0)
        {
            throw new InvalidDataException("加密文件损坏,无法读取完整的salt");
        }
        totalRead += read;
    }

    using Aes aes = GetAES(password, salt);
    using CryptoStream cryptoStream = new CryptoStream(inputStream, aes.CreateDecryptor(), CryptoStreamMode.Read);
    using FileStream outputStream = File.Create(destinationPath);

    byte[] buffer = new byte[1024 * 1024];
    int readPosition;
    while ((readPosition = cryptoStream.Read(buffer, 0, buffer.Length)) > 0)
    {
        outputStream.Write(buffer, 0, readPosition);
    }
}

关键修改说明

  1. 移除GetAES中的using声明,改为由调用方用using管理Aes实例生命周期
  2. 解密时循环读取salt,确保获取完整的32字节数据
  3. 加密时添加FlushFinalBlock()调用,保证最后一块加密数据(含填充)写入输出流
  4. 替换填充模式为PaddingMode.PKCS7,适配所有类型文件
  5. 移除所有手动Close()调用,依赖using自动释放资源
  6. 移除空catch块,让异常正常抛出以便调试

内容的提问来源于stack exchange,提问作者blcamp

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 03:10:38