2022-11-13 23:17:18 +08:00
|
|
|
|
using System;
|
2021-05-10 15:30:00 +08:00
|
|
|
|
|
|
|
|
|
|
namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
|
|
|
|
|
|
{
|
2024-02-05 10:53:59 +08:00
|
|
|
|
using SKIT.FlurlHttpClient.Primitives;
|
2024-02-06 11:23:04 +08:00
|
|
|
|
using SKIT.FlurlHttpClient.Wechat.TenpayV3.Constants;
|
2024-02-05 10:53:59 +08:00
|
|
|
|
|
2021-07-20 01:20:31 +08:00
|
|
|
|
public static class WechatTenpayClientEventDecryptionExtensions
|
2021-05-10 15:30:00 +08:00
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
2021-05-28 19:08:11 +08:00
|
|
|
|
/// <para>反序列化得到 <see cref="WechatTenpayEvent"/> 对象。</para>
|
2021-05-10 15:30:00 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="client"></param>
|
2024-01-29 23:12:37 +08:00
|
|
|
|
/// <param name="webhookJson"></param>
|
2021-05-10 15:30:00 +08:00
|
|
|
|
/// <returns></returns>
|
2024-01-29 23:12:37 +08:00
|
|
|
|
public static WechatTenpayEvent DeserializeEvent(this WechatTenpayClient client, string webhookJson)
|
2021-05-10 15:30:00 +08:00
|
|
|
|
{
|
2024-01-29 23:12:37 +08:00
|
|
|
|
if (client is null) throw new ArgumentNullException(nameof(client));
|
2024-02-05 10:53:59 +08:00
|
|
|
|
if (webhookJson is null) throw new ArgumentNullException(webhookJson);
|
2021-05-10 15:30:00 +08:00
|
|
|
|
|
2024-01-29 23:12:37 +08:00
|
|
|
|
return client.JsonSerializer.Deserialize<WechatTenpayEvent>(webhookJson);
|
2021-05-10 15:30:00 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 返回序列化并解密事件数据中被加密的通知数据。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <typeparam name="T"></typeparam>
|
|
|
|
|
|
/// <param name="client"></param>
|
2024-01-29 23:12:37 +08:00
|
|
|
|
/// <param name="webhookEvent"></param>
|
2021-05-10 15:30:00 +08:00
|
|
|
|
/// <returns></returns>
|
2024-01-29 23:12:37 +08:00
|
|
|
|
public static T DecryptEventResource<T>(this WechatTenpayClient client, WechatTenpayEvent webhookEvent)
|
2021-05-28 19:08:11 +08:00
|
|
|
|
where T : WechatTenpayEvent.Types.IDecryptedResource, new()
|
2021-05-10 15:30:00 +08:00
|
|
|
|
{
|
2024-01-29 23:12:37 +08:00
|
|
|
|
if (client is null) throw new ArgumentNullException(nameof(client));
|
|
|
|
|
|
if (webhookEvent is null) throw new ArgumentNullException(nameof(webhookEvent));
|
2021-05-10 15:30:00 +08:00
|
|
|
|
|
2024-01-29 23:12:37 +08:00
|
|
|
|
return DecryptEventResource<T>(client, webhookEvent.Resource);
|
2021-05-10 15:30:00 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 返回序列化并解密事件数据中被加密的通知数据。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <typeparam name="T"></typeparam>
|
|
|
|
|
|
/// <param name="client"></param>
|
2024-01-29 23:12:37 +08:00
|
|
|
|
/// <param name="webhookEventResource"></param>
|
2021-05-10 15:30:00 +08:00
|
|
|
|
/// <returns></returns>
|
2024-01-29 23:12:37 +08:00
|
|
|
|
public static T DecryptEventResource<T>(this WechatTenpayClient client, WechatTenpayEvent.Types.Resource webhookEventResource)
|
2021-05-28 19:08:11 +08:00
|
|
|
|
where T : WechatTenpayEvent.Types.IDecryptedResource, new()
|
2021-05-10 15:30:00 +08:00
|
|
|
|
{
|
2024-01-29 23:12:37 +08:00
|
|
|
|
if (client is null) throw new ArgumentNullException(nameof(client));
|
|
|
|
|
|
if (webhookEventResource is null) throw new ArgumentNullException(nameof(webhookEventResource));
|
2021-05-10 15:30:00 +08:00
|
|
|
|
|
|
|
|
|
|
string plainJson;
|
2024-01-29 23:12:37 +08:00
|
|
|
|
switch (webhookEventResource.Algorithm)
|
2021-05-10 15:30:00 +08:00
|
|
|
|
{
|
2024-02-06 11:23:04 +08:00
|
|
|
|
case EncryptionAlgorithms.AEAD_AES_256_GCM:
|
2022-11-13 23:17:18 +08:00
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
plainJson = Utilities.AESUtility.DecryptWithGCM(
|
2024-02-05 10:53:59 +08:00
|
|
|
|
encodingKey: new EncodedString(client.Credentials.MerchantV3Secret, EncodingKinds.Literal),
|
|
|
|
|
|
encodingNonce: new EncodedString(webhookEventResource.Nonce, EncodingKinds.Literal),
|
|
|
|
|
|
encodingAssociatedData: new EncodedString(webhookEventResource.AssociatedData, EncodingKinds.Literal),
|
|
|
|
|
|
encodingCipher: new EncodedString(webhookEventResource.CipherText, EncodingKinds.Base64)
|
|
|
|
|
|
)!;
|
2022-11-13 23:17:18 +08:00
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
2024-01-29 23:12:37 +08:00
|
|
|
|
throw new WechatTenpayException("Failed to decrypt event resource data. Please see the inner exception for more details.", ex);
|
2022-11-13 23:17:18 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
2024-02-06 11:23:04 +08:00
|
|
|
|
case EncryptionAlgorithms.AEAD_SM4_128_GCM:
|
2022-11-13 23:17:18 +08:00
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
// REF: https://pay.weixin.qq.com/docs/merchant/development/shangmi/guide.html
|
|
|
|
|
|
// 由于 SM4 密钥长度的限制,密钥由 APIv3 密钥通过国密 SM3 Hash 计算生成。SM4 密钥取其摘要(256bit)的前 128bit。
|
2024-02-05 10:53:59 +08:00
|
|
|
|
byte[] secretBytes = Utilities.SM3Utility.Hash(EncodedString.FromLiteralString(client.Credentials.MerchantV3Secret));
|
2022-11-13 23:17:18 +08:00
|
|
|
|
byte[] keyBytes = new byte[16];
|
|
|
|
|
|
Array.Copy(secretBytes, keyBytes, keyBytes.Length);
|
|
|
|
|
|
|
|
|
|
|
|
byte[] plainBytes = Utilities.SM4Utility.DecryptWithGCM(
|
|
|
|
|
|
keyBytes: keyBytes,
|
2024-02-05 10:53:59 +08:00
|
|
|
|
nonceBytes: EncodedString.FromLiteralString(webhookEventResource.Nonce),
|
|
|
|
|
|
associatedDataBytes: EncodedString.FromLiteralString(webhookEventResource.AssociatedData),
|
|
|
|
|
|
cipherBytes: EncodedString.FromBase64String(webhookEventResource.CipherText)
|
2022-11-13 23:17:18 +08:00
|
|
|
|
);
|
2024-02-05 10:53:59 +08:00
|
|
|
|
plainJson = EncodedString.ToLiteralString(plainBytes).Value!;
|
2022-11-13 23:17:18 +08:00
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
2024-01-29 23:12:37 +08:00
|
|
|
|
throw new WechatTenpayException("Failed to decrypt event resource data. Please see the inner exception for more details.", ex);
|
2022-11-13 23:17:18 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
{
|
2024-01-29 23:12:37 +08:00
|
|
|
|
throw new WechatTenpayException($"Failed to decrypt event resource data. Unsupported encryption algorithm: \"{webhookEventResource.Algorithm}\".");
|
2022-11-13 23:17:18 +08:00
|
|
|
|
}
|
2021-05-10 15:30:00 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-07-27 00:50:03 +08:00
|
|
|
|
return client.JsonSerializer.Deserialize<T>(plainJson);
|
2021-05-10 15:30:00 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|