style: clean code

This commit is contained in:
Fu Diwei
2022-11-09 23:02:53 +08:00
parent 0bf69a19a9
commit e5100effeb
10 changed files with 268 additions and 179 deletions

View File

@@ -22,10 +22,10 @@ bool ret = client.VerifyEventSignature(
由于 `VerifyEventSignature()` 方法内部会 `try-catch` 掉所有异常情况,并直接返回 `false`。为方便开发者在调试阶段排查验签的错误信息,你可以在验证回调通知事件签名时指定接收最后一个 `out` 返回参数,该参数中包含了一些异常的原因和相关堆栈信息。 由于 `VerifyEventSignature()` 方法内部会 `try-catch` 掉所有异常情况,并直接返回 `false`。为方便开发者在调试阶段排查验签的错误信息,你可以在验证回调通知事件签名时指定接收最后一个 `out` 返回参数,该参数中包含了一些异常的原因和相关堆栈信息。
```csharp ```csharp
bool ret = client.VerifyEventSignature(timestamp, nonce, body, signature, serialNumber, out Exception error); bool ret = client.VerifyEventSignature(authorization, signature, out Exception error);
if (!ret) if (!ret)
{ {
Console.WriteLine(error); Console.WriteLine(error);
Console.WriteLine(error.InnerException); Console.WriteLine(error?.InnerException);
} }
``` ```

View File

@@ -32,6 +32,6 @@ bool ret = client.VerifyResponseSignature(response, out Exception error);
if (!ret) if (!ret)
{ {
Console.WriteLine(error); Console.WriteLine(error);
Console.WriteLine(error.InnerException); Console.WriteLine(error?.InnerException);
} }
``` ```

View File

@@ -58,7 +58,7 @@ bool ret = client.VerifyEventSignature(timestamp, nonce, body, signature, serial
if (!ret) if (!ret)
{ {
Console.WriteLine(error); Console.WriteLine(error);
Console.WriteLine(error.InnerException); Console.WriteLine(error?.InnerException);
} }
``` ```

View File

@@ -67,7 +67,7 @@ bool ret = client.VerifyResponseSignature(response, out Exception error);
if (!ret) if (!ret)
{ {
Console.WriteLine(error); Console.WriteLine(error);
Console.WriteLine(error.InnerException); Console.WriteLine(error?.InnerException);
} }
``` ```

View File

@@ -6,12 +6,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayBusiness
{ {
internal static class WechatTenpayBusinessClientSignExtensions internal static class WechatTenpayBusinessClientSignExtensions
{ {
public static bool VerifySignature(this WechatTenpayBusinessClient client, string strAuthorization, string strBody) public static bool VerifySignature(this WechatTenpayBusinessClient client, string strAuthorization, string strContent, out Exception? error)
{
return VerifySignature(client, strAuthorization, strBody, out _);
}
public static bool VerifySignature(this WechatTenpayBusinessClient client, string strAuthorization, string strBody, out Exception? error)
{ {
if (!string.IsNullOrEmpty(strAuthorization)) if (!string.IsNullOrEmpty(strAuthorization))
{ {
@@ -27,10 +22,17 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayBusiness
string strTimestamp = dictTBEPAuthorization["timestamp"]!; string strTimestamp = dictTBEPAuthorization["timestamp"]!;
string strNonce = dictTBEPAuthorization["nonce"]!; string strNonce = dictTBEPAuthorization["nonce"]!;
string strSignature = dictTBEPAuthorization["signature"]!; string strSignature = dictTBEPAuthorization["signature"]!;
string strSerialNumber = dictTBEPAuthorization["tbep_serial_number"]!;
string strSignAlgorithm = dictTBEPAuthorization["signature_algorithm"]!; 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) catch (Exception ex)
{ {
@@ -43,26 +45,11 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayBusiness
return false; return false;
} }
public static bool VerifySignature(this WechatTenpayBusinessClient client, string strTimestamp, string strNonce, string strBody, string strSignature, string strSerialNumber) public static bool VerifySignature(this WechatTenpayBusinessClient client, string strTimestamp, string strNonce, string strContent, string strSignature, string strSignatureAlgorithm, string strSerialNumber, out Exception? error)
{
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)
{ {
if (client == null) throw new ArgumentNullException(nameof(client)); if (client == null) throw new ArgumentNullException(nameof(client));
switch (strSignAlgorithm) switch (strSignatureAlgorithm)
{ {
case Constants.SignAlgorithms.SHA245_WITH_RSA: case Constants.SignAlgorithms.SHA245_WITH_RSA:
{ {
@@ -80,7 +67,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayBusiness
error = null; error = null;
return Utilities.RSAUtility.VerifyWithSHA256( return Utilities.RSAUtility.VerifyWithSHA256(
publicKey: client.Credentials.TBEPCertificatePublicKey, publicKey: client.Credentials.TBEPCertificatePublicKey,
plainText: GetPlainTextForSignature(timestamp: strTimestamp, nonce: strNonce, body: strBody), message: GetPlainTextForSignature(timestamp: strTimestamp, nonce: strNonce, body: strContent),
signature: strSignature signature: strSignature
); );
} }

View File

@@ -30,9 +30,18 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayBusiness
if (callbackAuthorization == null) throw new ArgumentNullException(nameof(callbackAuthorization)); if (callbackAuthorization == null) throw new ArgumentNullException(nameof(callbackAuthorization));
if (callbackBody == null) throw new ArgumentNullException(nameof(callbackBody)); 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) if (error != null)
{
error = new Exceptions.WechatTenpayBusinessEventVerificationException("Verify signature of event failed. Please see the `InnerException` for more details.", error); error = new Exceptions.WechatTenpayBusinessEventVerificationException("Verify signature of event failed. Please see the `InnerException` for more details.", error);
}
return ret; return ret;
} }
@@ -48,7 +57,16 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayBusiness
/// <returns></returns> /// <returns></returns>
public static bool VerifyEventSignature(this WechatTenpayBusinessClient client, string callbackTimestamp, string callbackNonce, string callbackBody, string callbackSignature, string callbackSerialNumber) 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 _
);
} }
/// <summary> /// <summary>
@@ -59,12 +77,21 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayBusiness
/// <param name="callbackNonce">。</param> /// <param name="callbackNonce">。</param>
/// <param name="callbackBody"></param> /// <param name="callbackBody"></param>
/// <param name="callbackSignature"></param> /// <param name="callbackSignature"></param>
/// <param name="callbackSignatureAlgorithm"></param>
/// <param name="callbackSerialNumber"></param> /// <param name="callbackSerialNumber"></param>
/// <param name="callbackSignAlgorithm"></param>
/// <returns></returns> /// <returns></returns>
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 _
);
} }
/// <summary> /// <summary>
@@ -81,7 +108,16 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayBusiness
/// <exception cref="ArgumentNullException"></exception> /// <exception cref="ArgumentNullException"></exception>
public static bool VerifyEventSignature(this WechatTenpayBusinessClient client, string callbackTimestamp, string callbackNonce, string callbackBody, string callbackSignature, string callbackSerialNumber, out Exception? error) 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
);
} }
/// <summary> /// <summary>
@@ -92,18 +128,31 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayBusiness
/// <param name="callbackNonce">。</param> /// <param name="callbackNonce">。</param>
/// <param name="callbackBody"></param> /// <param name="callbackBody"></param>
/// <param name="callbackSignature"></param> /// <param name="callbackSignature"></param>
/// <param name="callbackSignatureAlgorithm"></param>
/// <param name="callbackSerialNumber"></param> /// <param name="callbackSerialNumber"></param>
/// <param name="callbackSignAlgorithm"></param>
/// <param name="error"></param> /// <param name="error"></param>
/// <returns></returns> /// <returns></returns>
/// <exception cref="ArgumentNullException"></exception> /// <exception cref="ArgumentNullException"></exception>
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)); 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) if (error != null)
{
error = new Exceptions.WechatTenpayBusinessEventVerificationException("Verify signature of event failed. Please see the `InnerException` for more details.", error); error = new Exceptions.WechatTenpayBusinessEventVerificationException("Verify signature of event failed. Please see the `InnerException` for more details.", error);
}
return ret; return ret;
} }
} }

