feat(core): 抽离公共的算法工具类

This commit is contained in:
Fu Diwei
2021-06-07 00:28:00 +08:00
parent 9887745358
commit f887778282
15 changed files with 141 additions and 61 deletions

View File

@@ -56,10 +56,10 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
{ {
try try
{ {
plainJson = Utilities.AesUtil.DecryptWithGCM( plainJson = Utilities.AESUtility.DecryptWithGCM(
aesKey: client.MerchantV3Secret, key: client.MerchantV3Secret,
nonce: resource.Nonce, iv: resource.Nonce,
associatedData: resource.AssociatedData, aad: resource.AssociatedData,
cipherText: resource.CipherText cipherText: resource.CipherText
); );
} }

View File

@@ -33,7 +33,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
request.FileName = Guid.NewGuid().ToString("N").ToLower() + ".png"; request.FileName = Guid.NewGuid().ToString("N").ToLower() + ".png";
if (string.IsNullOrEmpty(request.FileHash)) if (string.IsNullOrEmpty(request.FileHash))
request.FileHash = Utilities.Sha256Util.Hash(request.FileBytes).ToLower(); request.FileHash = Security.SHA256Utility.Hash(request.FileBytes).ToLower();
if (string.IsNullOrEmpty(request.FileContentType)) if (string.IsNullOrEmpty(request.FileContentType))
{ {

View File

@@ -33,7 +33,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
request.FileName = Guid.NewGuid().ToString("N").ToLower() + ".png"; request.FileName = Guid.NewGuid().ToString("N").ToLower() + ".png";
if (string.IsNullOrEmpty(request.FileHash)) if (string.IsNullOrEmpty(request.FileHash))
request.FileHash = Utilities.Sha256Util.Hash(request.FileBytes).ToLower(); request.FileHash = Security.SHA256Utility.Hash(request.FileBytes).ToLower();
if (string.IsNullOrEmpty(request.FileContentType)) if (string.IsNullOrEmpty(request.FileContentType))
{ {
@@ -81,7 +81,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
request.FileName = Guid.NewGuid().ToString("N").ToLower() + ".mp4"; request.FileName = Guid.NewGuid().ToString("N").ToLower() + ".mp4";
if (string.IsNullOrEmpty(request.FileHash)) if (string.IsNullOrEmpty(request.FileHash))
request.FileHash = Utilities.Sha256Util.Hash(request.FileBytes).ToLower(); request.FileHash = Security.SHA256Utility.Hash(request.FileBytes).ToLower();
if (string.IsNullOrEmpty(request.FileContentType)) if (string.IsNullOrEmpty(request.FileContentType))
{ {

View File

@@ -244,7 +244,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
request.FileName = Guid.NewGuid().ToString("N").ToLower() + ".png"; request.FileName = Guid.NewGuid().ToString("N").ToLower() + ".png";
if (string.IsNullOrEmpty(request.FileHash)) if (string.IsNullOrEmpty(request.FileHash))
request.FileHash = Utilities.Sha256Util.Hash(request.FileBytes).ToLower(); request.FileHash = Security.SHA256Utility.Hash(request.FileBytes).ToLower();
if (string.IsNullOrEmpty(request.FileContentType)) if (string.IsNullOrEmpty(request.FileContentType))
{ {

View File

@@ -42,7 +42,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
string timestamp = DateTimeOffset.Now.ToLocalTime().ToUnixTimeSeconds().ToString(); string timestamp = DateTimeOffset.Now.ToLocalTime().ToUnixTimeSeconds().ToString();
string nonce = Guid.NewGuid().ToString("N"); string nonce = Guid.NewGuid().ToString("N");
string package = $"prepay_id={prepayId}"; string package = $"prepay_id={prepayId}";
string sign = Utilities.RsaUtil.SignWithSHA256( string sign = Utilities.RSAUtility.SignWithSHA256(
privateKey: client.MerchantCertPrivateKey, privateKey: client.MerchantCertPrivateKey,
plainText: $"{appId}\n{timestamp}\n{nonce}\n{package}" plainText: $"{appId}\n{timestamp}\n{nonce}\n{package}"
); );
@@ -97,7 +97,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
string timestamp = DateTimeOffset.Now.ToLocalTime().ToUnixTimeSeconds().ToString(); string timestamp = DateTimeOffset.Now.ToLocalTime().ToUnixTimeSeconds().ToString();
string nonce = Guid.NewGuid().ToString("N"); string nonce = Guid.NewGuid().ToString("N");
string sign = Utilities.RsaUtil.SignWithSHA256( string sign = Utilities.RSAUtility.SignWithSHA256(
privateKey: client.MerchantCertPrivateKey, privateKey: client.MerchantCertPrivateKey,
plainText: $"{appId}\n{timestamp}\n{nonce}\n{prepayId}" plainText: $"{appId}\n{timestamp}\n{nonce}\n{prepayId}"
); );

View File

@@ -38,7 +38,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
{ {
try try
{ {
accountValidationModel.AccountNameEncryptedData = Utilities.RsaUtil.DecryptWithECB( accountValidationModel.AccountNameEncryptedData = Utilities.RSAUtility.DecryptWithECB(
client.MerchantCertPrivateKey, client.MerchantCertPrivateKey,
accountValidationModel.AccountNameEncryptedData accountValidationModel.AccountNameEncryptedData
); );
@@ -53,7 +53,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
{ {
try try
{ {
accountValidationModel.AccountNumberEncryptedData = Utilities.RsaUtil.DecryptWithECB( accountValidationModel.AccountNumberEncryptedData = Utilities.RSAUtility.DecryptWithECB(
client.MerchantCertPrivateKey, client.MerchantCertPrivateKey,
accountValidationModel.AccountNumberEncryptedData! accountValidationModel.AccountNumberEncryptedData!
); );
@@ -100,7 +100,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
{ {
try try
{ {
downloadBillModel.EncryptKeyEncryptedData = Utilities.RsaUtil.DecryptWithECB( downloadBillModel.EncryptKeyEncryptedData = Utilities.RSAUtility.DecryptWithECB(
client.MerchantCertPrivateKey, client.MerchantCertPrivateKey,
downloadBillModel.EncryptKeyEncryptedData downloadBillModel.EncryptKeyEncryptedData
); );
@@ -144,7 +144,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
{ {
try try
{ {
response.PayerPhoneEncryptedData = Utilities.RsaUtil.DecryptWithECB( response.PayerPhoneEncryptedData = Utilities.RSAUtility.DecryptWithECB(
client.MerchantCertPrivateKey, client.MerchantCertPrivateKey,
response.PayerPhoneEncryptedData! response.PayerPhoneEncryptedData!
); );
@@ -188,10 +188,10 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
{ {
try try
{ {
certificateModel.EncryptCertificate.CipherText = Utilities.AesUtil.DecryptWithGCM( certificateModel.EncryptCertificate.CipherText = Utilities.AESUtility.DecryptWithGCM(
aesKey: client.MerchantV3Secret, key: client.MerchantV3Secret,
nonce: certificateModel.EncryptCertificate.Nonce, iv: certificateModel.EncryptCertificate.Nonce,
associatedData: certificateModel.EncryptCertificate.AssociatedData, aad: certificateModel.EncryptCertificate.AssociatedData,
cipherText: certificateModel.EncryptCertificate.CipherText cipherText: certificateModel.EncryptCertificate.CipherText
); );
} }
@@ -242,7 +242,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
{ {
try try
{ {
complaintModel.PayerPhoneEncryptedData = Utilities.RsaUtil.DecryptWithECB( complaintModel.PayerPhoneEncryptedData = Utilities.RSAUtility.DecryptWithECB(
client.MerchantCertPrivateKey, client.MerchantCertPrivateKey,
complaintModel.PayerPhoneEncryptedData! complaintModel.PayerPhoneEncryptedData!
); );
@@ -290,7 +290,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
{ {
try try
{ {
guideModel.UserNameEncryptedData = Utilities.RsaUtil.DecryptWithECB( guideModel.UserNameEncryptedData = Utilities.RSAUtility.DecryptWithECB(
client.MerchantCertPrivateKey, client.MerchantCertPrivateKey,
guideModel.UserNameEncryptedData guideModel.UserNameEncryptedData
); );
@@ -305,7 +305,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
{ {
try try
{ {
guideModel.UserMobileEncryptedData = Utilities.RsaUtil.DecryptWithECB( guideModel.UserMobileEncryptedData = Utilities.RSAUtility.DecryptWithECB(
client.MerchantCertPrivateKey, client.MerchantCertPrivateKey,
guideModel.UserMobileEncryptedData guideModel.UserMobileEncryptedData
); );

View File

@@ -27,7 +27,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
try try
{ {
return Utilities.RsaUtil.VerifyWithSHA256( return Utilities.RSAUtility.VerifyWithSHA256(
publicKey: publicKey, publicKey: publicKey,
plainText: GetPlainTextForSignature(response), plainText: GetPlainTextForSignature(response),
signature: response.WechatpaySignature signature: response.WechatpaySignature
@@ -58,7 +58,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
try try
{ {
return Utilities.RsaUtil.VerifyWithSHA256ByCertificate( return Utilities.RSAUtility.VerifyWithSHA256ByCertificate(
certificate: certificate, certificate: certificate,
plainText: GetPlainTextForSignature(response), plainText: GetPlainTextForSignature(response),
signature: response.WechatpaySignature signature: response.WechatpaySignature

View File

@@ -54,7 +54,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Interceptors
{ {
try try
{ {
signText = Utilities.RsaUtil.SignWithSHA256(_mchCertPk, plainText); signText = Utilities.RSAUtility.SignWithSHA256(_mchCertPk, plainText);
} }
catch (Exception ex) catch (Exception ex)
{ {

View File

@@ -9,32 +9,32 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Utilities
/// <summary> /// <summary>
/// AES 算法工具类。 /// AES 算法工具类。
/// </summary> /// </summary>
public static class AesUtil public static class AESUtility
{ {
private const int AES_TAG_LENGH_BIT = 128; private const int AES_BLOCK_SIZE = 128;
private const string AES_GCM_CIPHER_ALG = "AES/GCM/NoPadding"; private const string AES_GCM_CIPHER_ALG = "AES/GCM/NoPadding";
/// <summary> /// <summary>
/// 基于 GCM 模式解密数据。 /// 基于 GCM 模式解密数据。
/// </summary> /// </summary>
/// <param name="aesKeyBytes">AES 密钥字节数组。</param> /// <param name="keyBytes">AES 密钥字节数组。</param>
/// <param name="associatedDataBytes">附加数据包字节数组。</param> /// <param name="ivBytes">加密使用的初始化向量字节数组。</param>
/// <param name="nonceBytes">加密使用的随机串初始化向量字节数组。</param> /// <param name="aadBytes">加密使用的附加数据包字节数组。</param>
/// <param name="cipherBytes">待解密数据字节数组。</param> /// <param name="cipherBytes">待解密数据字节数组。</param>
/// <returns>解密后的数据字节数组。</returns> /// <returns>解密后的数据字节数组。</returns>
public static byte[] DecryptWithGCM(byte[] aesKeyBytes, byte[] nonceBytes, byte[] associatedDataBytes, byte[] cipherBytes) public static byte[] DecryptWithGCM(byte[] keyBytes, byte[] ivBytes, byte[] aadBytes, byte[] cipherBytes)
{ {
if (aesKeyBytes == null) throw new ArgumentNullException(nameof(aesKeyBytes)); if (keyBytes == null) throw new ArgumentNullException(nameof(keyBytes));
if (nonceBytes == null) throw new ArgumentNullException(nameof(nonceBytes)); if (ivBytes == null) throw new ArgumentNullException(nameof(ivBytes));
if (associatedDataBytes == null) throw new ArgumentNullException(nameof(associatedDataBytes)); if (aadBytes == null) throw new ArgumentNullException(nameof(aadBytes));
if (cipherBytes == null) throw new ArgumentNullException(nameof(cipherBytes)); if (cipherBytes == null) throw new ArgumentNullException(nameof(cipherBytes));
IBufferedCipher cipher = CipherUtilities.GetCipher(AES_GCM_CIPHER_ALG); IBufferedCipher cipher = CipherUtilities.GetCipher(AES_GCM_CIPHER_ALG);
ICipherParameters aeadParams = new AeadParameters( ICipherParameters aeadParams = new AeadParameters(
new KeyParameter(aesKeyBytes), new KeyParameter(keyBytes),
AES_TAG_LENGH_BIT, AES_BLOCK_SIZE,
nonceBytes, ivBytes,
associatedDataBytes aadBytes
); );
cipher.Init(false, aeadParams); cipher.Init(false, aeadParams);
byte[] plainBytes = new byte[cipher.GetOutputSize(cipherBytes.Length)]; byte[] plainBytes = new byte[cipher.GetOutputSize(cipherBytes.Length)];
@@ -46,21 +46,21 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Utilities
/// <summary> /// <summary>
/// 基于 GCM 模式解密数据。 /// 基于 GCM 模式解密数据。
/// </summary> /// </summary>
/// <param name="aesKey">AES 密钥。</param> /// <param name="key">AES 密钥。</param>
/// <param name="nonce">加密使用的随机串初始化向量。</param> /// <param name="iv">加密使用的初始化向量。</param>
/// <param name="associatedData">附加数据包。</param> /// <param name="aad">加密使用的附加数据包。</param>
/// <param name="cipherText">经 Base64 编码后的待解密数据。</param> /// <param name="cipherText">经 Base64 编码后的待解密数据。</param>
/// <returns>解密后的文本数据。</returns> /// <returns>解密后的文本数据。</returns>
public static string DecryptWithGCM(string aesKey, string nonce, string? associatedData, string cipherText) public static string DecryptWithGCM(string key, string iv, string? aad, string cipherText)
{ {
if (aesKey == null) throw new ArgumentNullException(nameof(aesKey)); if (key == null) throw new ArgumentNullException(nameof(key));
if (nonce == null) throw new ArgumentNullException(nameof(nonce)); if (iv == null) throw new ArgumentNullException(nameof(iv));
if (cipherText == null) throw new ArgumentNullException(nameof(cipherText)); if (cipherText == null) throw new ArgumentNullException(nameof(cipherText));
byte[] plainBytes = DecryptWithGCM( byte[] plainBytes = DecryptWithGCM(
aesKeyBytes: Encoding.UTF8.GetBytes(aesKey), keyBytes: Encoding.UTF8.GetBytes(key),
nonceBytes: Encoding.UTF8.GetBytes(nonce), ivBytes: Encoding.UTF8.GetBytes(iv),
associatedDataBytes: Encoding.UTF8.GetBytes(associatedData ?? string.Empty), aadBytes: Encoding.UTF8.GetBytes(aad ?? string.Empty),
cipherBytes: Convert.FromBase64String(cipherText) cipherBytes: Convert.FromBase64String(cipherText)
); );
return Encoding.UTF8.GetString(plainBytes); return Encoding.UTF8.GetString(plainBytes);

View File

@@ -13,7 +13,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Utilities
/// <summary> /// <summary>
/// RSA 算法工具类。 /// RSA 算法工具类。
/// </summary> /// </summary>
public static class RsaUtil public static class RSAUtility
{ {
// REF: https://github.com/bcgit/bc-csharp/blob/master/crypto/src/security/CipherUtilities.cs // REF: https://github.com/bcgit/bc-csharp/blob/master/crypto/src/security/CipherUtilities.cs
private const string RSA_CIPHER_ALG = "RSA/ECB/PKCS1"; private const string RSA_CIPHER_ALG = "RSA/ECB/PKCS1";
@@ -91,7 +91,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Utilities
/// <summary> /// <summary>
/// 使用证书基于 SHA-256 算法验证签名。 /// 使用证书基于 SHA-256 算法验证签名。
/// </summary> /// </summary>
/// <param name="publicKey">证书cer 格式)。</param> /// <param name="certificate">证书cer 格式)。</param>
/// <param name="plainText">待验证的文本数据。</param> /// <param name="plainText">待验证的文本数据。</param>
/// <param name="signature">经 Base64 编码的待验证的签名。</param> /// <param name="signature">经 Base64 编码的待验证的签名。</param>
/// <returns>验证结果。</returns> /// <returns>验证结果。</returns>

View File

@@ -0,0 +1,44 @@
using System;
using System.Security.Cryptography;
using System.Text;
namespace SKIT.FlurlHttpClient.Wechat.Security
{
/// <summary>
/// HMAC-SHA-1 算法工具类。
/// </summary>
public static class HMACSHA1Utility
{
/// <summary>
/// 获取信息摘要。
/// </summary>
/// <param name="secretBytes">密钥字节数组。</param>
/// <param name="bytes">信息字节数组。</param>
/// <returns>信息摘要。</returns>
public static string Hash(byte[] secretBytes, byte[] bytes)
{
if (secretBytes == null) throw new ArgumentNullException(nameof(secretBytes));
if (bytes == null) throw new ArgumentNullException(nameof(bytes));
using HMAC hmac = new HMACSHA1(secretBytes);
byte[] hashBytes = hmac.ComputeHash(bytes);
return BitConverter.ToString(hashBytes).Replace("-", "");
}
/// <summary>
/// 获取信息摘要。
/// </summary>
/// <param name="secret">密钥。</param>
/// <param name="message">文本信息。</param>
/// <returns>信息摘要。</returns>
public static string Hash(string secret, string message)
{
if (secret == null) throw new ArgumentNullException(nameof(secret));
if (message == null) throw new ArgumentNullException(nameof(message));
byte[] secretBytes = Encoding.UTF8.GetBytes(secret);
byte[] bytes = Encoding.UTF8.GetBytes(message);
return Hash(secretBytes, bytes);
}
}
}

View File

@@ -2,12 +2,12 @@
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Text; using System.Text;
namespace SKIT.FlurlHttpClient.Wechat.Api.Utilities namespace SKIT.FlurlHttpClient.Wechat.Security
{ {
/// <summary> /// <summary>
/// HMAC-SHA-1 算法工具类。 /// HMAC-SHA-256 算法工具类。
/// </summary> /// </summary>
public static class HmacSha256Util public static class HMACSHA256Utility
{ {
/// <summary> /// <summary>
/// 获取信息摘要。 /// 获取信息摘要。

View File

@@ -0,0 +1,39 @@
using System;
using System.Security.Cryptography;
using System.Text;
namespace SKIT.FlurlHttpClient.Wechat.Security
{
/// <summary>
/// MD5 算法工具类。
/// </summary>
public static class MD5Utility
{
/// <summary>
/// 获取信息摘要。
/// </summary>
/// <param name="bytes">信息字节数组。</param>
/// <returns>信息摘要。</returns>
public static string Hash(byte[] bytes)
{
if (bytes == null) throw new ArgumentNullException(nameof(bytes));
using MD5 md5 = MD5.Create();
byte[] hashBytes = md5.ComputeHash(bytes);
return BitConverter.ToString(hashBytes).Replace("-", "");
}
/// <summary>
/// 获取信息摘要。
/// </summary>
/// <param name="message">文本信息。</param>
/// <returns>信息摘要。</returns>
public static string Hash(string message)
{
if (message == null) throw new ArgumentNullException(nameof(message));
byte[] bytes = Encoding.UTF8.GetBytes(message);
return Hash(bytes);
}
}
}

View File

@@ -2,12 +2,12 @@
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Text; using System.Text;
namespace SKIT.FlurlHttpClient.Wechat.Api.Utilities namespace SKIT.FlurlHttpClient.Wechat.Security
{ {
/// <summary> /// <summary>
/// SHA-1 算法工具类。 /// SHA-1 算法工具类。
/// </summary> /// </summary>
public static class Sha1Util public static class SHA1Utility
{ {
/// <summary> /// <summary>
/// 获取信息摘要。 /// 获取信息摘要。

View File

@@ -1,14 +1,13 @@
using System; using System;
using System.Security.Cryptography;
using System.Text; using System.Text;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Digests;
namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Utilities namespace SKIT.FlurlHttpClient.Wechat.Security
{ {
/// <summary> /// <summary>
/// SHA-256 算法工具类。 /// SHA-256 算法工具类。
/// </summary> /// </summary>
public static class Sha256Util public static class SHA256Utility
{ {
/// <summary> /// <summary>
/// 获取信息摘要。 /// 获取信息摘要。
@@ -19,10 +18,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Utilities
{ {
if (bytes == null) throw new ArgumentNullException(nameof(bytes)); if (bytes == null) throw new ArgumentNullException(nameof(bytes));
IDigest digest = new Sha256Digest(); using SHA256 sha = SHA256.Create();
byte[] hashBytes = new byte[digest.GetDigestSize()]; byte[] hashBytes = sha.ComputeHash(bytes);
digest.BlockUpdate(bytes, 0, bytes.Length);
digest.DoFinal(hashBytes, 0);
return BitConverter.ToString(hashBytes).Replace("-", ""); return BitConverter.ToString(hashBytes).Replace("-", "");
} }