/// <summary>
/// 解密微信支付回调中的加密资源(AES-256-GCM)
/// </summary>
/// <param name="callbackBody">回调原始Body</param>
/// <param name="apiV3Key">APIv3密钥(32位)</param>
/// <returns>解密后的支付结果JSON</returns>
public string DecryptPaymentData(string callbackBody, string apiV3Key)
{
try
{
// 记录原始回调数据(用于调试)
_logger.Info($"原始回调数据: {callbackBody}");
// 1. 验证APIv3密钥长度(必须32位)
if (apiV3Key.Length != 32)
{
throw new ArgumentException($"APIv3密钥长度错误(实际:{apiV3Key.Length}位,要求:32位)");
}
// 2. 解析回调Body,提取加密资源
JObject callbackJson = JObject.Parse(callbackBody);
JObject resource = callbackJson["resource"] as JObject;
if (resource == null)
throw new KeyNotFoundException("回调Body中未找到resource节点");
// 3. 提取解密参数(严格对应微信字段)
string algorithm = resource["algorithm"]?.ToString() ?? "";
string ciphertext = resource["ciphertext"]?.ToString() ?? "";
string nonce = resource["nonce"]?.ToString() ?? "";
string associatedData = resource["associated_data"]?.ToString() ?? "";
string originalType = resource["original_type"]?.ToString() ?? "";
// 记录参数用于调试
_logger.Info($"算法: {algorithm}(需为AEAD_AES_256_GCM)");
_logger.Info($"原始Nonce: {nonce}(长度:{nonce.Length}字符)");
_logger.Info($"原始Associated Data: {associatedData}");
_logger.Info($"原始类型: {originalType}");
_logger.Info($"Ciphertext长度: {ciphertext.Length}");
// 验证参数非空
if (string.IsNullOrEmpty(ciphertext))
throw new ArgumentException("ciphertext为空");
if (string.IsNullOrEmpty(nonce))
throw new ArgumentException("nonce为空");
if (algorithm != "AEAD_AES_256_GCM")
throw new ArgumentException($"不支持的加密算法:{algorithm}(要求AEAD_AES_256_GCM)");
// 4. 转换参数为字节数组(核心修正)
byte[] keyBytes = Encoding.UTF8.GetBytes(apiV3Key); // 密钥:UTF8编码(32字节)
// Nonce:直接UTF8编码(微信是12字符明文,无需Base64解码)
byte[] nonceBytes = Encoding.UTF8.GetBytes(nonce);
// 关联数据:为空时传null(微信规范)
byte[] associatedDataBytes = string.IsNullOrEmpty(associatedData)
? null
: Encoding.UTF8.GetBytes(associatedData);
// 密文:Base64解码
byte[] ciphertextBytes = Convert.FromBase64String(ciphertext);
// 5. 严格验证参数长度(微信强制规范)
if (nonceBytes.Length != 12)
{
throw new ArgumentException(
$"nonce长度错误(原始字符串:{nonce},UTF8编码后{nonceBytes.Length}字节,要求12字节)。" +
$"可能原因:回调数据被截断,或nonce提取错误。"
);
}
if (ciphertextBytes.Length <= 16)
throw new ArgumentException($"ciphertext长度不足(实际:{ciphertextBytes.Length}字节,需>16字节,确保包含16字节Tag)");
// 6. 记录转换后参数(调试用)
_logger.Info($"APIv3密钥长度: {keyBytes.Length}(正确应为32)");
_logger.Info($"Nonce长度: {nonceBytes.Length}(正确应为12)");
_logger.Info($"关联数据长度: {associatedDataBytes?.Length ?? 0}");
_logger.Info($"密文长度: {ciphertextBytes.Length}");
_logger.Info($"Nonce内容: {BitConverter.ToString(nonceBytes)}");
_logger.Info($"关联数据内容: {associatedData}");
// 7. 执行解密
byte[] plaintextBytes = Decrypt(
ciphertextBytes: ciphertextBytes,
keyBytes: keyBytes,
nonceBytes: nonceBytes,
associatedDataBytes: associatedDataBytes,
tagLength: 16
);
// 8. 转换为明文
string plaintext = Encoding.UTF8.GetString(plaintextBytes);
_logger.Info($"解密成功: {plaintext}");
return plaintext;
}
catch (Exception ex)
{
_logger.Error($"解密回调数据失败:{ex.Message}", ex);
throw new InvalidOperationException($"解密回调数据失败:{ex.Message}", ex);
}
}
/// <summary>
/// AES-256-GCM解密(严格遵循微信支付规范)
/// </summary>
public byte[] Decrypt(
byte[] ciphertextBytes,
byte[] keyBytes,
byte[] nonceBytes,
byte[] associatedDataBytes = null,
int tagLength = 16)
{
try
{
// 分割密文和Tag(微信ciphertext格式:密文 + 16字节Tag)
byte[] ciphertext = new byte[ciphertextBytes.Length - tagLength];
byte[] tag = new byte[tagLength];
Array.Copy(ciphertextBytes, 0, ciphertext, 0, ciphertext.Length);
Array.Copy(ciphertextBytes, ciphertext.Length, tag, 0, tagLength);
_logger.Info($"密文部分长度: {ciphertext.Length}");
_logger.Info($"Tag长度: {tag.Length}(正确应为16)");
_logger.Info($"Tag内容: {BitConverter.ToString(tag)}");
// 初始化GCM引擎
GcmBlockCipher cipher = new GcmBlockCipher(new AesEngine());
AeadParameters parameters = new AeadParameters(
new KeyParameter(keyBytes),
tagLength * 8, // Tag长度(位)
nonceBytes, // 随机数(必须与加密时一致)
associatedDataBytes // 关联数据(可为null)
);
// 初始化解密模式
cipher.Init(false, parameters);
// 执行解密
byte[] output = new byte[cipher.GetOutputSize(ciphertext.Length)];
int len = cipher.ProcessBytes(ciphertext, 0, ciphertext.Length, output, 0);
cipher.DoFinal(output, len); // 此处会校验MAC,失败则抛异常
return output;
}
catch (InvalidCipherTextException ex)
{
// MAC校验失败(最可能:密钥错误、nonce错误、数据篡改)
_logger.Error($"AES-GCM解密失败(MAC校验不通过): {ex.Message}", ex);
_logger.Error($"失败参数: 密钥={BitConverter.ToString(keyBytes)}, Nonce={BitConverter.ToString(nonceBytes)}");
throw new CryptographicException("AES-GCM解密失败(密钥错误、数据篡改或参数不匹配)", ex);
}
catch (Exception ex)
{
_logger.Error($"AES-GCM解密过程异常: {ex.Message}", ex);
throw new CryptographicException("AES-GCM解密过程发生异常", ex);
}
}
[2025-09-10 08:50:37.393] [INFO] Cnso.Wechat.Payment.Services.WechatPayV3NotifyService: 原始回调数据: {"id":"143cca6d-1e34-5f05-a732-dbfb8b797b19","create_time":"2025-09-10T08:50:36+08:00","resource_type":"encrypt-resource","event_type":"TRANSACTION.SUCCESS","summary":"支付成功","resource":{"original_type":"transaction","algorithm":"AEAD_AES_256_GCM","ciphertext":"Fdk3D38J+AnhticRwDPONqkY/z+Puhi04F8fpRi1TOIh5agrHGcmRWKHECIjwrRExkqaGw/fdPcI58Yp5WWxLNE7Fzy6sY9CxbTW2lPvjcZshgrtGHwuhm19lnxQ926mc9t9cQf56ZARklXeYchYk6fIqC7XAt8URp7+VHO9NrUu9Rat/TsYSvJIzuUpiHRu7W/mfhllO676mOs5MTPstEIHq87x1QMVpnjhiJiYdZPMt8kSx2EVg+D8VgrebAHaV5rIRkrDyFLEyA5t3cwCjF57bOIxjtxKuGLMKFpSaBpdkztwUH6d104O7kCoDzxfIK81pLgv47NXZWiT14YBhUJhcg8S2Nkn9zZwWkOJnVlnV39UtaDgeWohuSTjyyOLT8girIJ6xd4cXsbaFmaX4HTgAtH9k/opBWhjn3nNtYqTwUBE/9HeHHjXFN6n/mBS3J9azcUT1ZjUiCXWluxUN0Vb7RQCGQv8OHBnCVW4cKaKX0c8GJoy63QdS8/0k9FfN918SkiQhXvFgGa4AlU4LnUdomoAukR05ujSPWhU+tiwY2n5NTWOpDGtEJ1STuRdYlgp6XHL17xEk+n4m+toyYHt","associated_data":"transaction","nonce":"G4LcckuzL8Vv"}}
[2025-09-10 08:50:37.393] : 算法: AEAD_AES_256_GCM(需为AEAD_AES_256_GCM)
[2025-09-10 08:50:37.393] : 原始Nonce: G4LcckuzL8Vv(长度:12字符)
[2025-09-10 08:50:37.393] : 原始Associated Data: transaction
[2025-09-10 08:50:37.393] : 原始类型: transaction
[2025-09-10 08:50:37.393] : Ciphertext长度: 600
[2025-09-10 08:50:37.393] : APIv3密钥长度: 32(正确应为32)
[2025-09-10 08:50:37.393] : Nonce长度: 12(正确应为12)
[2025-09-10 08:50:37.393] : 关联数据长度: 11
[2025-09-10 08:50:37.393] : 密文长度: 450
[2025-09-10 08:50:37.393] : Nonce内容: 47-34-4C-63-63-6B-75-7A-4C-38-56-76
[2025-09-10 08:50:37.393] : 关联数据内容: transaction
[2025-09-10 08:50:37.393] : 密文部分长度: 434
[2025-09-10 08:50:37.393] : Tag长度: 16(正确应为16)
[2025-09-10 08:50:37.393] : Tag内容: 29-E9-71-CB-D7-BC-44-93-E9-F8-9B-EB-68-C9-81-ED
[2025-09-10 08:50:37.424] [ERROR] Cnso.Wechat.Payment.Services.WechatPayV3NotifyService: AES-GCM解密失败(MAC校验不通过): mac check in GCM failed
异常: mac check in GCM failed

先校验一下你的 key 对不对https://tools.aifuwu.net/wechat-pay-tools/apiv3-key-validator