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

大字符串对称加密解密后丢失1-5字节问题求助

问题:大字符串AES加密解密后丢失字节

我正在修改一段旧代码,将原基于SHA1的逻辑适配为SHA256或SHA512。作为密码学领域的新手,我发现一个问题:当加密大字符串(如16字节及以上)时,经Encrypt方法加密后再通过Decrypt方法解密,结果会丢失1-5字节,但短字符串加密解密无异常。

相关代码

加密解密方法

public string Decrypt(string data, EncryptionValue eV, string passPhrase)
{
    byte[] bytes = Encoding.ASCII.GetBytes(eV.InitVector);
    byte[] rgbSalt = Encoding.ASCII.GetBytes(eV.SaltValue);
    byte[] buffer = Convert.FromBase64String(data);
    byte[] rgbKey = new Rfc2898DeriveBytes(passPhrase, rgbSalt, eV.PassIterations, hash).GetBytes(eV.KeySize / 8);

    var managed = Aes.Create("AesManaged");
    managed.Padding = PaddingMode.PKCS7;
    managed.Mode = CipherMode.CBC;
    ICryptoTransform transform = managed.CreateDecryptor(rgbKey, bytes);
    MemoryStream stream = new(buffer);
    CryptoStream stream2 = new(stream, transform, CryptoStreamMode.Read);
    byte[] buffer5 = new byte[buffer.Length];
    int count = stream2.Read(buffer5, 0, buffer5.Length);
    stream.Close();
    stream2.Close();
    return Encoding.UTF8.GetString(buffer5, 0, count);
}
public string Encrypt(string data, EncryptionValue eV, string passPhrase)
{
    byte[] bytes = Encoding.ASCII.GetBytes(eV.InitVector);
    byte[] rgbSalt = Encoding.ASCII.GetBytes(eV.SaltValue);
    byte[] buffer = Encoding.UTF8.GetBytes(data);
    byte[] rgbKey = new Rfc2898DeriveBytes(passPhrase, rgbSalt, eV.PassIterations, hash).GetBytes(eV.KeySize / 8);

    var managed = Aes.Create("AesManaged");
    managed.Padding = PaddingMode.PKCS7;
    
    managed.Mode = CipherMode.CBC;
    ICryptoTransform transform = managed.CreateEncryptor(rgbKey, bytes);
    MemoryStream stream = new();
    CryptoStream stream2 = new(stream, transform, CryptoStreamMode.Write);
    stream2.Write(buffer, 0, buffer.Length);
    stream2.FlushFinalBlock();
    byte[] inArray = stream.ToArray();
    stream.Close();
    stream2.Close();
    return Convert.ToBase64String(inArray);
}

EncryptionValue类定义

public int PassIterations { get; set; }
public int KeySize { get; set; }
public string InitVector { get; set; }
public string SaltValue { get; set; }

测试参数:迭代次数约为1000,密钥大小为256或128,初始向量为"~1B2c3D4e5F6g7H8"。我希望实现至少120字节字符串的加密存储。


问题原因及修复方案

原因

问题出在Decrypt方法的stream2.Read(buffer5, 0, buffer5.Length)调用上。CryptoStream.Read()方法无法保证一次性读取所有数据,处理大字节流时,它只会返回当前能读取的字节数,剩余数据需要多次读取才能获取完整。你直接用单次Read的结果作为总长度,就会丢弃后续未读取的字节,导致解密结果不完整。

修复后的Decrypt方法

public string Decrypt(string data, EncryptionValue eV, string passPhrase)
{
    byte[] ivBytes = Encoding.ASCII.GetBytes(eV.InitVector);
    byte[] saltBytes = Encoding.ASCII.GetBytes(eV.SaltValue);
    byte[] cipherBytes = Convert.FromBase64String(data);
    byte[] keyBytes = new Rfc2898DeriveBytes(passPhrase, saltBytes, eV.PassIterations, hash)
        .GetBytes(eV.KeySize / 8);

    // 使用using自动释放资源,替代手动Close
    using var aes = Aes.Create("AesManaged");
    aes.Padding = PaddingMode.PKCS7;
    aes.Mode = CipherMode.CBC;
    
    ICryptoTransform decryptor = aes.CreateDecryptor(keyBytes, ivBytes);
    using var ms = new MemoryStream(cipherBytes);
    using var cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read);
    using var outputMs = new MemoryStream();
    
    byte[] buffer = new byte[4096]; // 用4KB大小的缓冲区,平衡性能与内存占用
    int readBytesCount;
    // 循环读取直到Read返回0,确保获取所有解密后的数据
    while ((readBytesCount = cs.Read(buffer, 0, buffer.Length)) > 0)
    {
        outputMs.Write(buffer, 0, readBytesCount);
    }
    
    return Encoding.UTF8.GetString(outputMs.ToArray());
}

额外优化点

  • 用using语句管理流和加密对象,自动释放资源,避免内存泄漏
  • 缓冲区设为4096字节(或更大的合理值),减少IO操作次数,提升性能
  • 变量名更具语义,提升代码可读性

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 13:21:16