大字符串对称加密解密后丢失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
相关产品推荐
相关产品推荐

