You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

BouncyCastle C# AES GCM解密求助:遇密钥长度与MAC校验错误

AES GCM加密解密问题修正(C# BouncyCastle)

原代码核心问题

  • 加密时每次生成新密钥,但解密未使用该密钥,反而错误将IV当作密钥传入,导致「密钥长度不合法」错误。
  • 解密未正确解析Base64密文,直接将字符串转UTF8字节,而非用Convert.FromBase64String解码。
  • 加密与解密使用的Nonce不一致(解密时用空数组),导致「GCM MAC校验失败」。
  • 解密时未传入与加密一致的关联数据,GCM参数初始化不完整。
  • 加密生成的密钥未保留,无法用于解密。

修正后的完整代码

加密函数

using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;
using System.Text;

public static string AesGcmEncrypt(string plainText, byte[] key, byte[] nonce, string associatedData = "")
{
    var plainBytes = Encoding.UTF8.GetBytes(plainText);
    var adBytes = Encoding.UTF8.GetBytes(associatedData);

    var gcm = new GcmBlockCipher(new AesEngine());
    var parameters = new AeadParameters(new KeyParameter(key), 128, nonce, adBytes);
    gcm.Init(true, parameters);

    var outputLength = gcm.GetOutputSize(plainBytes.Length);
    var cipherBytes = new byte[outputLength];

    var processed = gcm.ProcessBytes(plainBytes, 0, plainBytes.Length, cipherBytes, 0);
    gcm.DoFinal(cipherBytes, processed);

    // 将Nonce与密文+Tag拼接后转Base64,方便解密拆分
    var combined = new byte[nonce.Length + cipherBytes.Length];
    Buffer.BlockCopy(nonce, 0, combined, 0, nonce.Length);
    Buffer.BlockCopy(cipherBytes, 0, combined, nonce.Length, cipherBytes.Length);

    return Convert.ToBase64String(combined);
}

解密函数

public static string AesGcmDecrypt(string encryptedBase64, byte[] key, string associatedData = "")
{
    var combinedBytes = Convert.FromBase64String(encryptedBase64);
    // 拆分12字节Nonce(GCM标准推荐长度)和密文+Tag
    const int nonceLength = 12;
    var nonce = new byte[nonceLength];
    var cipherBytes = new byte[combinedBytes.Length - nonceLength];

    Buffer.BlockCopy(combinedBytes, 0, nonce, 0, nonceLength);
    Buffer.BlockCopy(combinedBytes, nonceLength, cipherBytes, 0, cipherBytes.Length);

    var adBytes = Encoding.UTF8.GetBytes(associatedData);

    var gcm = new GcmBlockCipher(new AesEngine());
    var parameters = new AeadParameters(new KeyParameter(key), 128, nonce, adBytes);
    gcm.Init(false, parameters);

    var outputLength = gcm.GetOutputSize(cipherBytes.Length);
    var plainBytes = new byte[outputLength];

    var processed = gcm.ProcessBytes(cipherBytes, 0, cipherBytes.Length, plainBytes, 0);
    gcm.DoFinal(plainBytes, processed);

    return Encoding.UTF8.GetString(plainBytes);
}

使用示例

public static void TestAesGcm()
{
    // 生成128位AES密钥(16字节)
    var keyGen = new CipherKeyGenerator();
    keyGen.Init(new KeyGenerationParameters(new SecureRandom(), 128));
    var key = ((KeyParameter)keyGen.GenerateKeyParameter()).GetKey();

    // 生成12字节Nonce(GCM标准推荐,需保证每次加密唯一)
    var nonce = new byte[12];
    new SecureRandom().NextBytes(nonce);

    string plainText = "Hello 123";
    string encrypted = AesGcmEncrypt(plainText, key, nonce);
    Console.WriteLine($"加密结果:{encrypted}");

    string decrypted = AesGcmDecrypt(encrypted, key);
    Console.WriteLine($"解密结果:{decrypted}");
}

关键修正说明

  1. 密钥管理:加密生成的密钥必须在解密方安全共享,示例中生成128位合规密钥,避免用IV代替密钥。
  2. Nonce规范:使用GCM推荐的12字节Nonce,加密时将Nonce与密文拼接,解密时拆分,确保两端Nonce一致。
  3. Base64处理:加密后将二进制数据转Base64,解密时反向解析,避免字符编码错误。
  4. GCM参数一致性:加密和解密使用相同的Tag长度(128位)、关联数据,保证MAC校验通过。

内容的提问来源于stack exchange,提问作者DemarcPoint

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 17:54:51