View File

@@ -32,11 +32,18 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayBusiness
{ {
if (client == null) throw new ArgumentNullException(nameof(client)); if (client == null) throw new ArgumentNullException(nameof(client));
string? responseAuthHeader = response.RawHeaders.FirstOrDefault(e => string.Equals(e.Key, "TBEP-Authorization", StringComparison.OrdinalIgnoreCase)).Value; bool ret = WechatTenpayBusinessClientSignExtensions.VerifySignature(
string responseBody = Encoding.UTF8.GetString(response.RawBytes); client,
bool ret = WechatTenpayBusinessClientSignExtensions.VerifySignature(client, responseAuthHeader, responseBody, out error); 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) if (error != null)
{
error = new Exceptions.WechatTenpayBusinessResponseVerificationException("Verify signature of response failed. Please see the `InnerException` for more details.", error); error = new Exceptions.WechatTenpayBusinessResponseVerificationException("Verify signature of response failed. Please see the `InnerException` for more details.", error);
}
return ret; return ret;
} }
@@ -52,7 +59,16 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayBusiness
/// <returns></returns> /// <returns></returns>
public static bool VerifyResponseSignature(this WechatTenpayBusinessClient client, string responseTimestamp, string responseNonce, string responseBody, string responseSignature, string responseSerialNumber) 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 _
);
} }
/// <summary> /// <summary>
@@ -63,12 +79,21 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayBusiness
/// <param name="responseNonce">。</param> /// <param name="responseNonce">。</param>
/// <param name="responseBody"></param> /// <param name="responseBody"></param>
/// <param name="responseSignature"></param> /// <param name="responseSignature"></param>
/// <param name="responseSignatureAlgorithm"></param>
/// <param name="responseSerialNumber"></param> /// <param name="responseSerialNumber"></param>
/// <param name="responseSignAlgorithm"></param>
/// <returns></returns> /// <returns></returns>
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 _
);
} }
/// <summary> /// <summary>
@@ -84,7 +109,16 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayBusiness
/// <returns></returns> /// <returns></returns>
public static bool VerifyResponseSignature(this WechatTenpayBusinessClient client, string responseTimestamp, string responseNonce, string responseBody, string responseSignature, string responseSerialNumber, out Exception? error) 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
);
} }
/// <summary> /// <summary>
@@ -95,17 +129,30 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayBusiness
/// <param name="responseNonce">。</param> /// <param name="responseNonce">。</param>
/// <param name="responseBody"></param> /// <param name="responseBody"></param>
/// <param name="responseSignature"></param> /// <param name="responseSignature"></param>
/// <param name="responseSignatureAlgorithm"></param>
/// <param name="responseSerialNumber"></param> /// <param name="responseSerialNumber"></param>
/// <param name="responseSignAlgorithm"></param>
/// <param name="error"></param> /// <param name="error"></param>
/// <returns></returns> /// <returns></returns>
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)); 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) if (error != null)
{
error = new Exceptions.WechatTenpayBusinessResponseVerificationException("Verify signature of response failed. Please see the `InnerException` for more details.", error); error = new Exceptions.WechatTenpayBusinessResponseVerificationException("Verify signature of response failed. Please see the `InnerException` for more details.", error);
}
return ret; return ret;
} }
} }

