C# .NET Framework下AES-gcm 128加解密实现相关问题咨询
Bouncy Castle 完全支持 AES-GCM 128 位加解密,以下是完整的实现步骤:
1. 引入Bouncy Castle库到.NET Framework项目
- 右键你的项目 → 选择「管理NuGet程序包」
- 搜索
BouncyCastle,找到官方发布的同名包(作者为Legion of the Bouncy Castle Inc.),点击安装即可完成引入
2. 完整AES-GCM 128加解密实现代码
首先引入需要的命名空间:
using System; using System.Text; using System.Security.Cryptography; using Org.BouncyCastle.Crypto.Engines; using Org.BouncyCastle.Crypto.Modes; using Org.BouncyCastle.Crypto.Parameters;
完整可运行的加解密代码和测试示例:
// 加密返回结果结构,包含解密需要的所有参数 public struct AesGcmEncryptResult { public byte[] Nonce; // 12字节随机数,解密必须和加密时一致 public byte[] CipherText; // 加密后的密文 public byte[] Tag; // 16字节认证标签,用于校验数据完整性 } /// <summary> /// AES-GCM 128位加密方法 /// </summary> /// <param name="key">16字节(128位)加密密钥</param> /// <param name="plainText">待加密明文</param> /// <param name="associatedData">可选关联数据,解密时需要传入完全相同的值</param> public static AesGcmEncryptResult AesGcmEncrypt(byte[] key, string plainText, byte[] associatedData = null) { if (key.Length != 16) throw new ArgumentException("AES-GCM 128位密钥长度必须为16字节"); // GCM算法推荐使用12字节的Nonce byte[] nonce = new byte[12]; // 生产环境请使用密码学安全的随机数生成器,不要用Random类 using (var rng = new RNGCryptoServiceProvider()) { rng.GetBytes(nonce); } byte[] plainBytes = Encoding.UTF8.GetBytes(plainText); GcmBlockCipher gcmCipher = new GcmBlockCipher(new AesEngine()); AeadParameters parameters = new AeadParameters(new KeyParameter(key), 128, nonce, associatedData); gcmCipher.Init(true, parameters); byte[] cipherTextWithTag = new byte[gcmCipher.GetOutputSize(plainBytes.Length)]; int processLen = gcmCipher.ProcessBytes(plainBytes, 0, plainBytes.Length, cipherTextWithTag, 0); gcmCipher.DoFinal(cipherTextWithTag, processLen); // 拆分密文和认证标签,Tag默认占结果的最后16字节 byte[] cipherText = new byte[cipherTextWithTag.Length - 16]; byte[] tag = new byte[16]; Array.Copy(cipherTextWithTag, 0, cipherText, 0, cipherText.Length); Array.Copy(cipherTextWithTag, cipherText.Length, tag, 0, 16); return new AesGcmEncryptResult { Nonce = nonce, CipherText = cipherText, Tag = tag }; } /// <summary> /// AES-GCM 128位解密方法 /// </summary> /// <param name="key">和加密时完全一致的16字节密钥</param> /// <param name="nonce">加密返回的12字节Nonce</param> /// <param name="cipherText">加密返回的密文</param> /// <param name="tag">加密返回的16字节认证标签</param> /// <param name="associatedData">和加密时完全一致的关联数据,无则传null</param> public static string AesGcmDecrypt(byte[] key, byte[] nonce, byte[] cipherText, byte[] tag, byte[] associatedData = null) { if (key.Length != 16) throw new ArgumentException("AES-GCM 128位密钥长度必须为16字节"); if (nonce.Length != 12) throw new ArgumentException("Nonce长度必须为12字节"); if (tag.Length != 16) throw new ArgumentException("认证标签长度必须为16字节"); // 合并密文和标签用于解密校验 byte[] cipherTextWithTag = new byte[cipherText.Length + tag.Length]; Array.Copy(cipherText, 0, cipherTextWithTag, 0, cipherText.Length); Array.Copy(tag, 0, cipherTextWithTag, cipherText.Length, tag.Length); GcmBlockCipher gcmCipher = new GcmBlockCipher(new AesEngine()); AeadParameters parameters = new AeadParameters(new KeyParameter(key), 128, nonce, associatedData); gcmCipher.Init(false, parameters); byte[] plainBytes = new byte[gcmCipher.GetOutputSize(cipherTextWithTag.Length)]; int processLen = gcmCipher.ProcessBytes(cipherTextWithTag, 0, cipherTextWithTag.Length, plainBytes, 0); gcmCipher.DoFinal(plainBytes, processLen); return Encoding.UTF8.GetString(plainBytes); } // 测试调用示例 public void TestAesGcm() { // 128位密钥,实际使用请从安全存储获取,不要硬编码 byte[] aesKey = Encoding.UTF8.GetBytes("your16bytekey1234"); string plainText = "待加密的测试内容"; // 加密 var encryptResult = AesGcmEncrypt(aesKey, plainText); Console.WriteLine($"密文Base64:{Convert.ToBase64String(encryptResult.CipherText)}"); Console.WriteLine($"Nonce Base64:{Convert.ToBase64String(encryptResult.Nonce)}"); Console.WriteLine($"Tag Base64:{Convert.ToBase64String(encryptResult.Tag)}"); // 解密 string decryptText = AesGcmDecrypt(aesKey, encryptResult.Nonce, encryptResult.CipherText, encryptResult.Tag); Console.WriteLine($"解密结果:{decryptText}"); }
3. 注意事项
- 不要直接用用户输入的明文密码作为密钥,实际生产建议通过PBKDF2等密钥派生算法生成符合长度要求的安全密钥
- 每次加密必须重新生成Nonce,相同密钥+Nonce组合重复使用会导致严重安全漏洞
- 加密时如果传入了关联数据,解密时必须传入完全相同的值,否则会校验失败抛出异常
- 密钥、Nonce、Tag三个参数解密时必须和加密时完全一致,任何一位改动都会导致解密失败
内容的提问来源于stack exchange,提问作者Kom Pe
相关产品推荐
相关产品推荐

