feat(wxapi): 移除 WxBizMsgCryptor 工具类

This commit is contained in:
Fu Diwei 2022-02-28 21:29:31 +08:00
parent 23d9d247ef
commit 62b871023c
4 changed files with 34 additions and 23 deletions

View File

@ -1,6 +1,14 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Xml.Linq; using System.Xml.Linq;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Security;
using System.Security.Cryptography;
using System.Text;
using System.Xml;
namespace SKIT.FlurlHttpClient.Wechat.Api namespace SKIT.FlurlHttpClient.Wechat.Api
{ {
@ -29,7 +37,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Api
public string Signature { get; set; } = default!; public string Signature { get; set; } = default!;
} }
private static TEvent InnerDeserializeEventFromJson<TEvent>(this WechatApiClient client, string callbackJson) private static TEvent InnerDeserializeEventFromJson<TEvent>(WechatApiClient client, string callbackJson)
where TEvent : WechatApiEvent where TEvent : WechatApiEvent
{ {
if (client == null) throw new ArgumentNullException(nameof(client)); if (client == null) throw new ArgumentNullException(nameof(client));
@ -40,7 +48,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Api
if (callbackJson.Contains("\"Encrypt\"")) if (callbackJson.Contains("\"Encrypt\""))
{ {
InnerEncryptedEvent encryptedEvent = client.JsonSerializer.Deserialize<InnerEncryptedEvent>(callbackJson); InnerEncryptedEvent encryptedEvent = client.JsonSerializer.Deserialize<InnerEncryptedEvent>(callbackJson);
callbackJson = Utilities.WxBizMsgCryptor.AESDecrypt(cipherText: encryptedEvent.EncryptedData, encodingAESKey: client.Credentials.PushEncodingAESKey!, out _); callbackJson = Utilities.WechatEventMessageCryptor.AESDecrypt(cipherText: encryptedEvent.EncryptedData, encodingAESKey: client.Credentials.PushEncodingAESKey!, out _);
} }
return client.JsonSerializer.Deserialize<TEvent>(callbackJson); return client.JsonSerializer.Deserialize<TEvent>(callbackJson);
@ -55,7 +63,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Api
} }
} }
private static TEvent InnerDeserializeEventFromXml<TEvent>(this WechatApiClient client, string callbackXml) private static TEvent InnerDeserializeEventFromXml<TEvent>(WechatApiClient client, string callbackXml)
where TEvent : WechatApiEvent where TEvent : WechatApiEvent
{ {
if (client == null) throw new ArgumentNullException(nameof(client)); if (client == null) throw new ArgumentNullException(nameof(client));
@ -67,7 +75,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Api
{ {
XDocument xDocument = XDocument.Parse(callbackXml); XDocument xDocument = XDocument.Parse(callbackXml);
string encryptedData = xDocument.Root.Element("Encrypt").Value; string encryptedData = xDocument.Root.Element("Encrypt").Value;
callbackXml = Utilities.WxBizMsgCryptor.AESDecrypt(cipherText: encryptedData, encodingAESKey: client.Credentials.PushEncodingAESKey!, out _); callbackXml = Utilities.WechatEventMessageCryptor.AESDecrypt(cipherText: encryptedData, encodingAESKey: client.Credentials.PushEncodingAESKey!, out _);
} }
return Utilities.XmlUtility.Deserialize<TEvent>(callbackXml); return Utilities.XmlUtility.Deserialize<TEvent>(callbackXml);
@ -163,12 +171,12 @@ namespace SKIT.FlurlHttpClient.Wechat.Api
{ {
string timestamp = DateTimeOffset.Now.ToLocalTime().ToUnixTimeSeconds().ToString(); string timestamp = DateTimeOffset.Now.ToLocalTime().ToUnixTimeSeconds().ToString();
string nonce = DateTimeOffset.Now.Ticks.ToString("x"); string nonce = DateTimeOffset.Now.Ticks.ToString("x");
string cipher = Utilities.WxBizMsgCryptor.AESEncrypt( string cipher = Utilities.WechatEventMessageCryptor.AESEncrypt(
plainText: json, plainText: json,
encodingAESKey: client.Credentials.PushEncodingAESKey!, encodingAESKey: client.Credentials.PushEncodingAESKey!,
appId: client.Credentials.AppId appId: client.Credentials.AppId
); );
string sign = Utilities.WxBizMsgCryptor.GenerateSignature( string sign = Utilities.WechatEventMessageCryptor.GenerateSignature(
sToken: client.Credentials.PushToken!, sToken: client.Credentials.PushToken!,
sTimestamp: timestamp, sTimestamp: timestamp,
sNonce: nonce, sNonce: nonce,
@ -223,13 +231,13 @@ namespace SKIT.FlurlHttpClient.Wechat.Api
try try
{ {
string cipher = Utilities.WxBizMsgCryptor.AESEncrypt( string cipher = Utilities.WechatEventMessageCryptor.AESEncrypt(
plainText: xml, plainText: xml,
encodingAESKey: client.Credentials.PushEncodingAESKey!, encodingAESKey: client.Credentials.PushEncodingAESKey!,
appId: client.Credentials.AppId appId: client.Credentials.AppId
); );
xml = Utilities.WxBizMsgCryptor.WrapXml(sToken: client.Credentials.PushToken!, sMsgEncrypt: cipher); xml = Utilities.WechatEventMessageCryptor.WrapXml(sToken: client.Credentials.PushToken!, sMsgEncrypt: cipher);
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -279,7 +287,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Api
try try
{ {
var encryptedEvent = client.JsonSerializer.Deserialize<InnerEncryptedEvent>(callbackJson); var encryptedEvent = client.JsonSerializer.Deserialize<InnerEncryptedEvent>(callbackJson);
return Utilities.WxBizMsgCryptor.VerifySignature( return Utilities.WechatEventMessageCryptor.VerifySignature(
sToken: client.Credentials.PushToken!, sToken: client.Credentials.PushToken!,
sTimestamp: callbackTimestamp, sTimestamp: callbackTimestamp,
sNonce: callbackNonce, sNonce: callbackNonce,
@ -313,7 +321,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Api
XDocument xDoc = XDocument.Parse(callbackXml); XDocument xDoc = XDocument.Parse(callbackXml);
string? msgEncrypt = xDoc.Root?.Element("Encrypt")?.Value; string? msgEncrypt = xDoc.Root?.Element("Encrypt")?.Value;
return Utilities.WxBizMsgCryptor.VerifySignature( return Utilities.WechatEventMessageCryptor.VerifySignature(
sToken: client.Credentials.PushToken!, sToken: client.Credentials.PushToken!,
sTimestamp: callbackTimestamp, sTimestamp: callbackTimestamp,
sNonce: callbackNonce, sNonce: callbackNonce,

View File

@ -0,0 +1,3 @@
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("SKIT.FlurlHttpClient.Wechat.Api.UnitTests")]

View File

@ -10,7 +10,7 @@ using System.Xml;
namespace SKIT.FlurlHttpClient.Wechat.Api.Utilities namespace SKIT.FlurlHttpClient.Wechat.Api.Utilities
{ {
public static class WxBizMsgCryptor internal static class WechatEventMessageCryptor
{ {
private const int AES_KEY_SIZE = 256; private const int AES_KEY_SIZE = 256;
private const int AES_BLOCK_SIZE = 128; private const int AES_BLOCK_SIZE = 128;
@ -74,15 +74,15 @@ namespace SKIT.FlurlHttpClient.Wechat.Api.Utilities
return res; return res;
} }
private static byte[] AESDecrypt(byte[] keyBytes, byte[] ivBytes, byte[] ciperBytes) private static byte[] AESDecrypt(byte[] keyBytes, byte[] ivBytes, byte[] cipherBytes)
{ {
if (keyBytes == null) throw new ArgumentNullException(nameof(keyBytes)); if (keyBytes == null) throw new ArgumentNullException(nameof(keyBytes));
if (ivBytes == null) throw new ArgumentNullException(nameof(ivBytes)); if (ivBytes == null) throw new ArgumentNullException(nameof(ivBytes));
if (ciperBytes == null) throw new ArgumentNullException(nameof(ciperBytes)); if (cipherBytes == null) throw new ArgumentNullException(nameof(cipherBytes));
using var aes = Aes.Create(); using var aes = Aes.Create();
aes.KeySize = 256; aes.KeySize = AES_KEY_SIZE;
aes.BlockSize = 128; aes.BlockSize = AES_BLOCK_SIZE;
aes.Mode = CipherMode.CBC; aes.Mode = CipherMode.CBC;
//aes.Padding = PaddingMode.PKCS7; //aes.Padding = PaddingMode.PKCS7;
aes.Padding = PaddingMode.None; aes.Padding = PaddingMode.None;
@ -93,9 +93,9 @@ namespace SKIT.FlurlHttpClient.Wechat.Api.Utilities
using (var ms = new MemoryStream()) using (var ms = new MemoryStream())
using (var cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Write)) using (var cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Write))
{ {
byte[] bMsg = new byte[ciperBytes.Length + 32 - ciperBytes.Length % 32]; byte[] msgBytes = new byte[cipherBytes.Length + 32 - cipherBytes.Length % 32];
Array.Copy(ciperBytes, bMsg, ciperBytes.Length); Array.Copy(cipherBytes, msgBytes, cipherBytes.Length);
cs.Write(ciperBytes, 0, ciperBytes.Length); cs.Write(cipherBytes, 0, cipherBytes.Length);
byte[] plainBytes = Decode2(ms.ToArray()); byte[] plainBytes = Decode2(ms.ToArray());
return plainBytes; return plainBytes;
@ -148,7 +148,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Api.Utilities
byte[] keyBytes = Convert.FromBase64String(encodingAESKey + "="); byte[] keyBytes = Convert.FromBase64String(encodingAESKey + "=");
byte[] ivBytes = new byte[16]; byte[] ivBytes = new byte[16];
Array.Copy(keyBytes, ivBytes, 16); Array.Copy(keyBytes, ivBytes, 16);
byte[] btmpMsg = AESDecrypt(ciperBytes: cipherBytes, ivBytes: ivBytes, keyBytes: keyBytes); byte[] btmpMsg = AESDecrypt(cipherBytes: cipherBytes, ivBytes: ivBytes, keyBytes: keyBytes);
int len = BitConverter.ToInt32(btmpMsg, 16); int len = BitConverter.ToInt32(btmpMsg, 16);
len = IPAddress.NetworkToHostOrder(len); len = IPAddress.NetworkToHostOrder(len);

View File

@ -2,7 +2,7 @@
namespace SKIT.FlurlHttpClient.Wechat.Api.UnitTests namespace SKIT.FlurlHttpClient.Wechat.Api.UnitTests
{ {
public class TestCase_WxBizMsgCryptorUtilityTests public class TestCase_WechatEventMessageCryptorTests
{ {
[Fact(DisplayName = "试用例:验签并解密回调数据")] [Fact(DisplayName = "试用例:验签并解密回调数据")]
public void TestVerifyAndDecryptEvent() public void TestVerifyAndDecryptEvent()
@ -15,12 +15,12 @@ namespace SKIT.FlurlHttpClient.Wechat.Api.UnitTests
string reqNonce = "1372623149"; string reqNonce = "1372623149";
string reqCipherText = "RypEvHKD8QQKFhvQ6QleEB4J58tiPdvo+rtK1I9qca6aM/wvqnLSV5zEPeusUiX5L5X/0lWfrf0QADHHhGd3QczcdCUpj911L3vg3W/sYYvuJTs3TUUkSUXxaccAS0qhxchrRYt66wiSpGLYL42aM6A8dTT+6k4aSknmPj48kzJs8qLjvd4Xgpue06DOdnLxAUHzM6+kDZ+HMZfJYuR+LtwGc2hgf5gsijff0ekUNXZiqATP7PF5mZxZ3Izoun1s4zG4LUMnvw2r+KqCKIw+3IQH03v+BCA9nMELNqbSf6tiWSrXJB3LAVGUcallcrw8V2t9EL4EhzJWrQUax5wLVMNS0+rUPA3k22Ncx4XXZS9o0MBH27Bo6BpNelZpS+/uh9KsNlY6bHCmJU9p8g7m3fVKn28H3KDYA5Pl/T8Z1ptDAVe0lXdQ2YoyyH2uyPIGHBZZIs2pDBS8R07+qN+E7Q=="; string reqCipherText = "RypEvHKD8QQKFhvQ6QleEB4J58tiPdvo+rtK1I9qca6aM/wvqnLSV5zEPeusUiX5L5X/0lWfrf0QADHHhGd3QczcdCUpj911L3vg3W/sYYvuJTs3TUUkSUXxaccAS0qhxchrRYt66wiSpGLYL42aM6A8dTT+6k4aSknmPj48kzJs8qLjvd4Xgpue06DOdnLxAUHzM6+kDZ+HMZfJYuR+LtwGc2hgf5gsijff0ekUNXZiqATP7PF5mZxZ3Izoun1s4zG4LUMnvw2r+KqCKIw+3IQH03v+BCA9nMELNqbSf6tiWSrXJB3LAVGUcallcrw8V2t9EL4EhzJWrQUax5wLVMNS0+rUPA3k22Ncx4XXZS9o0MBH27Bo6BpNelZpS+/uh9KsNlY6bHCmJU9p8g7m3fVKn28H3KDYA5Pl/T8Z1ptDAVe0lXdQ2YoyyH2uyPIGHBZZIs2pDBS8R07+qN+E7Q==";
string actualPlain = Utilities.WxBizMsgCryptor.AESDecrypt(reqCipherText, aesKey, out string actualAppId); string actualPlain = Utilities.WechatEventMessageCryptor.AESDecrypt(reqCipherText, aesKey, out string actualAppId);
string expectedPlain = "<xml><ToUserName><![CDATA[wx5823bf96d3bd56c7]]></ToUserName>\n<FromUserName><![CDATA[mycreate]]></FromUserName>\n<CreateTime>1409659813</CreateTime>\n<MsgType><![CDATA[text]]></MsgType>\n<Content><![CDATA[hello]]></Content>\n<MsgId>4561255354251345929</MsgId>\n<AgentID>218</AgentID>\n</xml>"; string expectedPlain = "<xml><ToUserName><![CDATA[wx5823bf96d3bd56c7]]></ToUserName>\n<FromUserName><![CDATA[mycreate]]></FromUserName>\n<CreateTime>1409659813</CreateTime>\n<MsgType><![CDATA[text]]></MsgType>\n<Content><![CDATA[hello]]></Content>\n<MsgId>4561255354251345929</MsgId>\n<AgentID>218</AgentID>\n</xml>";
Assert.Equal(expectedPlain, actualPlain); Assert.Equal(expectedPlain, actualPlain);
Assert.Equal(appId, actualAppId); Assert.Equal(appId, actualAppId);
Assert.True(Utilities.WxBizMsgCryptor.VerifySignature(token, reqTimeStamp, reqNonce, reqCipherText, reqMsgSig)); Assert.True(Utilities.WechatEventMessageCryptor.VerifySignature(token, reqTimeStamp, reqNonce, reqCipherText, reqMsgSig));
} }
[Fact(DisplayName = "试用例:验签回调数据")] [Fact(DisplayName = "试用例:验签回调数据")]
@ -32,7 +32,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Api.UnitTests
string reqNonce = "1811081856"; string reqNonce = "1811081856";
string reqCipherText = "Q/jUxIL3/jRaFeTKesIr1QSq2SOEApDqlzcRrRM6Jlk4EbMBns3plPOR/W3gThOEq+zYI42fNSoIUb3cQwt9zyD1aLU/7D3WNLute7LQ9LSHjZEfVmx5zcIR9zvrUWGjhe1whTPH4e1WR6vbOYs8o/bDRF0vX/NcE4XK7P83Y6CzQiJoKbjVCne84s0zcw5eh+ZUDB55eaDHPSoS7kAC8kB00pfBoDF0jyfc8CUKLW97e72vJGyUWjZ0BvYN+R+tFjMgEzg/EN1imuuFnf40DMAcvB6y+C97TuaWjpgfRdowGWzn10JAFNukRfQqjdA0e2bfczJ7+t9w/t8/XSMADJOt1xbnP+I5cRX/r7ueBGmG/6ejP3myO9yTXHdujGvwrXHuWw+J7qD4VoUVjbm2vQ1qQKbrweKssr6O+3XSbanZ5R3n26EpN/gfgX+r6rcGViqsFop9Ai9xMnfJUubB6Q=="; string reqCipherText = "Q/jUxIL3/jRaFeTKesIr1QSq2SOEApDqlzcRrRM6Jlk4EbMBns3plPOR/W3gThOEq+zYI42fNSoIUb3cQwt9zyD1aLU/7D3WNLute7LQ9LSHjZEfVmx5zcIR9zvrUWGjhe1whTPH4e1WR6vbOYs8o/bDRF0vX/NcE4XK7P83Y6CzQiJoKbjVCne84s0zcw5eh+ZUDB55eaDHPSoS7kAC8kB00pfBoDF0jyfc8CUKLW97e72vJGyUWjZ0BvYN+R+tFjMgEzg/EN1imuuFnf40DMAcvB6y+C97TuaWjpgfRdowGWzn10JAFNukRfQqjdA0e2bfczJ7+t9w/t8/XSMADJOt1xbnP+I5cRX/r7ueBGmG/6ejP3myO9yTXHdujGvwrXHuWw+J7qD4VoUVjbm2vQ1qQKbrweKssr6O+3XSbanZ5R3n26EpN/gfgX+r6rcGViqsFop9Ai9xMnfJUubB6Q==";
Assert.True(Utilities.WxBizMsgCryptor.VerifySignature(token, reqTimeStamp, reqNonce, reqCipherText, reqMsgSig)); Assert.True(Utilities.WechatEventMessageCryptor.VerifySignature(token, reqTimeStamp, reqNonce, reqCipherText, reqMsgSig));
} }
} }
} }