迁移RijndaelManaged至AES后解密报错:填充无效无法移除
问题:AES替换RijndaelManaged后抛出「填充无效且无法移除」异常
将加密组件从RijndaelManaged替换为Aes后,代码无法正常运行,抛出Padding is invalid and cannot be removed异常,此前使用RijndaelManaged时代码可正常工作。
代码中两次调用DecryptStringFromBytes_Aes方法:
- 第一次传入长度为80的
byte[],可正常执行并返回预期字符串; - 将返回字符串转换为长度48的
byte[]后第二次调用该方法,触发上述异常。已尝试调整填充模式或加密模式,问题仍未解决。
相关代码
// encryptedText comes as a post from another web application public static string DecryptStringAES(string encryptedText, string key) { var keybytes = Encoding.UTF8.GetBytes(key); var iv = keybytes; var encryptStringToBytes = EncryptStringToBytes_Aes(encryptedText, keybytes, iv); // roundtrip value is same as encryptedText -- which came from another webapp. // Decrypt the bytes to a string. here encryptStringToBytes is byte[80] // this line does not throw the exception var roundtrip = DecryptStringFromBytes_Aes(encryptStringToBytes, keybytes, iv); //DECRYPT FROM CRIPTOJS var encrypted = Convert.FromBase64String(roundtrip); //here encryptStringToBytes is byte[48] //This Line throws the exception --Padding is invalid and cannot be removed var id = DecryptStringFromBytes_Aes(encrypted, keybytes, iv); return id; } private static string DecryptStringFromBytes_Aes(byte[] cipherText, byte[] Key, byte[] IV) { if (cipherText == null || cipherText.Length <= 0) throw new ArgumentNullException("cipherText"); if (Key == null || Key.Length <= 0) throw new ArgumentNullException("Key"); if (IV == null || IV.Length <= 0) throw new ArgumentNullException("IV"); string plaintext = null; try { using (Aes aesAlg = Aes.Create()) { aesAlg.Mode = CipherMode.CFB; aesAlg.Padding = PaddingMode.PKCS7; aesAlg.Key = Key; aesAlg.IV = IV; ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV); using (MemoryStream msDecrypt = new MemoryStream(cipherText)) { using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read)) { using (StreamReader srDecrypt = new StreamReader(csDecrypt)) { plaintext = srDecrypt.ReadToEnd(); } } } } } catch (Exception ex) { string err = ex.Message; throw; } return plaintext; } private static byte[] EncryptStringToBytes_Aes(string plainText, byte[] Key, byte[] IV) { if (plainText == null || plainText.Length <= 0) throw new ArgumentNullException("plainText"); if (Key == null || Key.Length <= 0) throw new ArgumentNullException("Key"); if (IV == null || IV.Length <= 0) throw new ArgumentNullException("IV"); byte[] encrypted; try { using (Aes aesAlg = Aes.Create()) { aesAlg.Mode = CipherMode.CFB; aesAlg.Padding = PaddingMode.PKCS7; aesAlg.Key = Key; aesAlg.IV = IV; ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV); using (MemoryStream msEncrypt = new MemoryStream()) { using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)) { using (StreamWriter swEncrypt = new StreamWriter(csEncrypt)) { swEncrypt.Write(plainText); } encrypted = msEncrypt.ToArray(); } } } } catch (Exception ex) { string er = ex.Message; throw ex; } return encrypted; }
问题分析与修复方案
核心原因
- CFB模式参数不匹配:
RijndaelManaged支持自定义块大小,而Aes固定为128位块大小。此外,.NET的Aes默认CFB反馈大小为8位,而CryptoJS默认使用128位反馈大小,参数不一致会导致解密数据错位,触发填充错误。 - IV复用问题:代码中直接将密钥字节作为IV,不符合加密规范——IV应随机生成并与加密端完全一致,复用密钥会导致块对齐错误。
- 跨平台编码差异:CryptoJS和.NET在字符串转字节、Base64处理上可能存在编码差异,导致解密时数据不完整或错位。
具体修复步骤
- 统一CFB反馈大小:在
Aes配置中明确设置FeedbackSize为128(匹配CryptoJS默认值):aesAlg.FeedbackSize = 128; - 修正IV使用逻辑:确保解密时使用的IV与CryptoJS加密时的IV完全一致。如果CryptoJS通过密钥派生IV(如PBKDF2),需在.NET中实现相同的派生逻辑,不要复用密钥作为IV。
- 调整解密读取方式:对于流模式(CFB),改用
BinaryReader读取原始字节再转字符串,避免StreamReader编码转换引入的问题:using (BinaryReader brDecrypt = new BinaryReader(csDecrypt)) { byte[] plainBytes = brDecrypt.ReadBytes((int)csDecrypt.Length); plaintext = Encoding.UTF8.GetString(plainBytes); } - 验证数据完整性:检查
Convert.FromBase64String(roundtrip)得到的byte[]是否与CryptoJS加密输出的原始字节完全一致,排除Base64转换错误。
内容的提问来源于stack exchange,提问作者istudent
相关产品推荐
相关产品推荐

