使用BouncyCastle C#库实现AES加解密失败,无法还原原文本求助
AES-CTR加解密失败问题排查与修复(Bouncy Castle C#)
你的代码存在三个核心逻辑错误,直接导致解密无法还原原始文本:
1. 解密输入处理错误
解密时,输入是经过URL安全Base64编码的密文,你先还原了-/_为+//,但错误地用Encoding.UTF8.GetBytes()将其转成字节数组——密文是二进制数据,不是UTF8编码的字符串,正确做法是用Convert.FromBase64String()解码还原后的Base64字符串,得到密文字节数组。
2. 密码器初始化模式错误
不管加密还是解密,你都调用cipher.Init(true, ...),其中true代表加密模式。解密时必须将第一个参数改为false,否则会把密文当成明文再次加密,完全偏离预期。
3. 解密输出处理错误
解密得到的是原始明文的UTF8字节数组,你却将其转成Base64字符串返回,正确做法是直接将解密后的字节数组转成UTF8字符串。
修正后的完整代码
using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Digests; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Security; using System.Text; static string Encrypt(string keyString, string input) { // 密钥处理:SHA256哈希生成256位密钥 var keyBytes = Encoding.UTF8.GetBytes(keyString); var sha256 = new Sha256Digest(); sha256.BlockUpdate(keyBytes, 0, keyBytes.Length); var keyBytesPadded = new byte[sha256.GetDigestSize()]; sha256.DoFinal(keyBytesPadded, 0); // 生成随机IV(CTR模式必须用唯一IV,这里用随机保证安全性) var iv = new byte[16]; new SecureRandom().NextBytes(iv); // 初始化AES-CTR加密器 var cipher = CipherUtilities.GetCipher("AES/CTR/NoPadding"); cipher.Init(true, new ParametersWithIV(ParameterUtilities.CreateKeyParameter("AES", keyBytesPadded), iv)); // 加密明文 var inputBytes = Encoding.UTF8.GetBytes(input); var encryptedBytes = cipher.DoFinal(inputBytes); // 将IV和密文拼接(解密时需要用同一个IV),再转URL安全Base64 var combinedBytes = new byte[iv.Length + encryptedBytes.Length]; Buffer.BlockCopy(iv, 0, combinedBytes, 0, iv.Length); Buffer.BlockCopy(encryptedBytes, 0, combinedBytes, iv.Length, encryptedBytes.Length); var base64 = Convert.ToBase64String(combinedBytes); return base64.Replace("+", "-").Replace("/", "_"); } static string Decrypt(string keyString, string input) { // 还原URL安全Base64为标准Base64 var standardBase64 = input.Replace("-", "+").Replace("_", "/"); var combinedBytes = Convert.FromBase64String(standardBase64); // 拆分IV和密文(IV长度16字节) var iv = new byte[16]; var encryptedBytes = new byte[combinedBytes.Length - iv.Length]; Buffer.BlockCopy(combinedBytes, 0, iv, 0, iv.Length); Buffer.BlockCopy(combinedBytes, iv.Length, encryptedBytes, 0, encryptedBytes.Length); // 密钥处理:和加密时一致的SHA256哈希 var keyBytes = Encoding.UTF8.GetBytes(keyString); var sha256 = new Sha256Digest(); sha256.BlockUpdate(keyBytes, 0, keyBytes.Length); var keyBytesPadded = new byte[sha256.GetDigestSize()]; sha256.DoFinal(keyBytesPadded, 0); // 初始化AES-CTR解密器(注意第二个参数是false) var cipher = CipherUtilities.GetCipher("AES/CTR/NoPadding"); cipher.Init(false, new ParametersWithIV(ParameterUtilities.CreateKeyParameter("AES", keyBytesPadded), iv)); // 解密密文,转成明文字符串 var decryptedBytes = cipher.DoFinal(encryptedBytes); return Encoding.UTF8.GetString(decryptedBytes); } const string key = "supersecret"; const string message = "hello world!"; // 测试验证 var encrypted = Encrypt(key, message); var decrypted = Decrypt(key, encrypted); Console.WriteLine(decrypted == message); // 输出True
额外提醒:原代码里加密和解密用的是固定全0的IV,这在CTR模式下非常危险——重复使用相同IV和密钥会导致加密完全失效。修正后的代码改用随机生成IV,并将IV和密文一起传输,这是CTR模式的标准安全做法。
内容的提问来源于stack exchange,提问作者Node.JS
相关产品推荐
相关产品推荐

