C# AES加密问题:首尾空格触发CryptographicException异常
搞定C# AES加密里的填充和块大小异常
老兄,我之前做C# AES加密的时候也踩过一模一样的坑,来给你拆解下这两个问题的本质和正确解法:
第一个坑:Padding is invalid and cannot be removed.
你一开始遇到这个异常,说白了就是加密和解密的填充模式没对齐。AES是块加密算法,要求输入数据的字节长度必须是块大小(默认128位,也就是16字节)的整数倍,所以得靠“填充”来补全不够的部分。如果加密时用了默认的PaddingMode.PKCS7(.NET默认就是这个),但解密时你改成了None,那解密端找不到对应的填充标记,自然就报错了。你改成None能暂时解决,但这其实是绕开问题,不是真的解决——这也直接导致了你第二个坑。
第二个坑:The input data is not a complete block.
当你把填充设为None后,带空格的字符串转成字节后,长度刚好不是16的整数倍,AES直接就炸了,因为它要求输入必须是完整的块。你移除填充设置其实还是没碰根儿上的问题,反而让你的加密代码只能处理长度刚好是16倍数的字符串,太受限了。
正确的打开方式:保持加解密参数完全一致,用标准填充
其实根本不用去掉填充,只要保证加密和解密时的填充模式、块大小、密钥、IV完全匹配就行,统一用PaddingMode.PKCS7就好,框架会自动帮你处理填充和去填充的事儿,不用你手动纠结块大小。
给你一个能直接用的示例代码,不管字符串带不带空格都能正常加密解密:
using System; using System.Security.Cryptography; using System.Text; public class AesHelper { // 加密方法 public static string EncryptString(string plainText, byte[] key, byte[] iv) { using (Aes aes = Aes.Create()) { aes.Key = key; aes.IV = iv; aes.Padding = PaddingMode.PKCS7; // 统一用标准填充 aes.Mode = CipherMode.CBC; // 常用模式,必须配IV var encryptor = aes.CreateEncryptor(aes.Key, aes.IV); using (var ms = new System.IO.MemoryStream()) { using (var cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write)) { using (var sw = new System.IO.StreamWriter(cs)) { sw.Write(plainText); } return Convert.ToBase64String(ms.ToArray()); } } } } // 解密方法 public static string DecryptString(string cipherText, byte[] key, byte[] iv) { using (Aes aes = Aes.Create()) { aes.Key = key; aes.IV = iv; aes.Padding = PaddingMode.PKCS7; // 和加密端完全一致 aes.Mode = CipherMode.CBC; var decryptor = aes.CreateDecryptor(aes.Key, aes.IV); using (var ms = new System.IO.MemoryStream(Convert.FromBase64String(cipherText))) { using (var cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read)) { using (var sr = new System.IO.StreamReader(cs)) { return sr.ReadToEnd(); } } } } } }
几个必须注意的点:
- 填充模式绝对要一致:加密用
PKCS7,解密也得用,不能一边用一边不用,不然肯定报错。 - IV别瞎搞:如果用CBC模式(默认就是),必须生成随机的IV,加密时把IV和密文一起传给解密端,不能硬编码IV,不然安全性会很差。
- 编码要统一:字符串转字节的时候,加密和解密要用同一种编码(比如
UTF8),不然也可能出现奇怪的问题。
如果你真的有特殊需求必须用PaddingMode.None,那得手动把输入数据的字节长度补成16的整数倍(比如补0),解密后再手动去掉补的内容,但这种方式很容易出错,除非万不得已,真不推荐。
内容的提问来源于stack exchange,提问作者Bicycle-riding Dog
相关产品推荐
相关产品推荐