View File

@@ -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_CIPHER_PADDING_OAEP_WITH_SHA1_AND_MGF1 = "OAEPWITHSHA1ANDMGF1PADDING";
private const string RSA_SIGNER_ALGORITHM_SHA256 = "SHA-256withRSA"; 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);
}
/// <summary> /// <summary>
/// 使用私钥基于 SHA-256 算法生成签名。 /// 使用私钥基于 SHA-256 算法生成签名。
/// </summary> /// </summary>
/// <param name="privateKeyBytes">PKCS#8 私钥字节数组。</param> /// <param name="privateKeyBytes">PKCS#8 私钥字节数组。</param>
/// <param name="plainBytes">待签名的数据字节数组。</param> /// <param name="msgBytes">待签名的数据字节数组。</param>
/// <returns>签名字节数组。</returns> /// <returns>签名字节数组。</returns>
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 (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); RsaKeyParameters rsaKeyParams = (RsaKeyParameters)PrivateKeyFactory.CreateKey(privateKeyBytes);
return SignWithSHA256(rsaKeyParams, plainBytes); return SignWithSHA256(rsaKeyParams, msgBytes);
} }
/// <summary> /// <summary>
/// 使用私钥基于 SHA-256 算法生成签名。 /// 使用私钥基于 SHA-256 算法生成签名。
/// </summary> /// </summary>
/// <param name="privateKey">PKCS#8 私钥PEM 格式)。</param> /// <param name="privateKey">PKCS#8 私钥PEM 格式)。</param>
/// <param name="plainText">待签名的文本数据。</param> /// <param name="message">待签名的文本数据。</param>
/// <returns>经 Base64 编码的签名。</returns> /// <returns>经 Base64 编码的签名。</returns>
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 (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[] privateKeyBytes = ConvertPkcs8PrivateKeyToByteArray(privateKey);
byte[] plainBytes = Encoding.UTF8.GetBytes(plainText); byte[] msgBytes = Encoding.UTF8.GetBytes(message);
byte[] signBytes = SignWithSHA256(privateKeyBytes, plainBytes); byte[] signBytes = SignWithSHA256(privateKeyBytes, msgBytes);
return Convert.ToBase64String(signBytes); return Convert.ToBase64String(signBytes);
} }
@@ -52,36 +100,36 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayBusiness.Utilities
/// 使用公钥基于 SHA-256 算法验证签名。 /// 使用公钥基于 SHA-256 算法验证签名。
/// </summary> /// </summary>
/// <param name="publicKeyBytes">PKCS#8 公钥字节数据。</param> /// <param name="publicKeyBytes">PKCS#8 公钥字节数据。</param>
/// <param name="plainBytes">待验证的数据字节数据。</param> /// <param name="msgBytes">待验证的数据字节数据。</param>
/// <param name="signBytes">待验证的签名字节数据。</param> /// <param name="signBytes">待验证的签名字节数据。</param>
/// <returns>验证结果。</returns> /// <returns>验证结果。</returns>
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 (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)); if (signBytes == null) throw new ArgumentNullException(nameof(signBytes));
RsaKeyParameters rsaKeyParams = (RsaKeyParameters)PublicKeyFactory.CreateKey(publicKeyBytes); RsaKeyParameters rsaKeyParams = (RsaKeyParameters)PublicKeyFactory.CreateKey(publicKeyBytes);
return VerifyWithSHA256(rsaKeyParams, plainBytes, signBytes); return VerifyWithSHA256(rsaKeyParams, msgBytes, signBytes);
} }
/// <summary> /// <summary>
/// 使用公钥基于 SHA-256 算法验证签名。 /// 使用公钥基于 SHA-256 算法验证签名。
/// </summary> /// </summary>
/// <param name="publicKey">PKCS#8 公钥PEM 格式)。</param> /// <param name="publicKey">PKCS#8 公钥PEM 格式)。</param>
/// <param name="plainText">待验证的文本数据。</param> /// <param name="message">待验证的文本数据。</param>
/// <param name="signature">经 Base64 编码的待验证的签名。</param> /// <param name="signature">经 Base64 编码的待验证的签名。</param>
/// <returns>验证结果。</returns> /// <returns>验证结果。</returns>
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 (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)); if (signature == null) throw new ArgumentNullException(nameof(signature));
byte[] publicKeyBytes = ConvertPkcs8PublicKeyToByteArray(publicKey); byte[] publicKeyBytes = ConvertPkcs8PublicKeyToByteArray(publicKey);
byte[] plainBytes = Encoding.UTF8.GetBytes(plainText); byte[] msgBytes = Encoding.UTF8.GetBytes(message);
byte[] signBytes = Convert.FromBase64String(signature); byte[] signBytes = Convert.FromBase64String(signature);
return VerifyWithSHA256(publicKeyBytes, plainBytes, signBytes); return VerifyWithSHA256(publicKeyBytes, msgBytes, signBytes);
} }
/// <summary> /// <summary>
@@ -151,53 +199,5 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayBusiness.Utilities
byte[] cipherBytes = EncryptWithECB(publicKeyBytes, plainBytes, paddingAlgorithm); byte[] cipherBytes = EncryptWithECB(publicKeyBytes, plainBytes, paddingAlgorithm);
return Convert.ToBase64String(cipherBytes); 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);
}
} }
} }

