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

Angular与C#实现AES-GCM加解密报错排查及示例请求

AES-GCM 加解密认证标签不匹配问题排查及可运行代码

问题根源

你的代码存在以下关键错误,导致解密时认证标签验证失败:

  • IV编码不一致:Angular端将生成的IV转为十六进制字符串,但C#端用Base64解析,导致IV字节完全不符。
  • 附加数据未同步:加密时指定了additionalData: 'nvn',但解密时未传入该数据——GCM模式下附加数据会参与认证计算,缺失必然导致标签验证失败。
  • 变量逻辑混淆:C#端将拆分后的tag错误命名为additionalString,易引发逻辑误解。
  • 密钥长度验证缺失:AES-256-GCM要求密钥必须是32字节(256位),原代码未做长度校验。

修正后的可运行代码

Angular 加密代码(使用node-forge)

import * as forge from 'node-forge';

// 注意:密钥需为256位(32字节),示例用Base64编码格式,也可直接传入二进制缓冲区
const AES_KEY_BASE64 = '你的256位密钥Base64字符串'; // 比如:生成32字节随机数后转Base64
const FIXED_ADDITIONAL_DATA = 'nvn'; // 两端必须完全一致

function encryptAesGcm(data: string | object): string {
  // 生成12字节(96位)随机IV,符合GCM最佳实践
  const ivBuffer = forge.random.getBytesSync(12);
  const ivBase64 = forge.util.encode64(ivBuffer);

  // 解码密钥为二进制缓冲区
  const keyBuffer = forge.util.decode64(AES_KEY_BASE64);

  // 初始化GCM加密器
  const cipher = forge.cipher.createCipher('AES-GCM', keyBuffer);
  cipher.start({
    iv: ivBuffer, // 传入二进制缓冲区而非字符串
    additionalData: FIXED_ADDITIONAL_DATA,
    tagLength: 128
  });

  // 处理明文数据
  const plaintext = typeof data === 'object' ? JSON.stringify(data) : data.toString();
  cipher.update(forge.util.createBuffer(plaintext, 'utf8'));
  cipher.finish();

  // 转换密文和标签为Base64
  const ciphertextBase64 = forge.util.encode64(cipher.output.data);
  const tagBase64 = forge.util.encode64(cipher.mode.tag.data);

  // 拼接传输内容:IV|标签|密文
  return `${ivBase64}|${tagBase64}|${ciphertextBase64}`;
}

// 使用示例
const testData = "{hello world}";
const transmitMsg = encryptAesGcm(testData);
console.log('加密后传输内容:', transmitMsg);

C# 解密代码(使用System.Cryptography)

using System;
using System.Text;
using System.Security.Cryptography;

public class AesGcmDecryptor
{
    private const string FIXED_ADDITIONAL_DATA = "nvn"; // 必须和Angular端一致
    private const int AES_256_KEY_SIZE = 32; // 256位密钥对应32字节

    public static string DecryptAesGcm(string cipherText, string keyBase64)
    {
        // 拆分传输内容
        string[] parts = cipherText.Split('|');
        if (parts.Length != 3)
            throw new ArgumentException("无效的加密内容格式");

        string ivBase64 = parts[0];
        string tagBase64 = parts[1];
        string ciphertextBase64 = parts[2];

        // 解码各部分为字节数组
        byte[] keyBytes = Convert.FromBase64String(keyBase64);
        if (keyBytes.Length != AES_256_KEY_SIZE)
            throw new ArgumentException("密钥长度必须为32字节(AES-256)");

        byte[] ivBytes = Convert.FromBase64String(ivBase64);
        byte[] tagBytes = Convert.FromBase64String(tagBase64);
        byte[] ciphertextBytes = Convert.FromBase64String(ciphertextBase64);

        // 初始化GCM解密器并解密
        using var aesGcm = new AesGcm(keyBytes);
        byte[] plaintextBytes = new byte[ciphertextBytes.Length];
        aesGcm.Decrypt(ivBytes, ciphertextBytes, tagBytes, plaintextBytes, Encoding.UTF8.GetBytes(FIXED_ADDITIONAL_DATA));

        return Encoding.UTF8.GetString(plaintextBytes);
    }

    // 使用示例
    public static void Main()
    {
        string keyBase64 = "你的256位密钥Base64字符串"; // 和Angular端一致
        string cipherText = "从Angular端获取的传输内容";
        string plaintext = DecryptAesGcm(cipherText, keyBase64);
        Console.WriteLine("解密结果: " + plaintext);
    }
}

关键注意事项

  • 密钥管理:禁止硬编码密钥,建议通过环境变量或安全配置中心传递。
  • IV规则:GCM模式下IV必须随机且唯一(每次加密生成新IV),推荐使用12字节长度(符合NIST标准)。
  • 附加数据一致性:如果不需要附加数据,两端都要设为null或空字符串,不可一端设置一端忽略。
  • 编码统一:所有二进制数据(IV、密钥、密文、标签)的Base64编码/解码逻辑必须两端完全一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 00:01:20