diff --git a/docs/WechatTenpayBusiness/Advanced_EventSignatureVerification.md b/docs/WechatTenpayBusiness/Advanced_EventSignatureVerification.md index 343c7ef9..445c7dd1 100644 --- a/docs/WechatTenpayBusiness/Advanced_EventSignatureVerification.md +++ b/docs/WechatTenpayBusiness/Advanced_EventSignatureVerification.md @@ -22,10 +22,10 @@ bool ret = client.VerifyEventSignature( 由于 `VerifyEventSignature()` 方法内部会 `try-catch` 掉所有异常情况,并直接返回 `false`。为方便开发者在调试阶段排查验签的错误信息,你可以在验证回调通知事件签名时指定接收最后一个 `out` 返回参数,该参数中包含了一些异常的原因和相关堆栈信息。 ```csharp -bool ret = client.VerifyEventSignature(timestamp, nonce, body, signature, serialNumber, out Exception error); +bool ret = client.VerifyEventSignature(authorization, signature, out Exception error); if (!ret) { Console.WriteLine(error); - Console.WriteLine(error.InnerException); + Console.WriteLine(error?.InnerException); } ``` diff --git a/docs/WechatTenpayBusiness/Advanced_ResponseSignatureVerification.md b/docs/WechatTenpayBusiness/Advanced_ResponseSignatureVerification.md index 82c4128a..71aa9507 100644 --- a/docs/WechatTenpayBusiness/Advanced_ResponseSignatureVerification.md +++ b/docs/WechatTenpayBusiness/Advanced_ResponseSignatureVerification.md @@ -32,6 +32,6 @@ bool ret = client.VerifyResponseSignature(response, out Exception error); if (!ret) { Console.WriteLine(error); - Console.WriteLine(error.InnerException); + Console.WriteLine(error?.InnerException); } ``` diff --git a/docs/WechatTenpayV3/Advanced_EventSignatureVerification.md b/docs/WechatTenpayV3/Advanced_EventSignatureVerification.md index 82a1d32e..137ee057 100644 --- a/docs/WechatTenpayV3/Advanced_EventSignatureVerification.md +++ b/docs/WechatTenpayV3/Advanced_EventSignatureVerification.md @@ -58,7 +58,7 @@ bool ret = client.VerifyEventSignature(timestamp, nonce, body, signature, serial if (!ret) { Console.WriteLine(error); - Console.WriteLine(error.InnerException); + Console.WriteLine(error?.InnerException); } ``` diff --git a/docs/WechatTenpayV3/Advanced_ResponseSignatureVerification.md b/docs/WechatTenpayV3/Advanced_ResponseSignatureVerification.md index 0b1dcb07..8d3e5884 100644 --- a/docs/WechatTenpayV3/Advanced_ResponseSignatureVerification.md +++ b/docs/WechatTenpayV3/Advanced_ResponseSignatureVerification.md @@ -67,7 +67,7 @@ bool ret = client.VerifyResponseSignature(response, out Exception error); if (!ret) { Console.WriteLine(error); - Console.WriteLine(error.InnerException); + Console.WriteLine(error?.InnerException); } ``` diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayBusiness/Extensions/Internal/WechatTenpayBusinessClientSignExtensions.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayBusiness/Extensions/Internal/WechatTenpayBusinessClientSignExtensions.cs index 6b72b298..32e81c3f 100644 --- a/src/SKIT.FlurlHttpClient.Wechat.TenpayBusiness/Extensions/Internal/WechatTenpayBusinessClientSignExtensions.cs +++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayBusiness/Extensions/Internal/WechatTenpayBusinessClientSignExtensions.cs @@ -6,12 +6,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayBusiness { internal static class WechatTenpayBusinessClientSignExtensions { - public static bool VerifySignature(this WechatTenpayBusinessClient client, string strAuthorization, string strBody) - { - return VerifySignature(client, strAuthorization, strBody, out _); - } - - public static bool VerifySignature(this WechatTenpayBusinessClient client, string strAuthorization, string strBody, out Exception? error) + public static bool VerifySignature(this WechatTenpayBusinessClient client, string strAuthorization, string strContent, out Exception? error) { if (!string.IsNullOrEmpty(strAuthorization)) { @@ -27,10 +22,17 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayBusiness string strTimestamp = dictTBEPAuthorization["timestamp"]!; string strNonce = dictTBEPAuthorization["nonce"]!; string strSignature = dictTBEPAuthorization["signature"]!; - string strSerialNumber = dictTBEPAuthorization["tbep_serial_number"]!; string strSignAlgorithm = dictTBEPAuthorization["signature_algorithm"]!; + string strSerialNumber = dictTBEPAuthorization["tbep_serial_number"]!; - return VerifySignature(client, strTimestamp, strNonce, strBody, strSignature, strSerialNumber, strSignAlgorithm, out error); + return VerifySignature( + client, + strTimestamp: strTimestamp, + strNonce: strNonce, + strContent: strContent, + strSignature: strSignature, + strSignatureAlgorithm: strSignAlgorithm, + strSerialNumber: strSerialNumber, out error); } catch (Exception ex) { @@ -43,26 +45,11 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayBusiness return false; } - public static bool VerifySignature(this WechatTenpayBusinessClient client, string strTimestamp, string strNonce, string strBody, string strSignature, string strSerialNumber) - { - return VerifySignature(client, strTimestamp, strNonce, strBody, strSignature, strSerialNumber, Constants.SignAlgorithms.SHA245_WITH_RSA, out _); - } - - public static bool VerifySignature(this WechatTenpayBusinessClient client, string strTimestamp, string strNonce, string strBody, string strSignature, string strSerialNumber, string strSignAlgorithm) - { - return VerifySignature(client, strTimestamp, strNonce, strBody, strSignature, strSerialNumber, strSignAlgorithm, out _); - } - - public static bool VerifySignature(this WechatTenpayBusinessClient client, string strTimestamp, string strNonce, string strBody, string strSignature, string strSerialNumber, out Exception? error) - { - return VerifySignature(client, strTimestamp, strNonce, strBody, strSignature, strSerialNumber, Constants.SignAlgorithms.SHA245_WITH_RSA, out error); - } - - public static bool VerifySignature(this WechatTenpayBusinessClient client, string strTimestamp, string strNonce, string strBody, string strSignature, string strSerialNumber, string strSignAlgorithm, out Exception? error) + public static bool VerifySignature(this WechatTenpayBusinessClient client, string strTimestamp, string strNonce, string strContent, string strSignature, string strSignatureAlgorithm, string strSerialNumber, out Exception? error) { if (client == null) throw new ArgumentNullException(nameof(client)); - switch (strSignAlgorithm) + switch (strSignatureAlgorithm) { case Constants.SignAlgorithms.SHA245_WITH_RSA: { @@ -80,7 +67,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayBusiness error = null; return Utilities.RSAUtility.VerifyWithSHA256( publicKey: client.Credentials.TBEPCertificatePublicKey, - plainText: GetPlainTextForSignature(timestamp: strTimestamp, nonce: strNonce, body: strBody), + message: GetPlainTextForSignature(timestamp: strTimestamp, nonce: strNonce, body: strContent), signature: strSignature ); } diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayBusiness/Extensions/WechatTenpayBusinessClientEventVerificationExtensions.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayBusiness/Extensions/WechatTenpayBusinessClientEventVerificationExtensions.cs index 748689ca..2df5bdf2 100644 --- a/src/SKIT.FlurlHttpClient.Wechat.TenpayBusiness/Extensions/WechatTenpayBusinessClientEventVerificationExtensions.cs +++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayBusiness/Extensions/WechatTenpayBusinessClientEventVerificationExtensions.cs @@ -30,9 +30,18 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayBusiness if (callbackAuthorization == null) throw new ArgumentNullException(nameof(callbackAuthorization)); if (callbackBody == null) throw new ArgumentNullException(nameof(callbackBody)); - bool ret = WechatTenpayBusinessClientSignExtensions.VerifySignature(client, callbackAuthorization, callbackBody, out error); + bool ret = WechatTenpayBusinessClientSignExtensions.VerifySignature( + client, + strAuthorization: callbackAuthorization, + strContent: callbackBody, + out error + ); + if (error != null) + { error = new Exceptions.WechatTenpayBusinessEventVerificationException("Verify signature of event failed. Please see the `InnerException` for more details.", error); + } + return ret; } @@ -48,7 +57,16 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayBusiness /// public static bool VerifyEventSignature(this WechatTenpayBusinessClient client, string callbackTimestamp, string callbackNonce, string callbackBody, string callbackSignature, string callbackSerialNumber) { - return VerifyEventSignature(client, callbackTimestamp, callbackNonce, callbackBody, callbackSignature, callbackSerialNumber, Constants.SignAlgorithms.SHA245_WITH_RSA, out _); + return VerifyEventSignature( + client, + callbackTimestamp: callbackTimestamp, + callbackNonce: callbackNonce, + callbackBody: callbackBody, + callbackSignature: callbackSignature, + callbackSignatureAlgorithm: Constants.SignAlgorithms.SHA245_WITH_RSA, + callbackSerialNumber: callbackSerialNumber, + out _ + ); } /// @@ -59,12 +77,21 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayBusiness /// 。 /// /// + /// /// - /// /// - public static bool VerifyEventSignature(this WechatTenpayBusinessClient client, string callbackTimestamp, string callbackNonce, string callbackBody, string callbackSignature, string callbackSerialNumber, string callbackSignAlgorithm) + public static bool VerifyEventSignature(this WechatTenpayBusinessClient client, string callbackTimestamp, string callbackNonce, string callbackBody, string callbackSignature, string callbackSignatureAlgorithm, string callbackSerialNumber) { - return VerifyEventSignature(client, callbackTimestamp, callbackNonce, callbackBody, callbackSignature, callbackSerialNumber, callbackSignAlgorithm, out _); + return VerifyEventSignature( + client, + callbackTimestamp: callbackTimestamp, + callbackNonce: callbackNonce, + callbackBody: callbackBody, + callbackSignature: callbackSignature, + callbackSignatureAlgorithm: callbackSignatureAlgorithm, + callbackSerialNumber: callbackSerialNumber, + out _ + ); } /// @@ -81,7 +108,16 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayBusiness /// public static bool VerifyEventSignature(this WechatTenpayBusinessClient client, string callbackTimestamp, string callbackNonce, string callbackBody, string callbackSignature, string callbackSerialNumber, out Exception? error) { - return VerifyEventSignature(client, callbackTimestamp, callbackNonce, callbackBody, callbackSignature, callbackSerialNumber, Constants.SignAlgorithms.SHA245_WITH_RSA, out error); + return VerifyEventSignature( + client, + callbackTimestamp: callbackTimestamp, + callbackNonce: callbackNonce, + callbackBody: callbackBody, + callbackSignature: callbackSignature, + callbackSignatureAlgorithm: Constants.SignAlgorithms.SHA245_WITH_RSA, + callbackSerialNumber: callbackSerialNumber, + out error + ); } /// @@ -92,18 +128,31 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayBusiness /// 。 /// /// + /// /// - /// /// /// /// - public static bool VerifyEventSignature(this WechatTenpayBusinessClient client, string callbackTimestamp, string callbackNonce, string callbackBody, string callbackSignature, string callbackSerialNumber, string callbackSignAlgorithm, out Exception? error) + public static bool VerifyEventSignature(this WechatTenpayBusinessClient client, string callbackTimestamp, string callbackNonce, string callbackBody, string callbackSignature, string callbackSignatureAlgorithm, string callbackSerialNumber, out Exception? error) { if (client == null) throw new ArgumentNullException(nameof(client)); - bool ret = WechatTenpayBusinessClientSignExtensions.VerifySignature(client, callbackTimestamp, callbackNonce, callbackBody, callbackSignature, callbackSerialNumber, callbackSignAlgorithm, out error); + bool ret = WechatTenpayBusinessClientSignExtensions.VerifySignature( + client, + strTimestamp: callbackTimestamp, + strNonce: callbackNonce, + strContent: callbackBody, + strSignature: callbackSignature, + strSignatureAlgorithm: callbackSignatureAlgorithm, + strSerialNumber: callbackSerialNumber, + out error + ); + if (error != null) + { error = new Exceptions.WechatTenpayBusinessEventVerificationException("Verify signature of event failed. Please see the `InnerException` for more details.", error); + } + return ret; } } diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayBusiness/Extensions/WechatTenpayBusinessClientResponseVerificationExtensions.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayBusiness/Extensions/WechatTenpayBusinessClientResponseVerificationExtensions.cs index 87856814..2416d20b 100644 --- a/src/SKIT.FlurlHttpClient.Wechat.TenpayBusiness/Extensions/WechatTenpayBusinessClientResponseVerificationExtensions.cs +++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayBusiness/Extensions/WechatTenpayBusinessClientResponseVerificationExtensions.cs @@ -32,11 +32,18 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayBusiness { if (client == null) throw new ArgumentNullException(nameof(client)); - string? responseAuthHeader = response.RawHeaders.FirstOrDefault(e => string.Equals(e.Key, "TBEP-Authorization", StringComparison.OrdinalIgnoreCase)).Value; - string responseBody = Encoding.UTF8.GetString(response.RawBytes); - bool ret = WechatTenpayBusinessClientSignExtensions.VerifySignature(client, responseAuthHeader, responseBody, out error); + bool ret = WechatTenpayBusinessClientSignExtensions.VerifySignature( + client, + strAuthorization: response.RawHeaders.FirstOrDefault(e => string.Equals(e.Key, "TBEP-Authorization", StringComparison.OrdinalIgnoreCase)).Value, + strContent: Encoding.UTF8.GetString(response.RawBytes), + out error + ); + if (error != null) + { error = new Exceptions.WechatTenpayBusinessResponseVerificationException("Verify signature of response failed. Please see the `InnerException` for more details.", error); + } + return ret; } @@ -52,7 +59,16 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayBusiness /// public static bool VerifyResponseSignature(this WechatTenpayBusinessClient client, string responseTimestamp, string responseNonce, string responseBody, string responseSignature, string responseSerialNumber) { - return VerifyResponseSignature(client, responseTimestamp, responseNonce, responseBody, responseSignature, responseSerialNumber, Constants.SignAlgorithms.SHA245_WITH_RSA, out _); + return VerifyResponseSignature( + client, + responseTimestamp: responseTimestamp, + responseNonce: responseNonce, + responseBody: responseBody, + responseSignature: responseSignature, + responseSignatureAlgorithm: Constants.SignAlgorithms.SHA245_WITH_RSA, + responseSerialNumber: responseSerialNumber, + out _ + ); } /// @@ -63,12 +79,21 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayBusiness /// 。 /// /// + /// /// - /// /// - public static bool VerifyResponseSignature(this WechatTenpayBusinessClient client, string responseTimestamp, string responseNonce, string responseBody, string responseSignature, string responseSerialNumber, string responseSignAlgorithm) + public static bool VerifyResponseSignature(this WechatTenpayBusinessClient client, string responseTimestamp, string responseNonce, string responseBody, string responseSignature, string responseSignatureAlgorithm, string responseSerialNumber) { - return VerifyResponseSignature(client, responseTimestamp, responseNonce, responseBody, responseSignature, responseSerialNumber, responseSignAlgorithm, out _); + return VerifyResponseSignature( + client, + responseTimestamp: responseTimestamp, + responseNonce: responseNonce, + responseBody: responseBody, + responseSignature: responseSignature, + responseSignatureAlgorithm: responseSignatureAlgorithm, + responseSerialNumber: responseSerialNumber, + out _ + ); } /// @@ -84,7 +109,16 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayBusiness /// public static bool VerifyResponseSignature(this WechatTenpayBusinessClient client, string responseTimestamp, string responseNonce, string responseBody, string responseSignature, string responseSerialNumber, out Exception? error) { - return VerifyResponseSignature(client, responseTimestamp, responseNonce, responseBody, responseSignature, responseSerialNumber, Constants.SignAlgorithms.SHA245_WITH_RSA, out error); + return VerifyResponseSignature( + client, + responseTimestamp: responseTimestamp, + responseNonce: responseNonce, + responseBody: responseBody, + responseSignature: responseSignature, + responseSignatureAlgorithm: Constants.SignAlgorithms.SHA245_WITH_RSA, + responseSerialNumber: responseSerialNumber, + out error + ); } /// @@ -95,17 +129,30 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayBusiness /// 。 /// /// + /// /// - /// /// /// - public static bool VerifyResponseSignature(this WechatTenpayBusinessClient client, string responseTimestamp, string responseNonce, string responseBody, string responseSignature, string responseSerialNumber, string responseSignAlgorithm, out Exception? error) + public static bool VerifyResponseSignature(this WechatTenpayBusinessClient client, string responseTimestamp, string responseNonce, string responseBody, string responseSignature, string responseSignatureAlgorithm, string responseSerialNumber, out Exception? error) { if (client == null) throw new ArgumentNullException(nameof(client)); - bool ret = WechatTenpayBusinessClientSignExtensions.VerifySignature(client, responseTimestamp, responseNonce, responseBody, responseSignature, responseSerialNumber, responseSignAlgorithm, out error); + bool ret = WechatTenpayBusinessClientSignExtensions.VerifySignature( + client, + strTimestamp: responseTimestamp, + strNonce: responseNonce, + strContent: responseBody, + strSignature: responseSignature, + strSignatureAlgorithm: responseSignatureAlgorithm, + strSerialNumber: responseSerialNumber, + out error + ); + if (error != null) + { error = new Exceptions.WechatTenpayBusinessResponseVerificationException("Verify signature of response failed. Please see the `InnerException` for more details.", error); + } + return ret; } } diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayBusiness/Utilities/RSAUtility.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayBusiness/Utilities/RSAUtility.cs index 2ffcd86f..58af4a62 100644 --- a/src/SKIT.FlurlHttpClient.Wechat.TenpayBusiness/Utilities/RSAUtility.cs +++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayBusiness/Utilities/RSAUtility.cs @@ -16,35 +16,83 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayBusiness.Utilities private const string RSA_CIPHER_PADDING_OAEP_WITH_SHA1_AND_MGF1 = "OAEPWITHSHA1ANDMGF1PADDING"; private const string RSA_SIGNER_ALGORITHM_SHA256 = "SHA-256withRSA"; + private static byte[] ConvertPkcs8PrivateKeyToByteArray(string privateKey) + { + privateKey = privateKey + .Replace("-----BEGIN PRIVATE KEY-----", string.Empty) + .Replace("-----END PRIVATE KEY-----", string.Empty); + privateKey = Regex.Replace(privateKey, "\\s+", string.Empty); + return Convert.FromBase64String(privateKey); + } + + private static byte[] ConvertPkcs8PublicKeyToByteArray(string publicKey) + { + publicKey = publicKey + .Replace("-----BEGIN PUBLIC KEY-----", string.Empty) + .Replace("-----END PUBLIC KEY-----", string.Empty); + publicKey = Regex.Replace(publicKey, "\\s+", string.Empty); + return Convert.FromBase64String(publicKey); + } + + private static byte[] SignWithSHA256(RsaKeyParameters rsaPrivateKeyParams, byte[] msgBytes) + { + ISigner signer = SignerUtilities.GetSigner(RSA_SIGNER_ALGORITHM_SHA256); + signer.Init(true, rsaPrivateKeyParams); + signer.BlockUpdate(msgBytes, 0, msgBytes.Length); + return signer.GenerateSignature(); + } + + private static bool VerifyWithSHA256(RsaKeyParameters rsaPublicKeyParams, byte[] msgBytes, byte[] signBytes) + { + ISigner signer = SignerUtilities.GetSigner(RSA_SIGNER_ALGORITHM_SHA256); + signer.Init(false, rsaPublicKeyParams); + signer.BlockUpdate(msgBytes, 0, msgBytes.Length); + return signer.VerifySignature(signBytes); + } + + private static byte[] DecryptWithECB(RsaKeyParameters rsaPrivateKeyParams, byte[] cipherBytes, string paddingAlgorithm) + { + IBufferedCipher cipher = CipherUtilities.GetCipher($"{RSA_CIPHER_ALGORITHM_ECB}/{paddingAlgorithm}"); + cipher.Init(false, rsaPrivateKeyParams); + return cipher.DoFinal(cipherBytes); + } + + private static byte[] EncryptWithECB(RsaKeyParameters rsaPublicKeyParams, byte[] msgBytes, string paddingAlgorithm) + { + IBufferedCipher cipher = CipherUtilities.GetCipher($"{RSA_CIPHER_ALGORITHM_ECB}/{paddingAlgorithm}"); + cipher.Init(true, rsaPublicKeyParams); + return cipher.DoFinal(msgBytes); + } + /// /// 使用私钥基于 SHA-256 算法生成签名。 /// /// PKCS#8 私钥字节数组。 - /// 待签名的数据字节数组。 + /// 待签名的数据字节数组。 /// 签名字节数组。 - public static byte[] SignWithSHA256(byte[] privateKeyBytes, byte[] plainBytes) + public static byte[] SignWithSHA256(byte[] privateKeyBytes, byte[] msgBytes) { if (privateKeyBytes == null) throw new ArgumentNullException(nameof(privateKeyBytes)); - if (plainBytes == null) throw new ArgumentNullException(nameof(plainBytes)); + if (msgBytes == null) throw new ArgumentNullException(nameof(msgBytes)); RsaKeyParameters rsaKeyParams = (RsaKeyParameters)PrivateKeyFactory.CreateKey(privateKeyBytes); - return SignWithSHA256(rsaKeyParams, plainBytes); + return SignWithSHA256(rsaKeyParams, msgBytes); } /// /// 使用私钥基于 SHA-256 算法生成签名。 /// /// PKCS#8 私钥(PEM 格式)。 - /// 待签名的文本数据。 + /// 待签名的文本数据。 /// 经 Base64 编码的签名。 - public static string SignWithSHA256(string privateKey, string plainText) + public static string SignWithSHA256(string privateKey, string message) { if (privateKey == null) throw new ArgumentNullException(nameof(privateKey)); - if (plainText == null) throw new ArgumentNullException(nameof(plainText)); + if (message == null) throw new ArgumentNullException(nameof(message)); byte[] privateKeyBytes = ConvertPkcs8PrivateKeyToByteArray(privateKey); - byte[] plainBytes = Encoding.UTF8.GetBytes(plainText); - byte[] signBytes = SignWithSHA256(privateKeyBytes, plainBytes); + byte[] msgBytes = Encoding.UTF8.GetBytes(message); + byte[] signBytes = SignWithSHA256(privateKeyBytes, msgBytes); return Convert.ToBase64String(signBytes); } @@ -52,36 +100,36 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayBusiness.Utilities /// 使用公钥基于 SHA-256 算法验证签名。 /// /// PKCS#8 公钥字节数据。 - /// 待验证的数据字节数据。 + /// 待验证的数据字节数据。 /// 待验证的签名字节数据。 /// 验证结果。 - public static bool VerifyWithSHA256(byte[] publicKeyBytes, byte[] plainBytes, byte[] signBytes) + public static bool VerifyWithSHA256(byte[] publicKeyBytes, byte[] msgBytes, byte[] signBytes) { if (publicKeyBytes == null) throw new ArgumentNullException(nameof(publicKeyBytes)); - if (plainBytes == null) throw new ArgumentNullException(nameof(plainBytes)); + if (msgBytes == null) throw new ArgumentNullException(nameof(msgBytes)); if (signBytes == null) throw new ArgumentNullException(nameof(signBytes)); RsaKeyParameters rsaKeyParams = (RsaKeyParameters)PublicKeyFactory.CreateKey(publicKeyBytes); - return VerifyWithSHA256(rsaKeyParams, plainBytes, signBytes); + return VerifyWithSHA256(rsaKeyParams, msgBytes, signBytes); } /// /// 使用公钥基于 SHA-256 算法验证签名。 /// /// PKCS#8 公钥(PEM 格式)。 - /// 待验证的文本数据。 + /// 待验证的文本数据。 /// 经 Base64 编码的待验证的签名。 /// 验证结果。 - public static bool VerifyWithSHA256(string publicKey, string plainText, string signature) + public static bool VerifyWithSHA256(string publicKey, string message, string signature) { if (publicKey == null) throw new ArgumentNullException(nameof(publicKey)); - if (plainText == null) throw new ArgumentNullException(nameof(plainText)); + if (message == null) throw new ArgumentNullException(nameof(message)); if (signature == null) throw new ArgumentNullException(nameof(signature)); byte[] publicKeyBytes = ConvertPkcs8PublicKeyToByteArray(publicKey); - byte[] plainBytes = Encoding.UTF8.GetBytes(plainText); + byte[] msgBytes = Encoding.UTF8.GetBytes(message); byte[] signBytes = Convert.FromBase64String(signature); - return VerifyWithSHA256(publicKeyBytes, plainBytes, signBytes); + return VerifyWithSHA256(publicKeyBytes, msgBytes, signBytes); } /// @@ -151,53 +199,5 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayBusiness.Utilities byte[] cipherBytes = EncryptWithECB(publicKeyBytes, plainBytes, paddingAlgorithm); return Convert.ToBase64String(cipherBytes); } - - private static byte[] ConvertPkcs8PrivateKeyToByteArray(string privateKey) - { - privateKey = privateKey - .Replace("-----BEGIN PRIVATE KEY-----", string.Empty) - .Replace("-----END PRIVATE KEY-----", string.Empty); - privateKey = Regex.Replace(privateKey, "\\s+", string.Empty); - return Convert.FromBase64String(privateKey); - } - - private static byte[] ConvertPkcs8PublicKeyToByteArray(string publicKey) - { - publicKey = publicKey - .Replace("-----BEGIN PUBLIC KEY-----", string.Empty) - .Replace("-----END PUBLIC KEY-----", string.Empty); - publicKey = Regex.Replace(publicKey, "\\s+", string.Empty); - return Convert.FromBase64String(publicKey); - } - - private static byte[] SignWithSHA256(RsaKeyParameters rsaKeyParams, byte[] plainBytes) - { - ISigner signer = SignerUtilities.GetSigner(RSA_SIGNER_ALGORITHM_SHA256); - signer.Init(true, rsaKeyParams); - signer.BlockUpdate(plainBytes, 0, plainBytes.Length); - return signer.GenerateSignature(); - } - - private static bool VerifyWithSHA256(RsaKeyParameters rsaKeyParams, byte[] plainBytes, byte[] signBytes) - { - ISigner signer = SignerUtilities.GetSigner(RSA_SIGNER_ALGORITHM_SHA256); - signer.Init(false, rsaKeyParams); - signer.BlockUpdate(plainBytes, 0, plainBytes.Length); - return signer.VerifySignature(signBytes); - } - - private static byte[] EncryptWithECB(RsaKeyParameters rsaKeyParams, byte[] plainBytes, string paddingAlgorithm) - { - IBufferedCipher cipher = CipherUtilities.GetCipher($"{RSA_CIPHER_ALGORITHM_ECB}/{paddingAlgorithm}"); - cipher.Init(true, rsaKeyParams); - return cipher.DoFinal(plainBytes); - } - - private static byte[] DecryptWithECB(RsaKeyParameters rsaKeyParams, byte[] cipherBytes, string paddingAlgorithm) - { - IBufferedCipher cipher = CipherUtilities.GetCipher($"{RSA_CIPHER_ALGORITHM_ECB}/{paddingAlgorithm}"); - cipher.Init(false, rsaKeyParams); - return cipher.DoFinal(cipherBytes); - } } } diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayBusiness/Utilities/SM3Utility.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayBusiness/Utilities/SM3Utility.cs index c09b7ed4..0165cfd7 100644 --- a/src/SKIT.FlurlHttpClient.Wechat.TenpayBusiness/Utilities/SM3Utility.cs +++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayBusiness/Utilities/SM3Utility.cs @@ -7,7 +7,40 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayBusiness.Utilities /// /// SM3 算法工具类。 /// - public static class SM3Utility + public static partial class SM3Utility + { + /// + /// 获取 SM3 哈希值。 + /// + /// 信息字节数组。 + /// 哈希字节数组。 + public static byte[] Hash(byte[] bytes) + { + if (bytes == null) throw new ArgumentNullException(nameof(bytes)); + + SM3Digest sm3 = new SM3Digest(); + sm3.BlockUpdate(bytes, 0, bytes.Length); + byte[] hashBytes = new byte[sm3.GetDigestSize()]; + sm3.DoFinal(hashBytes, 0); + return hashBytes; + } + + /// + /// 获取 SM3 哈希值。 + /// + /// 文本信息。 + /// 哈希值。 + public static string Hash(string message) + { + if (message == null) throw new ArgumentNullException(nameof(message)); + + byte[] msgBytes = Encoding.UTF8.GetBytes(message); + byte[] hashBytes = Hash(msgBytes); + return BitConverter.ToString(hashBytes).Replace("-", string.Empty); + } + } + + partial class SM3Utility { internal static class BitOperator { @@ -336,35 +369,5 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayBusiness.Utilities return DIGEST_LENGTH; } } - - /// - /// 获取 SM3 哈希值。 - /// - /// 信息字节数组。 - /// 哈希字节数组。 - public static byte[] Hash(byte[] bytes) - { - if (bytes == null) throw new ArgumentNullException(nameof(bytes)); - - SM3Digest sm3 = new SM3Digest(); - sm3.BlockUpdate(bytes, 0, bytes.Length); - byte[] hashBytes = new byte[sm3.GetDigestSize()]; - sm3.DoFinal(hashBytes, 0); - return hashBytes; - } - - /// - /// 获取 SM3 哈希值。 - /// - /// 文本信息。 - /// 哈希值。 - public static string Hash(string message) - { - if (message == null) throw new ArgumentNullException(nameof(message)); - - byte[] msgBytes = Encoding.UTF8.GetBytes(message); - byte[] hashBytes = Hash(msgBytes); - return BitConverter.ToString(hashBytes).Replace("-", string.Empty); - } } } diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Utilities/SM3Utility.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Utilities/SM3Utility.cs index 22730c36..4a470402 100644 --- a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Utilities/SM3Utility.cs +++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Utilities/SM3Utility.cs @@ -7,7 +7,40 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Utilities /// /// SM3 算法工具类。 /// - public static class SM3Utility + public static partial class SM3Utility + { + /// + /// 获取 SM3 哈希值。 + /// + /// 信息字节数组。 + /// 哈希字节数组。 + public static byte[] Hash(byte[] bytes) + { + if (bytes == null) throw new ArgumentNullException(nameof(bytes)); + + SM3Digest sm3 = new SM3Digest(); + sm3.BlockUpdate(bytes, 0, bytes.Length); + byte[] hashBytes = new byte[sm3.GetDigestSize()]; + sm3.DoFinal(hashBytes, 0); + return hashBytes; + } + + /// + /// 获取 SM3 哈希值。 + /// + /// 文本信息。 + /// 哈希值。 + public static string Hash(string message) + { + if (message == null) throw new ArgumentNullException(nameof(message)); + + byte[] msgBytes = Encoding.UTF8.GetBytes(message); + byte[] hashBytes = Hash(msgBytes); + return BitConverter.ToString(hashBytes).Replace("-", string.Empty); + } + } + + partial class SM3Utility { internal static class BitOperator { @@ -336,35 +369,5 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Utilities return DIGEST_LENGTH; } } - - /// - /// 获取 SM3 哈希值。 - /// - /// 信息字节数组。 - /// 哈希字节数组。 - public static byte[] Hash(byte[] bytes) - { - if (bytes == null) throw new ArgumentNullException(nameof(bytes)); - - SM3Digest sm3 = new SM3Digest(); - sm3.BlockUpdate(bytes, 0, bytes.Length); - byte[] hashBytes = new byte[sm3.GetDigestSize()]; - sm3.DoFinal(hashBytes, 0); - return hashBytes; - } - - /// - /// 获取 SM3 哈希值。 - /// - /// 文本信息。 - /// 哈希值。 - public static string Hash(string message) - { - if (message == null) throw new ArgumentNullException(nameof(message)); - - byte[] msgBytes = Encoding.UTF8.GetBytes(message); - byte[] hashBytes = Hash(msgBytes); - return BitConverter.ToString(hashBytes).Replace("-", string.Empty); - } } }