From a11df544e5072af775500bb0d6eba8f9a97d0355 Mon Sep 17 00:00:00 2001 From: Fu Diwei Date: Sun, 4 Feb 2024 22:53:47 +0800 Subject: [PATCH] =?UTF-8?q?refactor(work):=20=E4=BC=98=E5=8C=96=E5=8A=A0?= =?UTF-8?q?=E8=A7=A3=E5=AF=86=E5=8F=8A=E5=93=88=E5=B8=8C=E7=AE=97=E6=B3=95?= =?UTF-8?q?=E5=B7=A5=E5=85=B7=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Finance/WechatWorkFinanceClient.cs | 7 ++- .../WechatWorkClientParameterExtensions.cs | 4 +- .../Utilities/AESUtility.cs | 51 ++++++++-------- .../Utilities/RSAUtility.cs | 58 +++++++++---------- .../Utilities/SHA1Utility.cs | 29 ++++++---- .../Utilities/__Internal/WxMsgCryptor.cs | 2 +- .../TestCase_ToolsAESUtilityTests.cs | 6 +- .../TestCase_ToolsRSAUtilityTests.cs | 4 +- 8 files changed, 86 insertions(+), 75 deletions(-) diff --git a/src/SKIT.FlurlHttpClient.Wechat.Work/ExtendedSDK/Finance/WechatWorkFinanceClient.cs b/src/SKIT.FlurlHttpClient.Wechat.Work/ExtendedSDK/Finance/WechatWorkFinanceClient.cs index 24b15b40..e31c58d7 100644 --- a/src/SKIT.FlurlHttpClient.Wechat.Work/ExtendedSDK/Finance/WechatWorkFinanceClient.cs +++ b/src/SKIT.FlurlHttpClient.Wechat.Work/ExtendedSDK/Finance/WechatWorkFinanceClient.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; namespace SKIT.FlurlHttpClient.Wechat.Work.ExtendedSDK.Finance { + using SKIT.FlurlHttpClient.Primitives; using SKIT.FlurlHttpClient.Wechat.Work.ExtendedSDK.Finance.InteropServices; /// @@ -200,9 +201,9 @@ namespace SKIT.FlurlHttpClient.Wechat.Work.ExtendedSDK.Finance throw new WechatWorkFinanceException($"Failed to decrypt random key of the encrypted chat data, because there is no private key matched the verion: \"{request.PublicKeyVersion}\"."); encryptKey = Utilities.RSAUtility.DecryptWithECB( - privateKey: encryptionKeyEntry.Value.PrivateKey, - cipherText: request.EncryptedRandomKey - ); + privateKeyPem: encryptionKeyEntry.Value.PrivateKey, + encodingCipher: new EncodedString(request.EncryptedRandomKey, EncodingKinds.Base64) + )!; } catch (WechatWorkFinanceException) { diff --git a/src/SKIT.FlurlHttpClient.Wechat.Work/Extensions/WechatWorkClientParameterExtensions.cs b/src/SKIT.FlurlHttpClient.Wechat.Work/Extensions/WechatWorkClientParameterExtensions.cs index 0d2341ab..4ceb7980 100644 --- a/src/SKIT.FlurlHttpClient.Wechat.Work/Extensions/WechatWorkClientParameterExtensions.cs +++ b/src/SKIT.FlurlHttpClient.Wechat.Work/Extensions/WechatWorkClientParameterExtensions.cs @@ -29,7 +29,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Work string timestamp = DateTimeOffset.Now.ToLocalTime().ToUnixTimeSeconds().ToString(); string nonce = Guid.NewGuid().ToString("N"); - string sign = Utilities.SHA1Utility.Hash($"jsapi_ticket={jsapiTicket}&noncestr={nonce}×tamp={timestamp}&url={url.Split('#')[0]}").ToLower(); + string sign = Utilities.SHA1Utility.Hash($"jsapi_ticket={jsapiTicket}&noncestr={nonce}×tamp={timestamp}&url={url.Split('#')[0]}").Value!.ToLower(); return new ReadOnlyDictionary(new Dictionary() { @@ -58,7 +58,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Work string timestamp = DateTimeOffset.Now.ToLocalTime().ToUnixTimeSeconds().ToString(); string nonce = Guid.NewGuid().ToString("N"); - string sign = Utilities.SHA1Utility.Hash($"jsapi_ticket={jsapiTicket}&noncestr={nonce}×tamp={timestamp}&url={url.Split('#')[0]}").ToLower(); + string sign = Utilities.SHA1Utility.Hash($"jsapi_ticket={jsapiTicket}&noncestr={nonce}×tamp={timestamp}&url={url.Split('#')[0]}").Value!.ToLower(); return new ReadOnlyDictionary(new Dictionary() { diff --git a/src/SKIT.FlurlHttpClient.Wechat.Work/Utilities/AESUtility.cs b/src/SKIT.FlurlHttpClient.Wechat.Work/Utilities/AESUtility.cs index e52194c1..d5950433 100644 --- a/src/SKIT.FlurlHttpClient.Wechat.Work/Utilities/AESUtility.cs +++ b/src/SKIT.FlurlHttpClient.Wechat.Work/Utilities/AESUtility.cs @@ -1,29 +1,32 @@ using System; -using System.Text; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Security; namespace SKIT.FlurlHttpClient.Wechat.Work.Utilities { + using SKIT.FlurlHttpClient.Primitives; + /// /// AES 算法工具类。 /// public static class AESUtility { - private const string AES_CIPHER_ALGORITHM_GCM = "AES/GCM"; - private const string AES_CIPHER_PADDING_NOPADDING = "NoPadding"; + /// + /// 填充模式:NoPadding。 + /// + public const string PADDING_MODE_NOPADDING = "NoPadding"; /// /// 基于 GCM 模式解密数据。 /// /// AES 密钥字节数组。 - /// 加密使用的初始化向量字节数组。 - /// 加密使用的附加数据包字节数组。 + /// 初始化向量字节数组。 + /// 附加数据字节数组。 /// 待解密数据字节数组。 - /// 填充模式。(默认值:) + /// 填充模式。(默认值:) /// 解密后的数据字节数组。 - public static byte[] DecryptWithGCM(byte[] keyBytes, byte[] nonceBytes, byte[]? aadBytes, byte[] cipherBytes, string paddingMode = AES_CIPHER_PADDING_NOPADDING) + public static byte[] DecryptWithGCM(byte[] keyBytes, byte[] nonceBytes, byte[]? associatedDataBytes, byte[] cipherBytes, string paddingMode = PADDING_MODE_NOPADDING) { const int KEY_LENGTH_BYTE = 32; const int NONCE_LENGTH_BYTE = 12; @@ -36,12 +39,12 @@ namespace SKIT.FlurlHttpClient.Wechat.Work.Utilities if (cipherBytes is null) throw new ArgumentNullException(nameof(cipherBytes)); if (cipherBytes.Length < TAG_LENGTH_BYTE) throw new ArgumentException($"Invalid cipher byte length (expected: more than {TAG_LENGTH_BYTE}, actual: {cipherBytes.Length}).", nameof(cipherBytes)); - IBufferedCipher cipher = CipherUtilities.GetCipher(string.Format("{0}/{1}", AES_CIPHER_ALGORITHM_GCM, paddingMode)); + IBufferedCipher cipher = CipherUtilities.GetCipher($"AES/GCM/{paddingMode}"); ICipherParameters cipherParams = new AeadParameters( new KeyParameter(keyBytes), TAG_LENGTH_BYTE * 8, nonceBytes, - aadBytes + associatedDataBytes ); cipher.Init(false, cipherParams); byte[] plainBytes = new byte[cipher.GetOutputSize(cipherBytes.Length)]; @@ -53,26 +56,26 @@ namespace SKIT.FlurlHttpClient.Wechat.Work.Utilities /// /// 基于 GCM 模式解密数据。 /// - /// AES 密钥。 - /// 加密使用的初始化向量。 - /// 加密使用的附加数据包。 - /// 经 Base64 编码后的待解密数据。 - /// 填充模式。(默认值:) - /// 解密后的文本数据。 - public static string DecryptWithGCM(string key, string nonce, string? aad, string cipherText, string paddingMode = AES_CIPHER_PADDING_NOPADDING) + /// 经过编码后的(通常为 Base64)AES 密钥。 + /// 经过编码后的(通常为 Base64)初始化向量。 + /// 经过编码后的(通常为 Base64)附加数据。 + /// 经过编码后的(通常为 Base64)待解密数据。 + /// 填充模式。(默认值:) + /// 解密后的数据。 + public static EncodedString DecryptWithGCM(EncodedString encodingKey, EncodedString encodingNonce, EncodedString encodingAssociatedData, EncodedString encodingCipher, string paddingMode = PADDING_MODE_NOPADDING) { - if (key is null) throw new ArgumentNullException(nameof(key)); - if (nonce is null) throw new ArgumentNullException(nameof(nonce)); - if (cipherText is null) throw new ArgumentNullException(nameof(cipherText)); + if (encodingKey.Value is null) throw new ArgumentNullException(nameof(encodingKey)); + if (encodingNonce.Value is null) throw new ArgumentNullException(nameof(encodingNonce)); + if (encodingCipher.Value is null) throw new ArgumentNullException(nameof(encodingCipher)); byte[] plainBytes = DecryptWithGCM( - keyBytes: Encoding.UTF8.GetBytes(key), - nonceBytes: Encoding.UTF8.GetBytes(nonce), - aadBytes: aad is not null ? Encoding.UTF8.GetBytes(aad) : null, - cipherBytes: Convert.FromBase64String(cipherText), + keyBytes: EncodedString.FromString(encodingKey, fallbackEncodingKind: EncodingKinds.Base64), + nonceBytes: EncodedString.FromString(encodingNonce, fallbackEncodingKind: EncodingKinds.Base64), + associatedDataBytes: encodingAssociatedData.Value is not null ? EncodedString.FromString(encodingAssociatedData, fallbackEncodingKind: EncodingKinds.Base64) : null, + cipherBytes: EncodedString.FromString(encodingCipher, fallbackEncodingKind: EncodingKinds.Base64), paddingMode: paddingMode ); - return Encoding.UTF8.GetString(plainBytes); + return EncodedString.ToLiteralString(plainBytes); } } } diff --git a/src/SKIT.FlurlHttpClient.Wechat.Work/Utilities/RSAUtility.cs b/src/SKIT.FlurlHttpClient.Wechat.Work/Utilities/RSAUtility.cs index 1438fc8d..ea358942 100644 --- a/src/SKIT.FlurlHttpClient.Wechat.Work/Utilities/RSAUtility.cs +++ b/src/SKIT.FlurlHttpClient.Wechat.Work/Utilities/RSAUtility.cs @@ -1,6 +1,5 @@ using System; using System.IO; -using System.Text; using System.Text.RegularExpressions; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Parameters; @@ -9,17 +8,21 @@ using Org.BouncyCastle.Security; namespace SKIT.FlurlHttpClient.Wechat.Work.Utilities { + using SKIT.FlurlHttpClient.Primitives; + /// /// RSA 算法工具类。 /// public static class RSAUtility { - private const string RSA_CIPHER_ALGORITHM_NONE = "RSA/ECB"; - private const string RSA_CIPHER_PADDING_PKCS1 = "PKCS1PADDING"; + /// + /// 填充模式:PKCS1Padding。 + /// + public const string PADDING_MODE_PKCS1 = "PKCS1PADDING"; - private static byte[] ConvertPrivateKeyPkcs1PemToByteArray(string privateKey) + private static byte[] ConvertPrivateKeyPemToByteArray(string privateKeyPem) { - using (TextReader textReader = new StringReader(privateKey)) + using (TextReader textReader = new StringReader(privateKeyPem)) using (PemReader pemReader = new PemReader(textReader)) { AsymmetricCipherKeyPair cipherKeyPair = (AsymmetricCipherKeyPair)pemReader.ReadObject(); @@ -30,24 +33,19 @@ namespace SKIT.FlurlHttpClient.Wechat.Work.Utilities pemWriter.WriteObject(pkcs8); pemWriter.Writer.Close(); - privateKey = textWriter.ToString()!; - privateKey = privateKey + privateKeyPem = textWriter.ToString()!; + privateKeyPem = privateKeyPem .Replace("-----BEGIN PRIVATE KEY-----", string.Empty) .Replace("-----END PRIVATE KEY-----", string.Empty); - privateKey = Regex.Replace(privateKey, "\\s+", string.Empty); - return Convert.FromBase64String(privateKey); + privateKeyPem = Regex.Replace(privateKeyPem, "\\s+", string.Empty); + return Convert.FromBase64String(privateKeyPem); } } } - private static RsaKeyParameters ParsePrivateKeyPemToPrivateKeyParameters(byte[] privateKeyBytes) - { - return (RsaKeyParameters)PrivateKeyFactory.CreateKey(privateKeyBytes); - } - private static byte[] DecryptWithECB(RsaKeyParameters rsaPrivateKeyParams, byte[] cipherBytes, string paddingMode) { - IBufferedCipher cipher = CipherUtilities.GetCipher($"{RSA_CIPHER_ALGORITHM_NONE}/{paddingMode}"); + IBufferedCipher cipher = CipherUtilities.GetCipher($"RSA/ECB/{paddingMode}"); cipher.Init(false, rsaPrivateKeyParams); return cipher.DoFinal(cipherBytes); } @@ -55,35 +53,35 @@ namespace SKIT.FlurlHttpClient.Wechat.Work.Utilities /// /// 使用私钥基于 ECB 模式解密数据。 /// - /// PKCS#1 私钥字节数据。 - /// 待解密的数据字节数据。 - /// 填充模式。(默认值:) + /// PKCS#1/PKCS#8 私钥字节数组。 + /// 待解密的数据字节数组。 + /// 填充模式。(默认值:) /// 解密后的数据字节数组。 - public static byte[] DecryptWithECB(byte[] privateKeyBytes, byte[] cipherBytes, string paddingMode = RSA_CIPHER_PADDING_PKCS1) + public static byte[] DecryptWithECB(byte[] privateKeyBytes, byte[] cipherBytes, string paddingMode = PADDING_MODE_PKCS1) { if (privateKeyBytes is null) throw new ArgumentNullException(nameof(privateKeyBytes)); if (cipherBytes is null) throw new ArgumentNullException(nameof(cipherBytes)); - RsaKeyParameters rsaPrivateKeyParams = ParsePrivateKeyPemToPrivateKeyParameters(privateKeyBytes); + RsaKeyParameters rsaPrivateKeyParams = (RsaKeyParameters)PrivateKeyFactory.CreateKey(privateKeyBytes); return DecryptWithECB(rsaPrivateKeyParams, cipherBytes, paddingMode); } /// /// 使用私钥基于 ECB 模式解密数据。 /// - /// PKCS#1 私钥(PEM 格式)。 - /// 经 Base64 编码的待解密数据。 - /// 填充模式。(默认值:) - /// 解密后的文本数据。 - public static string DecryptWithECB(string privateKey, string cipherText, string paddingMode = RSA_CIPHER_PADDING_PKCS1) + /// PKCS#1/PKCS#8 私钥(PEM 格式)。 + /// 经过编码后的(通常为 Base64)待解密数据。 + /// 填充模式。(默认值:) + /// 解密后的数据。 + public static EncodedString DecryptWithECB(string privateKeyPem, EncodedString encodingCipher, string paddingMode = PADDING_MODE_PKCS1) { - if (privateKey is null) throw new ArgumentNullException(nameof(privateKey)); - if (cipherText is null) throw new ArgumentNullException(nameof(cipherText)); + if (privateKeyPem is null) throw new ArgumentNullException(nameof(privateKeyPem)); + if (encodingCipher.Value is null) throw new ArgumentNullException(nameof(encodingCipher)); - byte[] privateKeyBytes = ConvertPrivateKeyPkcs1PemToByteArray(privateKey); - byte[] cipherBytes = Convert.FromBase64String(cipherText); + byte[] privateKeyBytes = ConvertPrivateKeyPemToByteArray(privateKeyPem); + byte[] cipherBytes = EncodedString.FromString(encodingCipher, fallbackEncodingKind: EncodingKinds.Base64); byte[] plainBytes = DecryptWithECB(privateKeyBytes, cipherBytes, paddingMode); - return Encoding.UTF8.GetString(plainBytes); + return EncodedString.ToLiteralString(plainBytes); } } } diff --git a/src/SKIT.FlurlHttpClient.Wechat.Work/Utilities/SHA1Utility.cs b/src/SKIT.FlurlHttpClient.Wechat.Work/Utilities/SHA1Utility.cs index 8c14e8ae..f0b71758 100644 --- a/src/SKIT.FlurlHttpClient.Wechat.Work/Utilities/SHA1Utility.cs +++ b/src/SKIT.FlurlHttpClient.Wechat.Work/Utilities/SHA1Utility.cs @@ -1,39 +1,44 @@ using System; using System.Security.Cryptography; -using System.Text; namespace SKIT.FlurlHttpClient.Wechat.Work.Utilities { + using SKIT.FlurlHttpClient.Primitives; + /// /// SHA-1 算法工具类。 /// public static class SHA1Utility { /// - /// 获取 SHA-1 信息摘要。 + /// 计算 SHA-1 哈希值。 /// - /// 信息字节数组。 - /// 信息摘要字节数组。 + /// 要计算哈希值的信息字节数组。 + /// 哈希值字节数组。 public static byte[] Hash(byte[] bytes) { if (bytes is null) throw new ArgumentNullException(nameof(bytes)); - using SHA1 sha = SHA1.Create(); - return sha.ComputeHash(bytes); +#if NET5_0_OR_GREATER + return SHA1.HashData(bytes); +#else + using SHA1 sha1 = SHA1.Create(); + return sha1.ComputeHash(bytes); +#endif } /// - /// 获取 SHA-1 信息摘要。 + /// 计算 SHA-1 哈希值。 /// - /// 文本信息。 - /// 信息摘要。 - public static string Hash(string message) + /// 要计算哈希值的信息。 + /// 经过十六进制编码的哈希值。 + public static EncodedString Hash(string message) { if (message is null) throw new ArgumentNullException(nameof(message)); - byte[] msgBytes = Encoding.UTF8.GetBytes(message); + byte[] msgBytes = EncodedString.FromLiteralString(message); byte[] hashBytes = Hash(msgBytes); - return BitConverter.ToString(hashBytes).Replace("-", string.Empty); + return EncodedString.ToHexString(hashBytes); } } } diff --git a/src/SKIT.FlurlHttpClient.Wechat.Work/Utilities/__Internal/WxMsgCryptor.cs b/src/SKIT.FlurlHttpClient.Wechat.Work/Utilities/__Internal/WxMsgCryptor.cs index 434c5f45..4991754e 100644 --- a/src/SKIT.FlurlHttpClient.Wechat.Work/Utilities/__Internal/WxMsgCryptor.cs +++ b/src/SKIT.FlurlHttpClient.Wechat.Work/Utilities/__Internal/WxMsgCryptor.cs @@ -233,7 +233,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Work.Utilities tmp.Sort(StringComparer.Ordinal); string rawText = string.Join(string.Empty, tmp); - string signText = SHA1Utility.Hash(rawText); + string signText = SHA1Utility.Hash(rawText).Value!; return signText.ToLower(); } diff --git a/test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/TestCase_ToolsAESUtilityTests.cs b/test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/TestCase_ToolsAESUtilityTests.cs index b0ca8ce8..404580b4 100644 --- a/test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/TestCase_ToolsAESUtilityTests.cs +++ b/test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/TestCase_ToolsAESUtilityTests.cs @@ -2,6 +2,8 @@ using Xunit; namespace SKIT.FlurlHttpClient.Wechat.Work.UnitTests { + using SKIT.FlurlHttpClient.Primitives; + public class TestCase_ToolsAESUtilityTests { [Fact(DisplayName = "测试用例:AES-GCM 解密")] @@ -9,10 +11,10 @@ namespace SKIT.FlurlHttpClient.Wechat.Work.UnitTests { string key = "f09b03a7a1902b5b4913856f1fd07ab1"; string nonce = "aae8c2e79c5b"; - string aad = "certificate"; + string associatedData = "certificate"; string cipherText = "x9kkL5w1JuaypcjhrYIP+kVNlN8o8uN4yJyJjy5lg+PyPnQL2Zn//ORaXAyzdaK/WBMVd3u/Y9hLaTBLMyRXzowsrkJ5PT37johye48N7BAJQ0PJwW++d1RdhOOPjoqfmws6rSV5Gv2qhfdKjmpxVjr8xr71dtBt8J2wu+bAV99HHQoAynm/Pp9OQYZgpOQ+1cyFHd43TAxOoFfmixKrXr3HP8lJot0XCUSq4qkr1Hs44FV2KuzntSk8eqKr5N17UcuPF3VYnnnF/AvQ7HuLKWwrHhUbaXfkwy0Q2n36UJMfBj7344S97E8BnS89ojgOPQi+olBPyNgrtDWHgsJAKu7HA6PV/FgmXcrZirje/AH1u25es4z5xItHscm//6rDvALgf7greV5OJzMsSl/KVDtbkjDSzim0j4ZTduIfzh7l6jfOz115ITcNILT9ef2KkcMyBBc89GZlMGeHTbgsBHzGeLawX3dXFjqt5aMnHM3VWCovA2aUM4c//rqkZGf+Va86OEFoJQLiSTFpkOrKxcIxcrbKPLTgiDWRT3wzmnUDg7kSPbluzt3ROvMFq9lB8bO/pBd7TD2w87sfUdKLj69FniX6s37SBeRVhw8GSIvBf5lpLUhqL5zKYlbuAWePuz0wVV4NTtkaVKZlmm8KTODyZDFpsyKPubDDcwT1ftRf5aSVM4x04I/1B7GkNz/TOy+zpJ0h0B7VHdxyO5JYiI/1qsatX/FE2aJdQYMYOtqfDH7ZH5UUKIqo538OKvE2M4MlBR/aVE4z4QDKfE/1kYrOfvVGfDzF/FWHfUrcqB8kdQMvk8vCoM8yYZsX4KE1aoJbNM2pWv2tpr9JE8b/VQgUyHOgPYAha+UOmZki4Sfl9H62687EIWdbM57ZxmwIiBp60SrJLiBfZon9JqXKdtJOKj0CRokQiBnONNXCVerLFeBNQfeKRw8tgJXf+QPohMGYkSDdc8hTgdbmhTwB1Vv01stlYK12QMNRCovlp/fcmpB72Phlq+/3p5pqMzknw+qm5QAz7JnpZJCFHit52gHwAkKRkVPB3HF2rfLrdTYz5c9Bok1ICAY9My47eLFdduIe99V52cjMLQuUmNFBPrDdyZKVqIHJ/wtWO/wIFpAVGSJMHctyEKmeJVc1IQN74Wm00PrpPackHdO3G41bBmkp5pqUdsSgSkwdfNVqv0cMcSe04NrRGNKMcZ7TA/CMaP1YnhxvVE+z8aksJqSJ+gdplvuwl40y5C8UEHeAi1V8Q0Bf4YvYRgOVIWm2Lzjdn2z9PWLGcStUj11/1hthk2li4V3mgm2Cr2IZme2sn4rZmJ6dexGP1nk+ZYOq0xLE8F7oex9gyDN+A/6zHqnuhO/X08qye0gochMr8U89Qvj2c0L3P2mjCea2H1mEriAJPqMPMKIinh1lQJEZufnfCcPxbZLKTtl6zHtHgOztejd1gV/nUyCVKD4MCMfBDy9C/Af8pWx6akOg/QSQNIGA2AI6zprHn9zEjpFIzXJYvruVI22Yt6oF9Xnt7Ki82wRK2M96r4kj6cwSs4exMPGv8fWMrFTm0Br6p6T+HZsxyyn2ChuPIgpfisnce/ZaU/0xCZhK/K79+TK2GeeChq5oEpua/1tx4+kDHi7H9381pLJmy2oXW060c2mmwA9+EpcuwEDhr8fsnghbv41u7b1NhEmWNVUy29Dwaz61PPGUdh5DsvaKLWC+raZ/6UEKPw+tiABJ5o6u2jAWgmEYmmJCKapNgtfPc6D+O0aHH9oqh6u4+8NRAhusPZzDGWBr6AT4pexgWFeEhZhn6bXM9HhpUe0IhOTw5D+tqXrTlNon4kjYibiMUFy1h2YyYS3IEdu1J4xqvo0rFyCxF1C+P6ubc0tClRPkXg=="; - string actualPlain = Utilities.AESUtility.DecryptWithGCM(key: key, nonce: nonce, aad: aad, cipherText: cipherText); + string actualPlain = Utilities.AESUtility.DecryptWithGCM(encodingKey: new EncodedString(key, EncodingKinds.Literal), encodingNonce: new EncodedString(nonce, EncodingKinds.Literal), encodingAssociatedData: new EncodedString(associatedData, EncodingKinds.Literal), encodingCipher: new EncodedString(cipherText, EncodingKinds.Base64))!; string expectedPlain = "-----BEGIN CERTIFICATE-----\nMIID3DCCAsSgAwIBAgIUGZNrTcamx3sFSJsQli3v9C6gZe8wDQYJKoZIhvcNAQEL\nBQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT\nFFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg\nQ0EwHhcNMjAwODAxMDczNTE4WhcNMjUwNzMxMDczNTE4WjBuMRgwFgYDVQQDDA9U\nZW5wYXkuY29tIHNpZ24xEzARBgNVBAoMClRlbnBheS5jb20xHTAbBgNVBAsMFFRl\nbnBheS5jb20gQ0EgQ2VudGVyMQswCQYDVQQGDAJDTjERMA8GA1UEBwwIU2hlblpo\nZW4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDOAYHqxCqaRzoTIvgV\nixaYJJvmvHbiczbx5MQ9XL1ITSFxkTsNsk7RKHnO7eBS5imheJgQwd22Ky+XclSe\n7B4odssu/l/+gHo2gooTYrrCpQrOkpvGMf8R8aI56BQIF+vsomDvVq1NojHV2Fql\njMwFXzhj2EmU6p6gDv9iL7q1NrfnxFx8iJe4OhIB5Ek4qn1xXxrTUhiULd2vXlbI\nXhRetZSNcJsLt5Rw7D7c8F+aX2JchfeqsZECwKW7bSjMbVWWC6M9MgkB/aId8P0y\n7qEiiXFJkfkg1I/E1ud2apopsid5tdCyRRR6+MhhX2EC8S04MN4soUT7haqNNxX2\nrKHnAgMBAAGjgYEwfzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIE8DBlBgNVHR8EXjBc\nMFqgWKBWhlRodHRwOi8vZXZjYS5pdHJ1cy5jb20uY24vcHVibGljL2l0cnVzY3Js\nP0NBPTFCRDQyMjBFNTBEQkMwNEIwNkFEMzk3NTQ5ODQ2QzAxQzNFOEVCRDIwDQYJ\nKoZIhvcNAQELBQADggEBAJyg2z4oLQmPfftLQWyzbUc9ONhRMtfA+tVlVBgtLLKn\nWuDlsmEntheM07fu84F4pcfs3yHzjD7pAOFbO4Yt1yhQ50DK35sjbRWepPdWJZLl\nni7KBctcmm0o4zq37oB7vonmBEbFqYs9DaINYOjgI3J25iSBkPVC7dBbvFj2xB0L\ncIcXipq30tDdC/oUem27MNzwZAt49WthKhw6u3HSkcE5cO4LyYTsJhSyG/7LXwvV\nMgX4Jyzo0SSiGOU1/beaZssTVI8sTPJVlHWjhNE3Lc2SaAlKGfGwvt0X3cEZEF+7\noEZIFTkkAF2JhqfnpR3gST0G8Umq1SaVtCPP/zVI8x0=\n-----END CERTIFICATE-----"; Assert.Equal(expectedPlain, actualPlain); diff --git a/test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/TestCase_ToolsRSAUtilityTests.cs b/test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/TestCase_ToolsRSAUtilityTests.cs index 5cd164f7..5a02fa77 100644 --- a/test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/TestCase_ToolsRSAUtilityTests.cs +++ b/test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/TestCase_ToolsRSAUtilityTests.cs @@ -2,6 +2,8 @@ using Xunit; namespace SKIT.FlurlHttpClient.Wechat.Work.UnitTests { + using SKIT.FlurlHttpClient.Primitives; + public class TestCase_ToolsRSAUtilityTests { // 此处测试的 RSA 公钥/私钥是自签名生成的,仅供执行 RSA 相关的单元测试,不能用于调用企业微信 API @@ -12,7 +14,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Work.UnitTests public void TestRSADecrypt() { string cipherText = "ewwZ8LmXVJpkJpj/JWcz16L4bePAGcf3Fi2EKyC6AS3JsF5u4aku7iOYqtcAczjoYwE1fqSadRd6YTrWr3tLP3uWFYmhqthQoaAcjmQS0vHYRFeS1V7q5hbziVLRp7C42S4YrvqXAmSmUyjPUXG5tXFVchARVkTr1F53HGoPP+iBg+i8y0uJK4FgiuKraFgdtKofv/k5/30xKzRHxdLFCFt1rF7wL+Hk/7Bl0tFZM/rfhmuvwbf46zWhxKKviAge+61tEot4QCSBLnAFpPuSQsTOOSOrlCl92DwW54dWdlWwhqkTVHdm6pXEdUE66y1yoZkXfpqjnONjta0njqN/Jw=="; - string actualPlain = Utilities.RSAUtility.DecryptWithECB(RSA_PEM_PRIVATE_KEY, cipherText); + string actualPlain = Utilities.RSAUtility.DecryptWithECB(RSA_PEM_PRIVATE_KEY, new EncodedString(cipherText, EncodingKinds.Base64))!; string expectedPlain = "RsaDecryptTest"; Assert.Equal(expectedPlain, actualPlain);