C#游戏数据加解密抛出Bad PKCS7 padding错误求助
我在实现游戏数据加解密功能时,解密阶段抛出了PKCS7填充错误,相关代码和错误信息如下:
加密函数
private void WriteEncryptedData<T>(T Data, string path) { byte[] array; using (Aes aes = Aes.Create()) { aes.Key = Convert.FromBase64String(KEY); aes.IV = Convert.FromBase64String(IV); aes.Padding = PaddingMode.PKCS7; ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV); using MemoryStream memoryStream = new(); using CryptoStream cryptoStream = new(memoryStream, encryptor, CryptoStreamMode.Write); cryptoStream.Write(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(Data))); cryptoStream.FlushFinalBlock(); array = memoryStream.ToArray(); } File.WriteAllText(path, Convert.ToBase64String(array)); }
解密函数
private T ReadEncryptedData<T>(string path) { var data = File.ReadAllText(path); byte[] array = Convert.FromBase64String(data); string result; using (Aes aes = Aes.Create()) { aes.Key = Convert.FromBase64String(KEY); aes.IV = Convert.FromBase64String(IV); aes.Padding = PaddingMode.PKCS7; using ICryptoTransform cryptoTransform = aes.CreateDecryptor(aes.Key, aes.IV); using MemoryStream decryptionStream = new(array); using CryptoStream cryptoStream = new( decryptionStream, cryptoTransform, CryptoStreamMode.Read ); cryptoStream.Flush(); result = Encoding.UTF8.GetString(decryptionStream.ToArray()); } Debug.Log($"Decrypted result (if the following is not legible, probably wrong key or iv): {result}"); return JsonConvert.DeserializeObject<T>(result); }
错误信息
加载数据失败,原因:Bad PKCS7 padding. Invalid length 0. at
Mono.Security.Cryptography.SymmetricTransform.ThrowBadPaddingException
(System.Security.Cryptography.PaddingMode padding, System.Int32
length, System.Int32 position) [0x00056] in
<381999f96ea944d79e461a81dcbea654>:0 at
Mono.Security.Cryptography.SymmetricTransform.FinalDecrypt
(System.Byte[] inputBuffer, System.Int32 inputOffset, System.Int32
inputCount) [0x00146] in <381999f96ea944d79e461a81dcbea654>:0 at
Mono.Security.Cryptography.SymmetricTransform.TransformFinalBlock
(System.Byte[] inputBuffer, System.Int32 inputOffset, System.Int32
inputCount) [0x0002e] in <381999f96ea944d79e461a81dcbea654>:0 at
System.Security.Cryptography.CryptoStream.FlushFinalBlock () [0x00013]
in <381999f96ea944d79e461a81dcbea654>:0 at
System.Security.Cryptography.CryptoStream.Dispose (System.Boolean
disposing) [0x0000b] in <381999f96ea944d79e461a81dcbea654>:0 at
System.IO.Stream.Close () [0x00000] in
<381999f96ea944d79e461a81dcbea654>:0 at System.IO.Stream.Dispose ()
[0x00000] in <381999f96ea944d79e461a81dcbea654>:0
问题根源与修复
核心问题
解密函数的错误在于直接读取底层decryptionStream的字节数组,跳过了CryptoStream的解密处理流程。CryptoStream需要完成加密数据的读取、解密、填充校验后,才能输出明文,直接访问原MemoryStream拿到的还是加密字节,导致填充校验失败。
修正后的解密函数
private T ReadEncryptedData<T>(string path) { var data = File.ReadAllText(path); byte[] array = Convert.FromBase64String(data); string result; using (Aes aes = Aes.Create()) { aes.Key = Convert.FromBase64String(KEY); aes.IV = Convert.FromBase64String(IV); aes.Padding = PaddingMode.PKCS7; using ICryptoTransform cryptoTransform = aes.CreateDecryptor(aes.Key, aes.IV); using MemoryStream decryptionStream = new(array); using CryptoStream cryptoStream = new(decryptionStream, cryptoTransform, CryptoStreamMode.Read); // 通过StreamReader读取CryptoStream处理后的明文 using StreamReader reader = new(cryptoStream); result = reader.ReadToEnd(); } Debug.Log($"Decrypted result: {result}"); return JsonConvert.DeserializeObject<T>(result); }
额外注意事项
- 后续动态生成IV时,需将加密时使用的IV与加密数据一起存储(比如放在加密数据头部),解密时先读取IV再解密主体内容,确保解密用的IV和加密完全一致。
- 确保KEY长度符合AES标准:AES-128对应16字节、AES-192对应24字节、AES-256对应32字节,Base64转换后的字符串长度需匹配对应字节数。
内容的提问来源于stack exchange,提问作者Ando

