AES加密解密异常:加密结果多变且无法正常解密求助
问题原因与解决方案
核心问题
你的代码每次调用Aes.Create()时,都会自动生成随机的密钥和初始化向量(IV)。这导致:
- 同一明文每次加密用的密钥/IV不同,结果自然不一样;
- 解密时又生成新的随机密钥/IV,和加密时的完全不匹配,所以解密出乱码。
修复AES加密解密代码
如果坚持用AES,需要固定密钥和IV(因为你不需要高强度加密,可以硬编码一套固定值),加密和解密使用同一套密钥/IV:
// 固定的密钥和IV(可自行生成后转为Base64字符串替换占位符) private static readonly byte[] FixedKey = Convert.FromBase64String("abcdefghijklmnopqrstuvwxyz123456"); private static readonly byte[] FixedIV = Convert.FromBase64String("abcdefghijklmnop"); public static string Encrypt(string plainText) { if (Settings.LicenseOK()) { byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText); using var symmetricKey = Aes.Create(); symmetricKey.Key = FixedKey; symmetricKey.IV = FixedIV; symmetricKey.Padding = PaddingMode.Zeros; ICryptoTransform encryptor = symmetricKey.CreateEncryptor(symmetricKey.Key, symmetricKey.IV); using MemoryStream ms = new MemoryStream(); using CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write); cs.Write(plainTextBytes, 0, plainTextBytes.Length); cs.FlushFinalBlock(); return Convert.ToBase64String(ms.ToArray(), Base64FormattingOptions.None); } else throw new Exception("Errore nella DLL GDWS"); } public static string Decrypt(string cipherText) { if (Settings.LicenseOK()) { byte[] cipherTextBytes = Convert.FromBase64String(cipherText); using var symmetricKey = Aes.Create(); symmetricKey.Key = FixedKey; symmetricKey.IV = FixedIV; symmetricKey.Padding = PaddingMode.Zeros; ICryptoTransform decryptor = symmetricKey.CreateDecryptor(symmetricKey.Key, symmetricKey.IV); using MemoryStream ms = new MemoryStream(cipherTextBytes); using CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read); using MemoryStream resultMs = new MemoryStream(); cs.CopyTo(resultMs); byte[] plainTextBytes = resultMs.ToArray(); // 移除填充的0字节避免乱码 plainTextBytes = plainTextBytes.TakeWhile(b => b != 0).ToArray(); return Encoding.UTF8.GetString(plainTextBytes); } else throw new Exception("Errore nella DLL GDWS"); }
说明:
- 固定密钥/IV可通过临时调用一次
Aes.Create(),提取其Key和IV转成Base64字符串得到; - 修复了解密时的读取逻辑,改用
CopyTo确保读取完整数据,同时移除填充的0字节避免末尾乱码。
更适合需求的方案:仅防篡改(无需加密内容)
如果你不需要隐藏明文内容,只是防止用户篡改,用HMAC签名更简单高效:把明文和签名拼接存储,读取时重新计算签名对比即可。
private static readonly byte[] HmacKey = Convert.FromBase64String("abcdefghijklmnopqrstuvwxyz123456"); // 生成带签名的字符串 public static string CreateSignedString(string plainText) { if (!Settings.LicenseOK()) throw new Exception("Errore nella DLL GDWS"); using var hmac = new HMACSHA256(HmacKey); byte[] plainBytes = Encoding.UTF8.GetBytes(plainText); byte[] signatureBytes = hmac.ComputeHash(plainBytes); string signature = Convert.ToBase64String(signatureBytes); return $"{plainText}||{signature}"; } // 验证并提取原始明文 public static string VerifyAndGetOriginal(string signedText) { if (!Settings.LicenseOK()) throw new Exception("Errore nella DLL GDWS"); string[] parts = signedText.Split(new[] { "||" }, StringSplitOptions.None); if (parts.Length != 2) throw new InvalidOperationException("字符串已被篡改"); string plainText = parts[0]; string storedSignature = parts[1]; using var hmac = new HMACSHA256(HmacKey); byte[] plainBytes = Encoding.UTF8.GetBytes(plainText); byte[] computedSignatureBytes = hmac.ComputeHash(plainBytes); string computedSignature = Convert.ToBase64String(computedSignatureBytes); // 常量时间比较防止时序攻击 if (!CryptographicOperations.FixedTimeEquals(Encoding.UTF8.GetBytes(storedSignature), Encoding.UTF8.GetBytes(computedSignature))) throw new InvalidOperationException("字符串已被篡改"); return plainText; }
优势:
- 逻辑简单,无需处理加密解密的填充、IV等细节;
- 明文可见,但用户篡改后签名会不匹配,无法通过验证。
内容的提问来源于stack exchange,提问作者The Agony
相关产品推荐
相关产品推荐