View File

@@ -7,7 +7,40 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayBusiness.Utilities
/// <summary> /// <summary>
/// SM3 算法工具类。 /// SM3 算法工具类。
/// </summary> /// </summary>
public static class SM3Utility public static partial class SM3Utility
{
/// <summary>
/// 获取 SM3 哈希值。
/// </summary>
/// <param name="bytes">信息字节数组。</param>
/// <returns>哈希字节数组。</returns>
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;
}
/// <summary>
/// 获取 SM3 哈希值。
/// </summary>
/// <param name="message">文本信息。</param>
/// <returns>哈希值。</returns>
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 internal static class BitOperator
{ {
@@ -336,35 +369,5 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayBusiness.Utilities
return DIGEST_LENGTH; return DIGEST_LENGTH;
} }
} }
/// <summary>
/// 获取 SM3 哈希值。
/// </summary>
/// <param name="bytes">信息字节数组。</param>
/// <returns>哈希字节数组。</returns>
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;
}
/// <summary>
/// 获取 SM3 哈希值。
/// </summary>
/// <param name="message">文本信息。</param>
/// <returns>哈希值。</returns>
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);
}
} }
} }

View File

@@ -7,7 +7,40 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Utilities
/// <summary> /// <summary>
/// SM3 算法工具类。 /// SM3 算法工具类。
/// </summary> /// </summary>
public static class SM3Utility public static partial class SM3Utility
{
/// <summary>
/// 获取 SM3 哈希值。
/// </summary>
/// <param name="bytes">信息字节数组。</param>
/// <returns>哈希字节数组。</returns>
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;
}
/// <summary>
/// 获取 SM3 哈希值。
/// </summary>
/// <param name="message">文本信息。</param>
/// <returns>哈希值。</returns>
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 internal static class BitOperator
{ {
@@ -336,35 +369,5 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Utilities
return DIGEST_LENGTH; return DIGEST_LENGTH;
} }
} }
/// <summary>
/// 获取 SM3 哈希值。
/// </summary>
/// <param name="bytes">信息字节数组。</param>
/// <returns>哈希字节数组。</returns>
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;
}
/// <summary>
/// 获取 SM3 哈希值。
/// </summary>
/// <param name="message">文本信息。</param>
/// <returns>哈希值。</returns>
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);
}
} }
} }