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

C# AES-GCM加密解密异常:解密失败报参数越界求助

解决AES-GCM加密解密不匹配的问题

在C#中使用AES-GCM实现加密解密时,现有加密代码生成的密文无法被原解密代码解析,运行时抛出错误:Specified argument was out of the range of valid values。要求保留现有解密代码不变,修改加密代码修复问题。

错误原因

原加密代码的核心问题是没有将AES-GCM生成的认证标签(tag)写入到最终输出的密文中,但解密代码会从密文的最后16字节读取tag,导致解密时无法获取合法的tag,触发参数越界错误。

修改后的加密代码(保留原解密代码不变)

仅调整加密逻辑,其余代码保持原样:

// Encryption code.
private static byte[] salt = new byte[16];
private static byte[] iv = new byte[12];
private const int iterations = 100000;

public string Encrypt(string key, string data)
{
     byte[] tag = new byte[16];

     using (var rng = RandomNumberGenerator.Create())
     {
         rng.GetBytes(salt);
         rng.GetBytes(iv);
     }

     byte[] dataBytes = Encoding.UTF8.GetBytes(data);
     byte[] privateKey = DeriveKey(key);

     using (AesGcm aes = new AesGcm(privateKey, tag.Length))
     {
         byte[] encrypted = new byte[dataBytes.Length];
         aes.Encrypt(iv, dataBytes, encrypted, tag);

         // 修复点1:扩展缓冲区长度,加入tag的16字节容量
         byte[] combinedBuffer = new byte[salt.Length + iv.Length + encrypted.Length + tag.Length];
         Buffer.BlockCopy(salt, 0, combinedBuffer, 0, salt.Length);
         Buffer.BlockCopy(iv, 0, combinedBuffer, salt.Length, iv.Length);
         Buffer.BlockCopy(encrypted, 0, combinedBuffer, salt.Length + iv.Length, encrypted.Length);
         // 修复点2:将tag写入缓冲区末尾,与解密代码的读取逻辑对齐
         Buffer.BlockCopy(tag, 0, combinedBuffer, salt.Length + iv.Length + encrypted.Length, tag.Length);

         string base64Buff = BuffToBase64(combinedBuffer);
         return base64Buff;
     }
}

// 以下方法保持不变
public static byte[] DeriveKey(string password)
{
     byte[] passwordBytes = Encoding.UTF8.GetBytes(password);

     using (var pbkdf2 = new Rfc2898DeriveBytes(passwordBytes, salt, iterations, HashAlgorithmName.SHA256))
     {
         byte[] key = pbkdf2.GetBytes(32);
         return key;
     }
}

public static string BuffToBase64(byte[] buff)
{
    return Convert.ToBase64String(buff);
}

public static byte[] Base64ToBuff(string b64)
{
    return Convert.FromBase64String(b64);
}
 
// Decryption code 保持不变
public string Decrypt(string password, string encryptedString)
{
    Span<byte> encryptedData = Convert.FromBase64String(encryptedString).AsSpan();
    Span<byte> salt = encryptedData[..16]; 
    Span<byte> nonce = encryptedData[16..(16 + 12)];
    Span<byte> data = encryptedData[(16 + 12)..^16];
    Span<byte> tag = encryptedData[^16..];

    using Rfc2898DeriveBytes pbkdf2 = new(Encoding.UTF8.GetBytes(password), salt.ToArray(), 100000, HashAlgorithmName.SHA256);
    using AesGcm aes = new(pbkdf2.GetBytes(32), tag.Length); 

    Span<byte> result = new byte[data.Length];
    aes.Decrypt(nonce, data, tag, result);
    return Encoding.UTF8.GetString(result);
}

// 测试代码
var r = new AesGcmEncryption().Encrypt("my passphrase", "abcd");
var r2 = new AesGcmEncryption().Decrypt("my passphrase", r);

Console.WriteLine(r);
Console.WriteLine(r2);

修改关键点说明

  1. 扩展combinedBuffer的长度,增加tag的16字节容量,确保能容纳salt、iv、密文、tag四部分数据
  2. 新增tag的写入逻辑,将AES-GCM生成的认证标签放到缓冲区末尾,完全匹配解密代码从密文最后16字节读取tag的逻辑

额外提示(非必须修改)

原代码中salt和iv使用静态字段,多线程并发加密时可能出现数据干扰问题,建议改为方法内的局部变量,避免不同加密请求互相影响。该修改不影响解密兼容性,可根据实际场景优化。

内容的提问来源于stack exchange,提问作者TOAN-VN

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 04:26:08