diff --git a/src/SKIT.FlurlHttpClient.Wechat.Api/Extensions/WechatApiClientEventExtensions.cs b/src/SKIT.FlurlHttpClient.Wechat.Api/Extensions/WechatApiClientEventExtensions.cs index d3b2de87..59a34499 100644 --- a/src/SKIT.FlurlHttpClient.Wechat.Api/Extensions/WechatApiClientEventExtensions.cs +++ b/src/SKIT.FlurlHttpClient.Wechat.Api/Extensions/WechatApiClientEventExtensions.cs @@ -1,6 +1,14 @@ using System; using System.Collections.Generic; 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 { @@ -29,7 +37,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Api public string Signature { get; set; } = default!; } - private static TEvent InnerDeserializeEventFromJson(this WechatApiClient client, string callbackJson) + private static TEvent InnerDeserializeEventFromJson(WechatApiClient client, string callbackJson) where TEvent : WechatApiEvent { if (client == null) throw new ArgumentNullException(nameof(client)); @@ -40,7 +48,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Api if (callbackJson.Contains("\"Encrypt\"")) { InnerEncryptedEvent encryptedEvent = client.JsonSerializer.Deserialize(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(callbackJson); @@ -55,7 +63,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Api } } - private static TEvent InnerDeserializeEventFromXml(this WechatApiClient client, string callbackXml) + private static TEvent InnerDeserializeEventFromXml(WechatApiClient client, string callbackXml) where TEvent : WechatApiEvent { if (client == null) throw new ArgumentNullException(nameof(client)); @@ -67,7 +75,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Api { XDocument xDocument = XDocument.Parse(callbackXml); 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(callbackXml); @@ -163,12 +171,12 @@ namespace SKIT.FlurlHttpClient.Wechat.Api { string timestamp = DateTimeOffset.Now.ToLocalTime().ToUnixTimeSeconds().ToString(); string nonce = DateTimeOffset.Now.Ticks.ToString("x"); - string cipher = Utilities.WxBizMsgCryptor.AESEncrypt( + string cipher = Utilities.WechatEventMessageCryptor.AESEncrypt( plainText: json, encodingAESKey: client.Credentials.PushEncodingAESKey!, appId: client.Credentials.AppId ); - string sign = Utilities.WxBizMsgCryptor.GenerateSignature( + string sign = Utilities.WechatEventMessageCryptor.GenerateSignature( sToken: client.Credentials.PushToken!, sTimestamp: timestamp, sNonce: nonce, @@ -223,13 +231,13 @@ namespace SKIT.FlurlHttpClient.Wechat.Api try { - string cipher = Utilities.WxBizMsgCryptor.AESEncrypt( + string cipher = Utilities.WechatEventMessageCryptor.AESEncrypt( plainText: xml, encodingAESKey: client.Credentials.PushEncodingAESKey!, 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) { @@ -279,7 +287,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Api try { var encryptedEvent = client.JsonSerializer.Deserialize(callbackJson); - return Utilities.WxBizMsgCryptor.VerifySignature( + return Utilities.WechatEventMessageCryptor.VerifySignature( sToken: client.Credentials.PushToken!, sTimestamp: callbackTimestamp, sNonce: callbackNonce, @@ -313,7 +321,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Api XDocument xDoc = XDocument.Parse(callbackXml); string? msgEncrypt = xDoc.Root?.Element("Encrypt")?.Value; - return Utilities.WxBizMsgCryptor.VerifySignature( + return Utilities.WechatEventMessageCryptor.VerifySignature( sToken: client.Credentials.PushToken!, sTimestamp: callbackTimestamp, sNonce: callbackNonce, diff --git a/src/SKIT.FlurlHttpClient.Wechat.Api/Properties/AssemblyInfo.cs b/src/SKIT.FlurlHttpClient.Wechat.Api/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..f1b016bc --- /dev/null +++ b/src/SKIT.FlurlHttpClient.Wechat.Api/Properties/AssemblyInfo.cs @@ -0,0 +1,3 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("SKIT.FlurlHttpClient.Wechat.Api.UnitTests")] diff --git a/src/SKIT.FlurlHttpClient.Wechat.Api/Utilities/WxBizMsgCryptor.cs b/src/SKIT.FlurlHttpClient.Wechat.Api/Utilities/Internal/WechatEventMessageCryptor.cs similarity index 96% rename from src/SKIT.FlurlHttpClient.Wechat.Api/Utilities/WxBizMsgCryptor.cs rename to src/SKIT.FlurlHttpClient.Wechat.Api/Utilities/Internal/WechatEventMessageCryptor.cs index 1f28a837..d1c8ae03 100644 --- a/src/SKIT.FlurlHttpClient.Wechat.Api/Utilities/WxBizMsgCryptor.cs +++ b/src/SKIT.FlurlHttpClient.Wechat.Api/Utilities/Internal/WechatEventMessageCryptor.cs @@ -10,7 +10,7 @@ using System.Xml; 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_BLOCK_SIZE = 128; @@ -74,15 +74,15 @@ namespace SKIT.FlurlHttpClient.Wechat.Api.Utilities 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 (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(); - aes.KeySize = 256; - aes.BlockSize = 128; + aes.KeySize = AES_KEY_SIZE; + aes.BlockSize = AES_BLOCK_SIZE; aes.Mode = CipherMode.CBC; //aes.Padding = PaddingMode.PKCS7; aes.Padding = PaddingMode.None; @@ -93,9 +93,9 @@ namespace SKIT.FlurlHttpClient.Wechat.Api.Utilities using (var ms = new MemoryStream()) using (var cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Write)) { - byte[] bMsg = new byte[ciperBytes.Length + 32 - ciperBytes.Length % 32]; - Array.Copy(ciperBytes, bMsg, ciperBytes.Length); - cs.Write(ciperBytes, 0, ciperBytes.Length); + byte[] msgBytes = new byte[cipherBytes.Length + 32 - cipherBytes.Length % 32]; + Array.Copy(cipherBytes, msgBytes, cipherBytes.Length); + cs.Write(cipherBytes, 0, cipherBytes.Length); byte[] plainBytes = Decode2(ms.ToArray()); return plainBytes; @@ -148,7 +148,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Api.Utilities byte[] keyBytes = Convert.FromBase64String(encodingAESKey + "="); byte[] ivBytes = new byte[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); len = IPAddress.NetworkToHostOrder(len); diff --git a/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/TestCase_WxBizMsgCryptorUtilityTests.cs b/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/TestCase_WechatEventMessageCryptorTests.cs similarity index 83% rename from test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/TestCase_WxBizMsgCryptorUtilityTests.cs rename to test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/TestCase_WechatEventMessageCryptorTests.cs index 7cb7e7fe..36124e9f 100644 --- a/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/TestCase_WxBizMsgCryptorUtilityTests.cs +++ b/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/TestCase_WechatEventMessageCryptorTests.cs @@ -2,7 +2,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Api.UnitTests { - public class TestCase_WxBizMsgCryptorUtilityTests + public class TestCase_WechatEventMessageCryptorTests { [Fact(DisplayName = "试用例:验签并解密回调数据")] public void TestVerifyAndDecryptEvent() @@ -15,12 +15,12 @@ namespace SKIT.FlurlHttpClient.Wechat.Api.UnitTests string reqNonce = "1372623149"; 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 = "\n\n1409659813\n\n\n4561255354251345929\n218\n"; Assert.Equal(expectedPlain, actualPlain); 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 = "试用例:验签回调数据")] @@ -32,7 +32,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Api.UnitTests 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=="; - Assert.True(Utilities.WxBizMsgCryptor.VerifySignature(token, reqTimeStamp, reqNonce, reqCipherText, reqMsgSig)); + Assert.True(Utilities.WechatEventMessageCryptor.VerifySignature(token, reqTimeStamp, reqNonce, reqCipherText, reqMsgSig)); } } }