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

.NET使用AES解密时丢失后半部分字节问题排查

问题原因

代码存在两个核心错误,共同导致解密仅返回前16字节结果:

  • 加密阶段输出的密文本身不完整
    AES固定块大小为16字节,你使用的是默认PKCS7填充规则:当明文长度恰好是块大小的整数倍时,会额外追加1个全为0x10的16字节填充块。因此32字节的原始数据密钥加密后,完整密文长度应为48字节。
    你加密时仅为密文分配了32字节缓冲区,单次Read调用只拿到了前32字节密文,最后16字节的填充块密文未被读取就随流释放,存储下来的aKey1从一开始就是残缺数据。
  • 错误假设Stream.Read会一次性填满请求的缓冲区
    .NET中所有继承自Stream的类(包括CryptoStream),Read方法都不保证一次性返回你请求的全部字节数,方法返回值才是本次调用实际读取到的字节长度,必须循环读取直到Read返回0,才能确认拿到了全部数据。
    针对你当前的残缺密文场景:解密时CryptoStream读取第一个16字节密文块解密后返回,第二个16字节块因缺少后续填充块无法完成填充校验,不会被输出,因此最终仅拿到16字节明文,缓冲区剩余部分保留初始化的0值。
修复方法

不要手动用固定长度缓冲区单次调用Read接收加解密结果,直接用流的CopyTo方法自动完成全量数据读取,避免遗漏字节:

修正后的加密逻辑

byte[] aKey1;
using (Aes aes = Aes.Create())
{
    aes.Mode = CipherMode.CBC;
    aes.Key = pwdK1;
    aes.IV = IV;
    using (var plainStream = new MemoryStream(Key))
    using (var cryptoStream = new CryptoStream(plainStream, aes.CreateEncryptor(), CryptoStreamMode.Read))
    using (var cipherStream = new MemoryStream())
    {
        cryptoStream.CopyTo(cipherStream);
        aKey1 = cipherStream.ToArray(); // 此处得到的密文长度为48字节,是完整数据
    }
}

修正后的解密逻辑

byte[] bKey1;
using (Aes aes = Aes.Create())
{
    aes.Mode = CipherMode.CBC;
    aes.Key = pwdK1;
    aes.IV = IV;
    using (var cipherStream = new MemoryStream(aKey1))
    using (var cryptoStream = new CryptoStream(cipherStream, aes.CreateDecryptor(), CryptoStreamMode.Read))
    using (var plainStream = new MemoryStream())
    {
        cryptoStream.CopyTo(plainStream);
        bKey1 = plainStream.ToArray(); // 此处得到的明文长度为32字节,和原始Key完全一致
    }
}
额外注意事项

你设计的「随机生成数据密钥加密文件,再用密码派生密钥加密数据密钥,改密时仅重加密数据密钥」的方案符合加密最佳实践,实际落地时注意不要全局复用固定IV:每次加密数据密钥时都要新生成随机IV,将IV、盐值、加密后的数据密钥和密文文件存在一起即可,IV不需要保密。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 06:51:21