C#实现AES+RSA加密通信时AES解密开头出现乱码如何解决
问题根因
最直接导致解密开头乱码的原因是服务端创建解密器的顺序错误:
你服务端代码先调用 aes.CreateDecryptor() 生成解密器,之后才给 aes.IV 赋值硬编码的固定值。CreateDecryptor() 方法会在调用时立即读取当前AES实例的Key和IV生成转换器,后续修改AES实例的IV不会对已经生成的解密器生效,导致解密器实际使用的是AES实例初始化时自动生成的随机IV,和加密时的IV不匹配,第一个加密块(通常16字节)解密错误,表现为开头乱码。
其他需要修复的错误
- 所有
NetworkStream.Read调用未处理返回值:TCP是流式协议,Read方法不保证一次性读取到你期望长度的所有数据,返回值代表本次实际读取到的字节数,你需要根据返回值截取有效字节,否则buffer中未填充的部分会被转为无效的\0字符,导致字符串分割、Base64解析出错。 - 复用ICryptoTransform加密多段独立数据:AES默认CBC模式是链式加密,加密完一段数据调用
TransformFinalBlock后,转换器状态可能不符合下一段独立数据的加密要求,每段独立数据加密/解密都应该重新创建对应转换器。 - 密钥交换逻辑冗余混乱:你客户端生成RSA密钥对、发送公钥到服务端的逻辑完全无用,你需要的是客户端用服务端公钥加密AES密钥,服务端用自身私钥解密即可,当前服务端代码导入客户端公钥后又导入自身私钥,直接覆盖了之前的密钥配置,属于无效逻辑。
- 硬编码IV存在安全风险:IV应该每次加密随机生成,随密文一起传输,硬编码IV会降低加密安全性。
修复示例
服务端核心逻辑调整(解决开头乱码的核心修改)
// 先赋值Key和IV,再创建解密器 aes.Key = rsa.Decrypt(Convert.FromBase64String(Encoding.UTF8.GetString(bytesFrom).Split("$")[0]), RSAEncryptionPadding.Pkcs1); // 先设置IV aes.IV = Encoding.UTF8.GetBytes("1234567890123456"); // 再创建解密器 ICryptoTransform decrypt = aes.CreateDecryptor();
通用Read方法封装(解决TCP流读取不完整问题)
private string ReadUntilDelimiter(NetworkStream stream, char delimiter = '$') { var buffer = new List<byte>(); int readByte; while ((readByte = stream.ReadByte()) != -1) { if ((char)readByte == delimiter) break; buffer.Add((byte)readByte); } return Encoding.UTF8.GetString(buffer.ToArray()); }
后续读取数据直接调用该方法即可拿到完整的、不包含分隔符的有效字符串,不需要手动处理分割和读取长度。
内容的提问来源于stack exchange,提问作者BurntRanch
相关产品推荐
相关产品推荐

