mirror of
https://gitee.com/fudiwei/DotNetCore.SKIT.FlurlHttpClient.Wechat.git
synced 2025-04-05 17:37:54 +08:00
refactor: 在 .NET 5.0+ 目标框架下将 AES、RSA 算法工具类的部分实现使用标准库原生方式重写
This commit is contained in:
parent
7fff2b70ec
commit
916acb727a
@ -88,31 +88,38 @@ namespace SKIT.FlurlHttpClient.Wechat.Api.Utilities
|
||||
if (cipherBytes.Length < TAG_LENGTH_BYTE) throw new ArgumentException($"Invalid cipher byte length (expected: more than {TAG_LENGTH_BYTE}, actual: {cipherBytes.Length}).", nameof(cipherBytes));
|
||||
|
||||
#if NET5_0_OR_GREATER
|
||||
using (AesGcm aes = new AesGcm(keyBytes))
|
||||
if (AesGcm.IsSupported)
|
||||
{
|
||||
byte[] cipherWithoutTagBytes = new byte[cipherBytes.Length - TAG_LENGTH_BYTE];
|
||||
byte[] tagBytes = new byte[TAG_LENGTH_BYTE];
|
||||
Buffer.BlockCopy(cipherBytes, 0, cipherWithoutTagBytes, 0, cipherWithoutTagBytes.Length);
|
||||
Buffer.BlockCopy(cipherBytes, cipherWithoutTagBytes.Length, tagBytes, 0, tagBytes.Length);
|
||||
if (!string.Equals(paddingMode, PADDING_MODE_NOPADDING, StringComparison.OrdinalIgnoreCase))
|
||||
throw new NotSupportedException();
|
||||
|
||||
byte[] plainBytes = new byte[cipherWithoutTagBytes.Length];
|
||||
aes.Decrypt(nonceBytes, cipherWithoutTagBytes, tagBytes, plainBytes, associatedDataBytes);
|
||||
using (AesGcm aes = new AesGcm(keyBytes))
|
||||
{
|
||||
byte[] cipherWithoutTagBytes = new byte[cipherBytes.Length - TAG_LENGTH_BYTE];
|
||||
byte[] tagBytes = new byte[TAG_LENGTH_BYTE];
|
||||
Buffer.BlockCopy(cipherBytes, 0, cipherWithoutTagBytes, 0, cipherWithoutTagBytes.Length);
|
||||
Buffer.BlockCopy(cipherBytes, cipherWithoutTagBytes.Length, tagBytes, 0, tagBytes.Length);
|
||||
|
||||
byte[] plainBytes = new byte[cipherWithoutTagBytes.Length];
|
||||
aes.Decrypt(nonceBytes, cipherWithoutTagBytes, tagBytes, plainBytes, associatedDataBytes);
|
||||
return plainBytes;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
{
|
||||
IBufferedCipher cipher = CipherUtilities.GetCipher($"AES/GCM/{paddingMode}");
|
||||
ICipherParameters cipherParams = new AeadParameters(
|
||||
new KeyParameter(keyBytes),
|
||||
TAG_LENGTH_BYTE * 8,
|
||||
nonceBytes,
|
||||
associatedDataBytes
|
||||
);
|
||||
cipher.Init(false, cipherParams);
|
||||
byte[] plainBytes = new byte[cipher.GetOutputSize(cipherBytes.Length)];
|
||||
int len = cipher.ProcessBytes(cipherBytes, 0, cipherBytes.Length, plainBytes, 0);
|
||||
cipher.DoFinal(plainBytes, len);
|
||||
return plainBytes;
|
||||
}
|
||||
#else
|
||||
IBufferedCipher cipher = CipherUtilities.GetCipher($"AES/GCM/{paddingMode}");
|
||||
ICipherParameters cipherParams = new AeadParameters(
|
||||
new KeyParameter(keyBytes),
|
||||
TAG_LENGTH_BYTE * 8,
|
||||
nonceBytes,
|
||||
associatedDataBytes
|
||||
);
|
||||
cipher.Init(false, cipherParams);
|
||||
byte[] plainBytes = new byte[cipher.GetOutputSize(cipherBytes.Length)];
|
||||
int len = cipher.ProcessBytes(cipherBytes, 0, cipherBytes.Length, plainBytes, 0);
|
||||
cipher.DoFinal(plainBytes, len);
|
||||
return plainBytes;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -204,32 +211,38 @@ namespace SKIT.FlurlHttpClient.Wechat.Api.Utilities
|
||||
if (plainBytes is null) throw new ArgumentNullException(nameof(plainBytes));
|
||||
|
||||
#if NET5_0_OR_GREATER
|
||||
using (AesGcm aes = new AesGcm(keyBytes))
|
||||
if (AesGcm.IsSupported)
|
||||
{
|
||||
byte[] cipherBytes = new byte[plainBytes.Length];
|
||||
byte[] tagBytes = new byte[TAG_LENGTH_BYTE];
|
||||
aes.Encrypt(nonceBytes, plainBytes, cipherBytes, tagBytes, associatedDataBytes);
|
||||
if (!string.Equals(paddingMode, PADDING_MODE_NOPADDING, StringComparison.OrdinalIgnoreCase))
|
||||
throw new NotSupportedException();
|
||||
|
||||
byte[] cipherWithTagBytes = new byte[cipherBytes.Length + tagBytes.Length];
|
||||
Buffer.BlockCopy(cipherBytes, 0, cipherWithTagBytes, 0, cipherBytes.Length);
|
||||
Buffer.BlockCopy(tagBytes, 0, cipherWithTagBytes, cipherBytes.Length, tagBytes.Length);
|
||||
return cipherWithTagBytes;
|
||||
using (AesGcm aes = new AesGcm(keyBytes))
|
||||
{
|
||||
byte[] cipherBytes = new byte[plainBytes.Length];
|
||||
byte[] tagBytes = new byte[TAG_LENGTH_BYTE];
|
||||
aes.Encrypt(nonceBytes, plainBytes, cipherBytes, tagBytes, associatedDataBytes);
|
||||
|
||||
byte[] cipherWithTagBytes = new byte[cipherBytes.Length + tagBytes.Length];
|
||||
Buffer.BlockCopy(cipherBytes, 0, cipherWithTagBytes, 0, cipherBytes.Length);
|
||||
Buffer.BlockCopy(tagBytes, 0, cipherWithTagBytes, cipherBytes.Length, tagBytes.Length);
|
||||
return cipherWithTagBytes;
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
||||
IBufferedCipher cipher = CipherUtilities.GetCipher($"AES/GCM/{paddingMode}");
|
||||
ICipherParameters cipherParams = new AeadParameters(
|
||||
new KeyParameter(keyBytes),
|
||||
TAG_LENGTH_BYTE * 8,
|
||||
nonceBytes,
|
||||
associatedDataBytes
|
||||
);
|
||||
cipher.Init(true, cipherParams);
|
||||
byte[] cipherBytes = new byte[cipher.GetOutputSize(plainBytes.Length)];
|
||||
int len = cipher.ProcessBytes(plainBytes, 0, plainBytes.Length, cipherBytes, 0);
|
||||
cipher.DoFinal(cipherBytes, len);
|
||||
return cipherBytes;
|
||||
#endif
|
||||
{
|
||||
IBufferedCipher cipher = CipherUtilities.GetCipher($"AES/GCM/{paddingMode}");
|
||||
ICipherParameters cipherParams = new AeadParameters(
|
||||
new KeyParameter(keyBytes),
|
||||
TAG_LENGTH_BYTE * 8,
|
||||
nonceBytes,
|
||||
associatedDataBytes
|
||||
);
|
||||
cipher.Init(true, cipherParams);
|
||||
byte[] cipherBytes = new byte[cipher.GetOutputSize(plainBytes.Length)];
|
||||
int len = cipher.ProcessBytes(plainBytes, 0, plainBytes.Length, cipherBytes, 0);
|
||||
cipher.DoFinal(cipherBytes, len);
|
||||
return cipherBytes;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -23,7 +23,10 @@ namespace SKIT.FlurlHttpClient.Wechat.Api.Utilities
|
||||
|
||||
private static byte[] ConvertPrivateKeyPemToByteArray(string privateKeyPem)
|
||||
{
|
||||
if (!privateKeyPem.StartsWith("-----BEGIN PRIVATE KEY-----"))
|
||||
const string PKCS8_HEADER = "-----BEGIN PRIVATE KEY-----";
|
||||
const string PKCS8_FOOTER = "-----END PRIVATE KEY-----";
|
||||
|
||||
if (!privateKeyPem.StartsWith(PKCS8_HEADER))
|
||||
{
|
||||
using (TextReader textReader = new StringReader(privateKeyPem))
|
||||
using (PemReader pemReader = new PemReader(textReader))
|
||||
@ -56,15 +59,18 @@ namespace SKIT.FlurlHttpClient.Wechat.Api.Utilities
|
||||
}
|
||||
|
||||
privateKeyPem = privateKeyPem
|
||||
.Replace("-----BEGIN PRIVATE KEY-----", string.Empty)
|
||||
.Replace("-----END PRIVATE KEY-----", string.Empty);
|
||||
.Replace(PKCS8_HEADER, string.Empty)
|
||||
.Replace(PKCS8_FOOTER, string.Empty);
|
||||
privateKeyPem = Regex.Replace(privateKeyPem, "\\s+", string.Empty);
|
||||
return Convert.FromBase64String(privateKeyPem);
|
||||
}
|
||||
|
||||
private static byte[] ConvertPublicKeyPemToByteArray(string publicKeyPem)
|
||||
{
|
||||
if (!publicKeyPem.StartsWith("-----BEGIN PUBLIC KEY-----"))
|
||||
const string PKCS8_HEADER = "-----BEGIN PUBLIC KEY-----";
|
||||
const string PKCS8_FOOTER = "-----END PUBLIC KEY-----";
|
||||
|
||||
if (!publicKeyPem.StartsWith(PKCS8_HEADER))
|
||||
{
|
||||
using (TextReader textReader = new StringReader(publicKeyPem))
|
||||
using (PemReader pemReader = new PemReader(textReader))
|
||||
@ -91,8 +97,8 @@ namespace SKIT.FlurlHttpClient.Wechat.Api.Utilities
|
||||
}
|
||||
|
||||
publicKeyPem = publicKeyPem
|
||||
.Replace("-----BEGIN PUBLIC KEY-----", string.Empty)
|
||||
.Replace("-----END PUBLIC KEY-----", string.Empty);
|
||||
.Replace(PKCS8_HEADER, string.Empty)
|
||||
.Replace(PKCS8_FOOTER, string.Empty);
|
||||
publicKeyPem = Regex.Replace(publicKeyPem, "\\s+", string.Empty);
|
||||
return Convert.FromBase64String(publicKeyPem);
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayBusiness
|
||||
break;
|
||||
}
|
||||
|
||||
bool valid = Utilities.RSAUtility.Verify(
|
||||
bool valid = Utilities.RSAUtility.VerifyWithSHA256(
|
||||
publicKeyPem: client.Credentials.TBEPCertificatePublicKey,
|
||||
messageData: GenerateMessageForSignature(timestamp: strTimestamp, nonce: strNonce, body: strContent),
|
||||
encodingSignature: new EncodedString(strSignature, EncodingKinds.Base64)
|
||||
|
@ -75,13 +75,13 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayBusiness.Interceptors
|
||||
{
|
||||
try
|
||||
{
|
||||
sign = Utilities.RSAUtility.Sign(_platformCertPk, signData).Value!;
|
||||
sign = Utilities.RSAUtility.SignWithSHA256(_platformCertPk, signData).Value!;
|
||||
|
||||
if (softSignRequired)
|
||||
{
|
||||
byte[] keyBytes = EncodedString.FromBase64String(_enterpriseCertPk!);
|
||||
byte[] msgBytes = EncodedString.FromBase64String(sign);
|
||||
softSign = EncodedString.ToBase64String(Utilities.RSAUtility.Sign(keyBytes, msgBytes)).Value!;
|
||||
softSign = EncodedString.ToBase64String(Utilities.RSAUtility.SignWithSHA256(keyBytes, msgBytes)).Value!;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text.RegularExpressions;
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
@ -23,11 +24,14 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayBusiness.Utilities
|
||||
/// <summary>
|
||||
/// 签名算法:SHA-256withRSA。
|
||||
/// </summary>
|
||||
public const string DIGEST_ALGORITHM_SHA256 = "SHA-256withRSA";
|
||||
private const string DIGEST_ALGORITHM_SHA256 = "SHA-256withRSA";
|
||||
|
||||
private static byte[] ConvertPrivateKeyPemToByteArray(string privateKeyPem)
|
||||
{
|
||||
if (!privateKeyPem.StartsWith("-----BEGIN PRIVATE KEY-----"))
|
||||
const string PKCS8_HEADER = "-----BEGIN PRIVATE KEY-----";
|
||||
const string PKCS8_FOOTER = "-----END PRIVATE KEY-----";
|
||||
|
||||
if (!privateKeyPem.StartsWith(PKCS8_HEADER))
|
||||
{
|
||||
using (TextReader textReader = new StringReader(privateKeyPem))
|
||||
using (PemReader pemReader = new PemReader(textReader))
|
||||
@ -60,15 +64,18 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayBusiness.Utilities
|
||||
}
|
||||
|
||||
privateKeyPem = privateKeyPem
|
||||
.Replace("-----BEGIN PRIVATE KEY-----", string.Empty)
|
||||
.Replace("-----END PRIVATE KEY-----", string.Empty);
|
||||
.Replace(PKCS8_HEADER, string.Empty)
|
||||
.Replace(PKCS8_FOOTER, string.Empty);
|
||||
privateKeyPem = Regex.Replace(privateKeyPem, "\\s+", string.Empty);
|
||||
return Convert.FromBase64String(privateKeyPem);
|
||||
}
|
||||
|
||||
private static byte[] ConvertPublicKeyPemToByteArray(string publicKeyPem)
|
||||
{
|
||||
if (!publicKeyPem.StartsWith("-----BEGIN PUBLIC KEY-----"))
|
||||
const string PKCS8_HEADER = "-----BEGIN PUBLIC KEY-----";
|
||||
const string PKCS8_FOOTER = "-----END PUBLIC KEY-----";
|
||||
|
||||
if (!publicKeyPem.StartsWith(PKCS8_HEADER))
|
||||
{
|
||||
using (TextReader textReader = new StringReader(publicKeyPem))
|
||||
using (PemReader pemReader = new PemReader(textReader))
|
||||
@ -95,8 +102,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayBusiness.Utilities
|
||||
}
|
||||
|
||||
publicKeyPem = publicKeyPem
|
||||
.Replace("-----BEGIN PUBLIC KEY-----", string.Empty)
|
||||
.Replace("-----END PUBLIC KEY-----", string.Empty);
|
||||
.Replace(PKCS8_HEADER, string.Empty)
|
||||
.Replace(PKCS8_FOOTER, string.Empty);
|
||||
publicKeyPem = Regex.Replace(publicKeyPem, "\\s+", string.Empty);
|
||||
return Convert.FromBase64String(publicKeyPem);
|
||||
}
|
||||
@ -111,17 +118,17 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayBusiness.Utilities
|
||||
return (RsaKeyParameters)PublicKeyFactory.CreateKey(publicKeyBytes);
|
||||
}
|
||||
|
||||
private static byte[] Sign(RsaKeyParameters rsaPrivateKeyParams, byte[] messageBytes, string digestAlgorithm)
|
||||
private static byte[] Sign(RsaKeyParameters rsaPrivateKeyParams, byte[] messageBytes, string algorithm)
|
||||
{
|
||||
ISigner signer = SignerUtilities.GetSigner(digestAlgorithm);
|
||||
ISigner signer = SignerUtilities.GetSigner(algorithm);
|
||||
signer.Init(true, rsaPrivateKeyParams);
|
||||
signer.BlockUpdate(messageBytes, 0, messageBytes.Length);
|
||||
return signer.GenerateSignature();
|
||||
}
|
||||
|
||||
private static bool Verify(RsaKeyParameters rsaPublicKeyParams, byte[] messageBytes, byte[] signBytes, string digestAlgorithm)
|
||||
private static bool Verify(RsaKeyParameters rsaPublicKeyParams, byte[] messageBytes, byte[] signBytes, string algorithm)
|
||||
{
|
||||
ISigner signer = SignerUtilities.GetSigner(digestAlgorithm);
|
||||
ISigner signer = SignerUtilities.GetSigner(algorithm);
|
||||
signer.Init(false, rsaPublicKeyParams);
|
||||
signer.BlockUpdate(messageBytes, 0, messageBytes.Length);
|
||||
return signer.VerifySignature(signBytes);
|
||||
@ -142,66 +149,78 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayBusiness.Utilities
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用私钥生成签名。
|
||||
/// 使用私钥基于 SHA-256 算法生成签名。
|
||||
/// </summary>
|
||||
/// <param name="privateKeyBytes">PKCS#1/PKCS#8 私钥字节数组。</param>
|
||||
/// <param name="privateKeyBytes">PKCS#8 私钥字节数组。</param>
|
||||
/// <param name="messageBytes">待签名的数据字节数组。</param>
|
||||
/// <param name="digestAlgorithm">签名算法。(默认值:<see cref="DIGEST_ALGORITHM_SHA256"/>)</param>
|
||||
/// <returns>签名字节数组。</returns>
|
||||
public static byte[] Sign(byte[] privateKeyBytes, byte[] messageBytes, string digestAlgorithm = DIGEST_ALGORITHM_SHA256)
|
||||
public static byte[] SignWithSHA256(byte[] privateKeyBytes, byte[] messageBytes)
|
||||
{
|
||||
if (privateKeyBytes is null) throw new ArgumentNullException(nameof(privateKeyBytes));
|
||||
if (messageBytes is null) throw new ArgumentNullException(nameof(messageBytes));
|
||||
|
||||
#if NET5_0_OR_GREATER
|
||||
using (RSA rsa = RSA.Create())
|
||||
{
|
||||
rsa.ImportPkcs8PrivateKey(privateKeyBytes, out _);
|
||||
return rsa.SignData(messageBytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
|
||||
}
|
||||
#else
|
||||
RsaKeyParameters rsaPrivateKeyParams = ParsePrivateKeyToParameters(privateKeyBytes);
|
||||
return Sign(rsaPrivateKeyParams, messageBytes, digestAlgorithm);
|
||||
return Sign(rsaPrivateKeyParams, messageBytes, DIGEST_ALGORITHM_SHA256);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用私钥生成签名。
|
||||
/// 使用私钥基于 SHA-256 算法生成签名。
|
||||
/// </summary>
|
||||
/// <param name="privateKeyPem">PKCS#1/PKCS#8 私钥(PEM 格式)。</param>
|
||||
/// <param name="messageData">待签名的数据。</param>
|
||||
/// <param name="digestAlgorithm">签名算法。(默认值:<see cref="DIGEST_ALGORITHM_SHA256"/>)</param>
|
||||
/// <returns>经过 Base64 编码的签名。</returns>
|
||||
public static EncodedString Sign(string privateKeyPem, string messageData, string digestAlgorithm = DIGEST_ALGORITHM_SHA256)
|
||||
public static EncodedString SignWithSHA256(string privateKeyPem, string messageData)
|
||||
{
|
||||
if (privateKeyPem is null) throw new ArgumentNullException(nameof(privateKeyPem));
|
||||
if (messageData is null) throw new ArgumentNullException(nameof(messageData));
|
||||
|
||||
byte[] privateKeyBytes = ConvertPrivateKeyPemToByteArray(privateKeyPem);
|
||||
byte[] messageBytes = EncodedString.FromLiteralString(messageData);
|
||||
byte[] signBytes = Sign(privateKeyBytes, messageBytes, digestAlgorithm);
|
||||
byte[] signBytes = SignWithSHA256(privateKeyBytes, messageBytes);
|
||||
return EncodedString.ToBase64String(signBytes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用公钥验证签名。
|
||||
/// 使用公钥基于 SHA-256 算法验证签名。
|
||||
/// </summary>
|
||||
/// <param name="publicKeyBytes">PKCS#1/PKCS#8 公钥字节数组。</param>
|
||||
/// <param name="messageBytes">待验证的数据字节数组。</param>
|
||||
/// <param name="signBytes">签名字节数组。</param>
|
||||
/// <param name="digestAlgorithm">签名算法。(默认值:<see cref="DIGEST_ALGORITHM_SHA256"/>)</param>
|
||||
/// <returns>验证结果。</returns>
|
||||
public static bool Verify(byte[] publicKeyBytes, byte[] messageBytes, byte[] signBytes, string digestAlgorithm = DIGEST_ALGORITHM_SHA256)
|
||||
public static bool VerifyWithSHA256(byte[] publicKeyBytes, byte[] messageBytes, byte[] signBytes)
|
||||
{
|
||||
if (publicKeyBytes is null) throw new ArgumentNullException(nameof(publicKeyBytes));
|
||||
if (messageBytes is null) throw new ArgumentNullException(nameof(messageBytes));
|
||||
if (signBytes is null) throw new ArgumentNullException(nameof(signBytes));
|
||||
|
||||
#if NET5_0_OR_GREATER
|
||||
using (RSA rsa = RSA.Create())
|
||||
{
|
||||
rsa.ImportSubjectPublicKeyInfo(publicKeyBytes, out _);
|
||||
return rsa.VerifyData(messageBytes, signBytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
|
||||
}
|
||||
#else
|
||||
RsaKeyParameters rsaPublicKeyParams = ParsePublicKeyToParameters(publicKeyBytes);
|
||||
return Verify(rsaPublicKeyParams, messageBytes, signBytes, digestAlgorithm);
|
||||
return Verify(rsaPublicKeyParams, messageBytes, signBytes, DIGEST_ALGORITHM_SHA256);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用公钥验证签名。
|
||||
/// 使用公钥基于 SHA-256 算法验证签名。
|
||||
/// </summary>
|
||||
/// <param name="publicKeyPem">PKCS#1/PKCS#8 公钥(PEM 格式)。</param>
|
||||
/// <param name="messageData">待验证的数据。</param>
|
||||
/// <param name="encodingSignature">经过编码后的(通常为 Base64)签名。</param>
|
||||
/// <param name="digestAlgorithm">签名算法。(默认值:<see cref="DIGEST_ALGORITHM_SHA256"/>)</param>
|
||||
/// <returns>验证结果。</returns>
|
||||
public static bool Verify(string publicKeyPem, string messageData, EncodedString encodingSignature, string digestAlgorithm = DIGEST_ALGORITHM_SHA256)
|
||||
public static bool VerifyWithSHA256(string publicKeyPem, string messageData, EncodedString encodingSignature)
|
||||
{
|
||||
if (publicKeyPem is null) throw new ArgumentNullException(nameof(publicKeyPem));
|
||||
if (messageData is null) throw new ArgumentNullException(nameof(messageData));
|
||||
@ -210,13 +229,13 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayBusiness.Utilities
|
||||
byte[] publicKeyBytes = ConvertPublicKeyPemToByteArray(publicKeyPem);
|
||||
byte[] messageBytes = EncodedString.FromLiteralString(messageData);
|
||||
byte[] signBytes = EncodedString.FromString(encodingSignature, fallbackEncodingKind: EncodingKinds.Base64);
|
||||
return Verify(publicKeyBytes, messageBytes, signBytes, digestAlgorithm);
|
||||
return VerifyWithSHA256(publicKeyBytes, messageBytes, signBytes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用私钥基于 ECB 模式解密数据。
|
||||
/// </summary>
|
||||
/// <param name="privateKeyBytes">PKCS#1/PKCS#8 私钥字节数组。</param>
|
||||
/// <param name="privateKeyBytes">PKCS#8 私钥字节数组。</param>
|
||||
/// <param name="cipherBytes">待解密的数据字节数组。</param>
|
||||
/// <param name="paddingMode">填充模式。(默认值:<see cref="PADDING_MODE_OAEPWITHSHA1ANDMGF1"/>)</param>
|
||||
/// <returns>解密后的数据字节数组。</returns>
|
||||
|
@ -1,5 +1,12 @@
|
||||
using System;
|
||||
|
||||
namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.ExtendedSDK.Global
|
||||
{
|
||||
using SKIT.FlurlHttpClient.Primitives;
|
||||
using SKIT.FlurlHttpClient.Wechat.TenpayV3.Constants;
|
||||
using SKIT.FlurlHttpClient.Wechat.TenpayV3.ExtendedSDK.Global.Models;
|
||||
using SKIT.FlurlHttpClient.Wechat.TenpayV3.Utilities;
|
||||
|
||||
public static class WechatTenpayGlobalClientResponseDecryptionExtensions
|
||||
{
|
||||
/// <summary>
|
||||
@ -8,9 +15,43 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.ExtendedSDK.Global
|
||||
/// <param name="client"></param>
|
||||
/// <param name="response"></param>
|
||||
/// <returns></returns>
|
||||
public static Models.QueryCertificatesResponse DecryptResponseSensitiveProperty(this WechatTenpayGlobalClient client, Models.QueryCertificatesResponse response)
|
||||
public static QueryCertificatesResponse DecryptResponseSensitiveProperty(this WechatTenpayGlobalClient client, QueryCertificatesResponse response)
|
||||
{
|
||||
return WechatTenpayClientResponseDecryptionExtensions.DecryptResponseSensitiveProperty(client, response);
|
||||
if (client is null) throw new ArgumentNullException(nameof(client));
|
||||
if (response is null) throw new ArgumentNullException(nameof(response));
|
||||
|
||||
if (response.CertificateList is null)
|
||||
return response;
|
||||
|
||||
foreach (var certificate in response.CertificateList)
|
||||
{
|
||||
if (certificate.EncryptCertificate is null)
|
||||
continue;
|
||||
|
||||
switch (certificate.EncryptCertificate.Algorithm)
|
||||
{
|
||||
case EncryptionAlgorithms.AEAD_AES_256_GCM:
|
||||
{
|
||||
if (string.IsNullOrEmpty(client.Credentials.MerchantV3Secret))
|
||||
throw new WechatTenpayException("Failed to decrypt response, because the merchant APIv3 secret is not set.");
|
||||
|
||||
certificate.EncryptCertificate.CipherText = AESUtility.DecryptWithGCM(
|
||||
encodingKey: new EncodedString(client.Credentials.MerchantV3Secret, EncodingKinds.Literal),
|
||||
encodingNonce: new EncodedString(certificate.EncryptCertificate.Nonce, EncodingKinds.Literal),
|
||||
encodingAssociatedData: new EncodedString(certificate.EncryptCertificate.AssociatedData, EncodingKinds.Literal),
|
||||
encodingCipher: new EncodedString(certificate.EncryptCertificate.CipherText, EncodingKinds.Base64)
|
||||
)!;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
throw new WechatTenpayException($"Failed to decrypt response. Unsupported encryption algorithm: \"{certificate.EncryptCertificate.Algorithm}\".");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -22,6 +63,12 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.ExtendedSDK.Global
|
||||
public static TResponse DecryptResponseSensitiveProperty<TResponse>(this WechatTenpayGlobalClient client, TResponse response)
|
||||
where TResponse : WechatTenpayGlobalResponse
|
||||
{
|
||||
// [GET] /certificates 接口的响应模型需特殊处理
|
||||
if (response is QueryCertificatesResponse queryCertificatesResponse)
|
||||
{
|
||||
return (DecryptResponseSensitiveProperty(client, queryCertificatesResponse) as TResponse)!;
|
||||
}
|
||||
|
||||
return WechatTenpayClientResponseDecryptionExtensions.DecryptResponseSensitiveProperty(client, response);
|
||||
}
|
||||
}
|
||||
|
@ -78,10 +78,13 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.ExtendedSDK.Global
|
||||
/// <param name="httpContent"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
public new Task<T> SendFlurlRequestAsync<T>(IFlurlRequest flurlRequest, HttpContent? httpContent = null, CancellationToken cancellationToken = default)
|
||||
public async new Task<T> SendFlurlRequestAsync<T>(IFlurlRequest flurlRequest, HttpContent? httpContent = null, CancellationToken cancellationToken = default)
|
||||
where T : WechatTenpayGlobalResponse, new()
|
||||
{
|
||||
return base.SendFlurlRequestAsync<T>(flurlRequest, httpContent, cancellationToken);
|
||||
if (flurlRequest is null) throw new ArgumentNullException(nameof(flurlRequest));
|
||||
|
||||
using IFlurlResponse flurlResponse = await base.SendFlurlRequestAsync(flurlRequest, httpContent, cancellationToken).ConfigureAwait(false);
|
||||
return await WrapFlurlResponseAsJsonAsync<T>(flurlResponse, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -92,10 +95,32 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.ExtendedSDK.Global
|
||||
/// <param name="data"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
public new Task<T> SendFlurlRequestAsJsonAsync<T>(IFlurlRequest flurlRequest, object? data = null, CancellationToken cancellationToken = default)
|
||||
public async new Task<T> SendFlurlRequestAsJsonAsync<T>(IFlurlRequest flurlRequest, object? data = null, CancellationToken cancellationToken = default)
|
||||
where T : WechatTenpayGlobalResponse, new()
|
||||
{
|
||||
return base.SendFlurlRequestAsJsonAsync<T>(flurlRequest, data, cancellationToken);
|
||||
if (flurlRequest is null) throw new ArgumentNullException(nameof(flurlRequest));
|
||||
|
||||
bool isSimpleRequest = data is null ||
|
||||
flurlRequest.Verb == HttpMethod.Get ||
|
||||
flurlRequest.Verb == HttpMethod.Head ||
|
||||
flurlRequest.Verb == HttpMethod.Options;
|
||||
using IFlurlResponse flurlResponse = isSimpleRequest ?
|
||||
await base.SendFlurlRequestAsync(flurlRequest, null, cancellationToken).ConfigureAwait(false) :
|
||||
await base.SendFlurlRequestAsJsonAsync(flurlRequest, data, cancellationToken).ConfigureAwait(false);
|
||||
return await WrapFlurlResponseAsJsonAsync<T>(flurlResponse, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private new async Task<TResponse> WrapFlurlResponseAsJsonAsync<TResponse>(IFlurlResponse flurlResponse, CancellationToken cancellationToken = default)
|
||||
where TResponse : WechatTenpayGlobalResponse, new()
|
||||
{
|
||||
TResponse result = await base.WrapFlurlResponseAsJsonAsync<TResponse>(flurlResponse, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (AutoDecryptResponseSensitiveProperty && result.IsSuccessful())
|
||||
{
|
||||
this.DecryptResponseSensitiveProperty(result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
|
||||
string timestamp = DateTimeOffset.Now.ToLocalTime().ToUnixTimeSeconds().ToString();
|
||||
string nonce = Guid.NewGuid().ToString("N");
|
||||
string package = $"prepay_id={prepayId}";
|
||||
string sign = Utilities.RSAUtility.Sign(
|
||||
string sign = Utilities.RSAUtility.SignWithSHA256(
|
||||
privateKeyPem: client.Credentials.MerchantCertificatePrivateKey,
|
||||
messageData: $"{appId}\n{timestamp}\n{nonce}\n{package}\n"
|
||||
)!;
|
||||
@ -96,7 +96,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
|
||||
|
||||
string timestamp = DateTimeOffset.Now.ToLocalTime().ToUnixTimeSeconds().ToString();
|
||||
string nonce = Guid.NewGuid().ToString("N");
|
||||
string sign = Utilities.RSAUtility.Sign(
|
||||
string sign = Utilities.RSAUtility.SignWithSHA256(
|
||||
privateKeyPem: client.Credentials.MerchantCertificatePrivateKey,
|
||||
messageData: $"{appId}\n{timestamp}\n{nonce}\n{prepayId}\n"
|
||||
)!;
|
||||
|
@ -67,7 +67,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
|
||||
{
|
||||
try
|
||||
{
|
||||
bool valid = Utilities.RSAUtility.VerifyByCertificate(
|
||||
bool valid = Utilities.RSAUtility.VerifyWithSHA256ByCertificate(
|
||||
certificatePem: certificate,
|
||||
messageData: message,
|
||||
encodingSignature: new EncodedString(signature, EncodingKinds.Base64)
|
||||
|
@ -62,7 +62,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Interceptors
|
||||
{
|
||||
try
|
||||
{
|
||||
sign = Utilities.RSAUtility.Sign(_mchCertPk, signData).Value!;
|
||||
sign = Utilities.RSAUtility.SignWithSHA256(_mchCertPk, signData).Value!;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Security.Cryptography;
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
using Org.BouncyCastle.Security;
|
||||
@ -39,18 +40,39 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.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($"AES/GCM/{paddingMode}");
|
||||
ICipherParameters cipherParams = new AeadParameters(
|
||||
new KeyParameter(keyBytes),
|
||||
TAG_LENGTH_BYTE * 8,
|
||||
nonceBytes,
|
||||
associatedDataBytes
|
||||
);
|
||||
cipher.Init(false, cipherParams);
|
||||
byte[] plainBytes = new byte[cipher.GetOutputSize(cipherBytes.Length)];
|
||||
int len = cipher.ProcessBytes(cipherBytes, 0, cipherBytes.Length, plainBytes, 0);
|
||||
cipher.DoFinal(plainBytes, len);
|
||||
return plainBytes;
|
||||
#if NET5_0_OR_GREATER
|
||||
if (AesGcm.IsSupported)
|
||||
{
|
||||
if (!string.Equals(paddingMode, PADDING_MODE_NOPADDING, StringComparison.OrdinalIgnoreCase))
|
||||
throw new NotSupportedException();
|
||||
|
||||
using (AesGcm aes = new AesGcm(keyBytes))
|
||||
{
|
||||
byte[] cipherWithoutTagBytes = new byte[cipherBytes.Length - TAG_LENGTH_BYTE];
|
||||
byte[] tagBytes = new byte[TAG_LENGTH_BYTE];
|
||||
Buffer.BlockCopy(cipherBytes, 0, cipherWithoutTagBytes, 0, cipherWithoutTagBytes.Length);
|
||||
Buffer.BlockCopy(cipherBytes, cipherWithoutTagBytes.Length, tagBytes, 0, tagBytes.Length);
|
||||
|
||||
byte[] plainBytes = new byte[cipherWithoutTagBytes.Length];
|
||||
aes.Decrypt(nonceBytes, cipherWithoutTagBytes, tagBytes, plainBytes, associatedDataBytes);
|
||||
return plainBytes;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
{
|
||||
IBufferedCipher cipher = CipherUtilities.GetCipher($"AES/GCM/{paddingMode}");
|
||||
ICipherParameters cipherParams = new AeadParameters(
|
||||
new KeyParameter(keyBytes),
|
||||
TAG_LENGTH_BYTE * 8,
|
||||
nonceBytes,
|
||||
associatedDataBytes
|
||||
);
|
||||
cipher.Init(false, cipherParams);
|
||||
byte[] plainBytes = new byte[cipher.GetOutputSize(cipherBytes.Length)];
|
||||
int len = cipher.ProcessBytes(cipherBytes, 0, cipherBytes.Length, plainBytes, 0);
|
||||
cipher.DoFinal(plainBytes, len);
|
||||
return plainBytes;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text.RegularExpressions;
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
@ -29,11 +30,14 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Utilities
|
||||
/// <summary>
|
||||
/// 签名算法:SHA-256withRSA。
|
||||
/// </summary>
|
||||
public const string DIGEST_ALGORITHM_SHA256 = "SHA-256withRSA";
|
||||
private const string DIGEST_ALGORITHM_SHA256 = "SHA-256withRSA";
|
||||
|
||||
private static byte[] ConvertPrivateKeyPemToByteArray(string privateKeyPem)
|
||||
{
|
||||
if (!privateKeyPem.StartsWith("-----BEGIN PRIVATE KEY-----"))
|
||||
const string PKCS8_HEADER = "-----BEGIN PRIVATE KEY-----";
|
||||
const string PKCS8_FOOTER = "-----END PRIVATE KEY-----";
|
||||
|
||||
if (!privateKeyPem.StartsWith(PKCS8_HEADER))
|
||||
{
|
||||
using (TextReader textReader = new StringReader(privateKeyPem))
|
||||
using (PemReader pemReader = new PemReader(textReader))
|
||||
@ -66,15 +70,18 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Utilities
|
||||
}
|
||||
|
||||
privateKeyPem = privateKeyPem
|
||||
.Replace("-----BEGIN PRIVATE KEY-----", string.Empty)
|
||||
.Replace("-----END PRIVATE KEY-----", string.Empty);
|
||||
.Replace(PKCS8_HEADER, string.Empty)
|
||||
.Replace(PKCS8_FOOTER, string.Empty);
|
||||
privateKeyPem = Regex.Replace(privateKeyPem, "\\s+", string.Empty);
|
||||
return Convert.FromBase64String(privateKeyPem);
|
||||
}
|
||||
|
||||
private static byte[] ConvertPublicKeyPemToByteArray(string publicKeyPem)
|
||||
{
|
||||
if (!publicKeyPem.StartsWith("-----BEGIN PUBLIC KEY-----"))
|
||||
const string PKCS8_HEADER = "-----BEGIN PUBLIC KEY-----";
|
||||
const string PKCS8_FOOTER = "-----END PUBLIC KEY-----";
|
||||
|
||||
if (!publicKeyPem.StartsWith(PKCS8_HEADER))
|
||||
{
|
||||
using (TextReader textReader = new StringReader(publicKeyPem))
|
||||
using (PemReader pemReader = new PemReader(textReader))
|
||||
@ -101,12 +108,24 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Utilities
|
||||
}
|
||||
|
||||
publicKeyPem = publicKeyPem
|
||||
.Replace("-----BEGIN PUBLIC KEY-----", string.Empty)
|
||||
.Replace("-----END PUBLIC KEY-----", string.Empty);
|
||||
.Replace(PKCS8_HEADER, string.Empty)
|
||||
.Replace(PKCS8_FOOTER, string.Empty);
|
||||
publicKeyPem = Regex.Replace(publicKeyPem, "\\s+", string.Empty);
|
||||
return Convert.FromBase64String(publicKeyPem);
|
||||
}
|
||||
|
||||
private static byte[] ConvertCertificatePemToByteArray(string certificatePem)
|
||||
{
|
||||
const string CER_HEADER = "-----BEGIN CERTIFICATE-----";
|
||||
const string CER_FOOTER = "-----END CERTIFICATE-----";
|
||||
|
||||
certificatePem = certificatePem
|
||||
.Replace(CER_HEADER, string.Empty)
|
||||
.Replace(CER_FOOTER, string.Empty);
|
||||
certificatePem = Regex.Replace(certificatePem, "\\s+", string.Empty);
|
||||
return Convert.FromBase64String(certificatePem);
|
||||
}
|
||||
|
||||
private static X509Certificate ParseCertificatePemToX509(string certificatePem)
|
||||
{
|
||||
using (TextReader sreader = new StringReader(certificatePem))
|
||||
@ -126,17 +145,17 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Utilities
|
||||
return (RsaKeyParameters)PublicKeyFactory.CreateKey(publicKeyBytes);
|
||||
}
|
||||
|
||||
private static byte[] Sign(RsaKeyParameters rsaPrivateKeyParams, byte[] messageBytes, string digestAlgorithm)
|
||||
private static byte[] Sign(RsaKeyParameters rsaPrivateKeyParams, byte[] messageBytes, string algorithm)
|
||||
{
|
||||
ISigner signer = SignerUtilities.GetSigner(digestAlgorithm);
|
||||
ISigner signer = SignerUtilities.GetSigner(algorithm);
|
||||
signer.Init(true, rsaPrivateKeyParams);
|
||||
signer.BlockUpdate(messageBytes, 0, messageBytes.Length);
|
||||
return signer.GenerateSignature();
|
||||
}
|
||||
|
||||
private static bool Verify(RsaKeyParameters rsaPublicKeyParams, byte[] messageBytes, byte[] signBytes, string digestAlgorithm)
|
||||
private static bool Verify(RsaKeyParameters rsaPublicKeyParams, byte[] messageBytes, byte[] signBytes, string algorithm)
|
||||
{
|
||||
ISigner signer = SignerUtilities.GetSigner(digestAlgorithm);
|
||||
ISigner signer = SignerUtilities.GetSigner(algorithm);
|
||||
signer.Init(false, rsaPublicKeyParams);
|
||||
signer.BlockUpdate(messageBytes, 0, messageBytes.Length);
|
||||
return signer.VerifySignature(signBytes);
|
||||
@ -157,66 +176,78 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Utilities
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用私钥生成签名。
|
||||
/// 使用私钥基于 SHA-256 算法生成签名。
|
||||
/// </summary>
|
||||
/// <param name="privateKeyBytes">PKCS#1/PKCS#8 私钥字节数组。</param>
|
||||
/// <param name="privateKeyBytes">PKCS#8 私钥字节数组。</param>
|
||||
/// <param name="messageBytes">待签名的数据字节数组。</param>
|
||||
/// <param name="digestAlgorithm">签名算法。(默认值:<see cref="DIGEST_ALGORITHM_SHA256"/>)</param>
|
||||
/// <returns>签名字节数组。</returns>
|
||||
public static byte[] Sign(byte[] privateKeyBytes, byte[] messageBytes, string digestAlgorithm = DIGEST_ALGORITHM_SHA256)
|
||||
public static byte[] SignWithSHA256(byte[] privateKeyBytes, byte[] messageBytes)
|
||||
{
|
||||
if (privateKeyBytes is null) throw new ArgumentNullException(nameof(privateKeyBytes));
|
||||
if (messageBytes is null) throw new ArgumentNullException(nameof(messageBytes));
|
||||
|
||||
#if NET5_0_OR_GREATER
|
||||
using (RSA rsa = RSA.Create())
|
||||
{
|
||||
rsa.ImportPkcs8PrivateKey(privateKeyBytes, out _);
|
||||
return rsa.SignData(messageBytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
|
||||
}
|
||||
#else
|
||||
RsaKeyParameters rsaPrivateKeyParams = ParsePrivateKeyToParameters(privateKeyBytes);
|
||||
return Sign(rsaPrivateKeyParams, messageBytes, digestAlgorithm);
|
||||
return Sign(rsaPrivateKeyParams, messageBytes, DIGEST_ALGORITHM_SHA256);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用私钥生成签名。
|
||||
/// 使用私钥基于 SHA-256 算法生成签名。
|
||||
/// </summary>
|
||||
/// <param name="privateKeyPem">PKCS#1/PKCS#8 私钥(PEM 格式)。</param>
|
||||
/// <param name="messageData">待签名的数据。</param>
|
||||
/// <param name="digestAlgorithm">签名算法。(默认值:<see cref="DIGEST_ALGORITHM_SHA256"/>)</param>
|
||||
/// <returns>经过 Base64 编码的签名。</returns>
|
||||
public static EncodedString Sign(string privateKeyPem, string messageData, string digestAlgorithm = DIGEST_ALGORITHM_SHA256)
|
||||
public static EncodedString SignWithSHA256(string privateKeyPem, string messageData)
|
||||
{
|
||||
if (privateKeyPem is null) throw new ArgumentNullException(nameof(privateKeyPem));
|
||||
if (messageData is null) throw new ArgumentNullException(nameof(messageData));
|
||||
|
||||
byte[] privateKeyBytes = ConvertPrivateKeyPemToByteArray(privateKeyPem);
|
||||
byte[] messageBytes = EncodedString.FromLiteralString(messageData);
|
||||
byte[] signBytes = Sign(privateKeyBytes, messageBytes, digestAlgorithm);
|
||||
byte[] signBytes = SignWithSHA256(privateKeyBytes, messageBytes);
|
||||
return EncodedString.ToBase64String(signBytes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用公钥验证签名。
|
||||
/// 使用公钥基于 SHA-256 算法验证签名。
|
||||
/// </summary>
|
||||
/// <param name="publicKeyBytes">PKCS#1/PKCS#8 公钥字节数组。</param>
|
||||
/// <param name="messageBytes">待验证的数据字节数组。</param>
|
||||
/// <param name="signBytes">签名字节数组。</param>
|
||||
/// <param name="digestAlgorithm">签名算法。(默认值:<see cref="DIGEST_ALGORITHM_SHA256"/>)</param>
|
||||
/// <returns>验证结果。</returns>
|
||||
public static bool Verify(byte[] publicKeyBytes, byte[] messageBytes, byte[] signBytes, string digestAlgorithm = DIGEST_ALGORITHM_SHA256)
|
||||
public static bool VerifyWithSHA256(byte[] publicKeyBytes, byte[] messageBytes, byte[] signBytes)
|
||||
{
|
||||
if (publicKeyBytes is null) throw new ArgumentNullException(nameof(publicKeyBytes));
|
||||
if (messageBytes is null) throw new ArgumentNullException(nameof(messageBytes));
|
||||
if (signBytes is null) throw new ArgumentNullException(nameof(signBytes));
|
||||
|
||||
#if NET5_0_OR_GREATER
|
||||
using (RSA rsa = RSA.Create())
|
||||
{
|
||||
rsa.ImportSubjectPublicKeyInfo(publicKeyBytes, out _);
|
||||
return rsa.VerifyData(messageBytes, signBytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
|
||||
}
|
||||
#else
|
||||
RsaKeyParameters rsaPublicKeyParams = ParsePublicKeyToParameters(publicKeyBytes);
|
||||
return Verify(rsaPublicKeyParams, messageBytes, signBytes, digestAlgorithm);
|
||||
return Verify(rsaPublicKeyParams, messageBytes, signBytes, DIGEST_ALGORITHM_SHA256);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用公钥验证签名。
|
||||
/// 使用公钥基于 SHA-256 算法验证签名。
|
||||
/// </summary>
|
||||
/// <param name="publicKeyPem">PKCS#1/PKCS#8 公钥(PEM 格式)。</param>
|
||||
/// <param name="messageData">待验证的数据。</param>
|
||||
/// <param name="encodingSignature">经过编码后的(通常为 Base64)签名。</param>
|
||||
/// <param name="digestAlgorithm">签名算法。(默认值:<see cref="DIGEST_ALGORITHM_SHA256"/>)</param>
|
||||
/// <returns>验证结果。</returns>
|
||||
public static bool Verify(string publicKeyPem, string messageData, EncodedString encodingSignature, string digestAlgorithm = DIGEST_ALGORITHM_SHA256)
|
||||
public static bool VerifyWithSHA256(string publicKeyPem, string messageData, EncodedString encodingSignature)
|
||||
{
|
||||
if (publicKeyPem is null) throw new ArgumentNullException(nameof(publicKeyPem));
|
||||
if (messageData is null) throw new ArgumentNullException(nameof(messageData));
|
||||
@ -225,7 +256,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Utilities
|
||||
byte[] publicKeyBytes = ConvertPublicKeyPemToByteArray(publicKeyPem);
|
||||
byte[] messageBytes = EncodedString.FromLiteralString(messageData);
|
||||
byte[] signBytes = EncodedString.FromString(encodingSignature, fallbackEncodingKind: EncodingKinds.Base64);
|
||||
return Verify(publicKeyBytes, messageBytes, signBytes, digestAlgorithm);
|
||||
return VerifyWithSHA256(publicKeyBytes, messageBytes, signBytes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -234,20 +265,19 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Utilities
|
||||
/// <param name="certificatePem">证书内容(PEM 格式)。</param>
|
||||
/// <param name="messageData">待验证的数据。</param>
|
||||
/// <param name="encodingSignature">经过编码后的(通常为 Base64)签名。</param>
|
||||
/// <param name="digestAlgorithm">签名算法。(默认值:<see cref="DIGEST_ALGORITHM_SHA256"/>)</param>
|
||||
/// <returns>验证结果。</returns>
|
||||
public static bool VerifyByCertificate(string certificatePem, string messageData, EncodedString encodingSignature, string digestAlgorithm = DIGEST_ALGORITHM_SHA256)
|
||||
public static bool VerifyWithSHA256ByCertificate(string certificatePem, string messageData, EncodedString encodingSignature)
|
||||
{
|
||||
if (certificatePem is null) throw new ArgumentNullException(nameof(certificatePem));
|
||||
|
||||
string publicKeyPem = ExportPublicKeyFromCertificate(certificatePem);
|
||||
return Verify(publicKeyPem, messageData, encodingSignature, digestAlgorithm);
|
||||
return VerifyWithSHA256(publicKeyPem, messageData, encodingSignature);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用私钥基于 ECB 模式解密数据。
|
||||
/// </summary>
|
||||
/// <param name="privateKeyBytes">PKCS#1/PKCS#8 私钥字节数组。</param>
|
||||
/// <param name="privateKeyBytes">PKCS#8 私钥字节数组。</param>
|
||||
/// <param name="cipherBytes">待解密的数据字节数组。</param>
|
||||
/// <param name="paddingMode">填充模式。(默认值:<see cref="PADDING_MODE_OAEPWITHSHA1ANDMGF1"/>)</param>
|
||||
/// <returns>解密后的数据字节数组。</returns>
|
||||
@ -256,7 +286,18 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Utilities
|
||||
if (privateKeyBytes is null) throw new ArgumentNullException(nameof(privateKeyBytes));
|
||||
if (cipherBytes is null) throw new ArgumentNullException(nameof(cipherBytes));
|
||||
|
||||
RsaKeyParameters rsaPrivateKeyParams = ParsePrivateKeyToParameters(privateKeyBytes);
|
||||
#if NET5_0_OR_GREATER
|
||||
if (string.Equals(paddingMode, PADDING_MODE_PKCS1, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
using (RSA rsa = RSA.Create())
|
||||
{
|
||||
rsa.ImportPkcs8PrivateKey(privateKeyBytes, out _);
|
||||
return rsa.Decrypt(cipherBytes, RSAEncryptionPadding.Pkcs1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
RsaKeyParameters rsaPrivateKeyParams = (RsaKeyParameters)PrivateKeyFactory.CreateKey(privateKeyBytes);
|
||||
return DecryptWithECB(rsaPrivateKeyParams, cipherBytes, paddingMode);
|
||||
}
|
||||
|
||||
@ -290,6 +331,16 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Utilities
|
||||
if (publicKeyBytes is null) throw new ArgumentNullException(nameof(publicKeyBytes));
|
||||
if (plainBytes is null) throw new ArgumentNullException(nameof(plainBytes));
|
||||
|
||||
#if NET5_0_OR_GREATER
|
||||
if (string.Equals(paddingMode, PADDING_MODE_PKCS1, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
using (RSA rsa = RSA.Create())
|
||||
{
|
||||
rsa.ImportSubjectPublicKeyInfo(publicKeyBytes, out _);
|
||||
return rsa.Encrypt(plainBytes, RSAEncryptionPadding.Pkcs1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
RsaKeyParameters rsaPublicKeyParams = ParsePublicKeyToParameters(publicKeyBytes);
|
||||
return EncryptWithECB(rsaPublicKeyParams, plainBytes, paddingMode);
|
||||
}
|
||||
@ -360,8 +411,15 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Utilities
|
||||
{
|
||||
if (certificate is null) throw new ArgumentNullException(nameof(certificate));
|
||||
|
||||
#if NET5_0_OR_GREATER
|
||||
using (System.Security.Cryptography.X509Certificates.X509Certificate2 x509cert = new System.Security.Cryptography.X509Certificates.X509Certificate2(ConvertCertificatePemToByteArray(certificate)))
|
||||
{
|
||||
return x509cert.SerialNumber;
|
||||
}
|
||||
#else
|
||||
X509Certificate x509cert = ParseCertificatePemToX509(certificate);
|
||||
return x509cert.SerialNumber.ToString(16);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -373,8 +431,15 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Utilities
|
||||
{
|
||||
if (certificate is null) throw new ArgumentNullException(nameof(certificate));
|
||||
|
||||
#if NET5_0_OR_GREATER
|
||||
using (System.Security.Cryptography.X509Certificates.X509Certificate2 x509cert = new System.Security.Cryptography.X509Certificates.X509Certificate2(ConvertCertificatePemToByteArray(certificate)))
|
||||
{
|
||||
return new DateTimeOffset(x509cert.NotBefore);
|
||||
}
|
||||
#else
|
||||
X509Certificate x509cert = ParseCertificatePemToX509(certificate);
|
||||
return new DateTimeOffset(x509cert.NotBefore);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -386,8 +451,15 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Utilities
|
||||
{
|
||||
if (certificate is null) throw new ArgumentNullException(nameof(certificate));
|
||||
|
||||
#if NET5_0_OR_GREATER
|
||||
using (System.Security.Cryptography.X509Certificates.X509Certificate2 x509cert = new System.Security.Cryptography.X509Certificates.X509Certificate2(ConvertCertificatePemToByteArray(certificate)))
|
||||
{
|
||||
return new DateTimeOffset(x509cert.NotAfter);
|
||||
}
|
||||
#else
|
||||
X509Certificate x509cert = ParseCertificatePemToX509(certificate);
|
||||
return new DateTimeOffset(x509cert.NotAfter);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Utilities
|
||||
return Convert.FromBase64String(publicKeyPem);
|
||||
}
|
||||
|
||||
private static X509Certificate ConvertCertificatePemToX509(string certificatePem)
|
||||
private static X509Certificate ParseCertificatePemToX509(string certificatePem)
|
||||
{
|
||||
using (TextReader sreader = new StringReader(certificatePem))
|
||||
{
|
||||
@ -726,7 +726,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Utilities
|
||||
|
||||
using (TextWriter swriter = new StringWriter())
|
||||
{
|
||||
X509Certificate x509cert = ConvertCertificatePemToX509(certificatePem);
|
||||
X509Certificate x509cert = ParseCertificatePemToX509(certificatePem);
|
||||
ECPublicKeyParameters exPublicKeyParams = (ECPublicKeyParameters)x509cert.GetPublicKey();
|
||||
PemWriter pemWriter = new PemWriter(swriter);
|
||||
pemWriter.WriteObject(exPublicKeyParams);
|
||||
@ -744,7 +744,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Utilities
|
||||
{
|
||||
if (certificatePem is null) throw new ArgumentNullException(nameof(certificatePem));
|
||||
|
||||
X509Certificate x509cert = ConvertCertificatePemToX509(certificatePem);
|
||||
X509Certificate x509cert = ParseCertificatePemToX509(certificatePem);
|
||||
return x509cert.SerialNumber.ToString(16);
|
||||
}
|
||||
|
||||
@ -757,7 +757,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Utilities
|
||||
{
|
||||
if (certificatePem is null) throw new ArgumentNullException(nameof(certificatePem));
|
||||
|
||||
X509Certificate x509cert = ConvertCertificatePemToX509(certificatePem);
|
||||
X509Certificate x509cert = ParseCertificatePemToX509(certificatePem);
|
||||
return new DateTimeOffset(x509cert.NotBefore);
|
||||
}
|
||||
|
||||
@ -770,7 +770,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Utilities
|
||||
{
|
||||
if (certificatePem is null) throw new ArgumentNullException(nameof(certificatePem));
|
||||
|
||||
X509Certificate x509cert = ConvertCertificatePemToX509(certificatePem);
|
||||
X509Certificate x509cert = ParseCertificatePemToX509(certificatePem);
|
||||
return new DateTimeOffset(x509cert.NotAfter);
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Security.Cryptography;
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
using Org.BouncyCastle.Security;
|
||||
@ -39,18 +40,39 @@ 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($"AES/GCM/{paddingMode}");
|
||||
ICipherParameters cipherParams = new AeadParameters(
|
||||
new KeyParameter(keyBytes),
|
||||
TAG_LENGTH_BYTE * 8,
|
||||
nonceBytes,
|
||||
associatedDataBytes
|
||||
);
|
||||
cipher.Init(false, cipherParams);
|
||||
byte[] plainBytes = new byte[cipher.GetOutputSize(cipherBytes.Length)];
|
||||
int len = cipher.ProcessBytes(cipherBytes, 0, cipherBytes.Length, plainBytes, 0);
|
||||
cipher.DoFinal(plainBytes, len);
|
||||
return plainBytes;
|
||||
#if NET5_0_OR_GREATER
|
||||
if (AesGcm.IsSupported)
|
||||
{
|
||||
if (!string.Equals(paddingMode, PADDING_MODE_NOPADDING, StringComparison.OrdinalIgnoreCase))
|
||||
throw new NotSupportedException();
|
||||
|
||||
using (AesGcm aes = new AesGcm(keyBytes))
|
||||
{
|
||||
byte[] cipherWithoutTagBytes = new byte[cipherBytes.Length - TAG_LENGTH_BYTE];
|
||||
byte[] tagBytes = new byte[TAG_LENGTH_BYTE];
|
||||
Buffer.BlockCopy(cipherBytes, 0, cipherWithoutTagBytes, 0, cipherWithoutTagBytes.Length);
|
||||
Buffer.BlockCopy(cipherBytes, cipherWithoutTagBytes.Length, tagBytes, 0, tagBytes.Length);
|
||||
|
||||
byte[] plainBytes = new byte[cipherWithoutTagBytes.Length];
|
||||
aes.Decrypt(nonceBytes, cipherWithoutTagBytes, tagBytes, plainBytes, associatedDataBytes);
|
||||
return plainBytes;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
{
|
||||
IBufferedCipher cipher = CipherUtilities.GetCipher($"AES/GCM/{paddingMode}");
|
||||
ICipherParameters cipherParams = new AeadParameters(
|
||||
new KeyParameter(keyBytes),
|
||||
TAG_LENGTH_BYTE * 8,
|
||||
nonceBytes,
|
||||
associatedDataBytes
|
||||
);
|
||||
cipher.Init(false, cipherParams);
|
||||
byte[] plainBytes = new byte[cipher.GetOutputSize(cipherBytes.Length)];
|
||||
int len = cipher.ProcessBytes(cipherBytes, 0, cipherBytes.Length, plainBytes, 0);
|
||||
cipher.DoFinal(plainBytes, len);
|
||||
return plainBytes;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text.RegularExpressions;
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
@ -22,7 +23,10 @@ namespace SKIT.FlurlHttpClient.Wechat.Work.Utilities
|
||||
|
||||
private static byte[] ConvertPrivateKeyPemToByteArray(string privateKeyPem)
|
||||
{
|
||||
if (!privateKeyPem.StartsWith("-----BEGIN PRIVATE KEY-----"))
|
||||
const string PKCS8_HEADER = "-----BEGIN PRIVATE KEY-----";
|
||||
const string PKCS8_FOOTER = "-----END PRIVATE KEY-----";
|
||||
|
||||
if (!privateKeyPem.StartsWith(PKCS8_HEADER))
|
||||
{
|
||||
using (TextReader textReader = new StringReader(privateKeyPem))
|
||||
using (PemReader pemReader = new PemReader(textReader))
|
||||
@ -55,8 +59,8 @@ namespace SKIT.FlurlHttpClient.Wechat.Work.Utilities
|
||||
}
|
||||
|
||||
privateKeyPem = privateKeyPem
|
||||
.Replace("-----BEGIN PRIVATE KEY-----", string.Empty)
|
||||
.Replace("-----END PRIVATE KEY-----", string.Empty);
|
||||
.Replace(PKCS8_HEADER, string.Empty)
|
||||
.Replace(PKCS8_FOOTER, string.Empty);
|
||||
privateKeyPem = Regex.Replace(privateKeyPem, "\\s+", string.Empty);
|
||||
return Convert.FromBase64String(privateKeyPem);
|
||||
}
|
||||
@ -71,7 +75,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Work.Utilities
|
||||
/// <summary>
|
||||
/// 使用私钥基于 ECB 模式解密数据。
|
||||
/// </summary>
|
||||
/// <param name="privateKeyBytes">PKCS#1/PKCS#8 私钥字节数组。</param>
|
||||
/// <param name="privateKeyBytes">PKCS#8 私钥字节数组。</param>
|
||||
/// <param name="cipherBytes">待解密的数据字节数组。</param>
|
||||
/// <param name="paddingMode">填充模式。(默认值:<see cref="PADDING_MODE_PKCS1"/>)</param>
|
||||
/// <returns>解密后的数据字节数组。</returns>
|
||||
@ -80,6 +84,17 @@ namespace SKIT.FlurlHttpClient.Wechat.Work.Utilities
|
||||
if (privateKeyBytes is null) throw new ArgumentNullException(nameof(privateKeyBytes));
|
||||
if (cipherBytes is null) throw new ArgumentNullException(nameof(cipherBytes));
|
||||
|
||||
#if NET5_0_OR_GREATER
|
||||
if (string.Equals(paddingMode, PADDING_MODE_PKCS1, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
using (RSA rsa = RSA.Create())
|
||||
{
|
||||
rsa.ImportPkcs8PrivateKey(privateKeyBytes, out _);
|
||||
return rsa.Decrypt(cipherBytes, RSAEncryptionPadding.Pkcs1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
RsaKeyParameters rsaPrivateKeyParams = (RsaKeyParameters)PrivateKeyFactory.CreateKey(privateKeyBytes);
|
||||
return DecryptWithECB(rsaPrivateKeyParams, cipherBytes, paddingMode);
|
||||
}
|
||||
|
@ -57,14 +57,14 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
|
||||
public void TestRSASignatureSHA256WithRSASign()
|
||||
{
|
||||
string msgText = "SHA256WithRSASignTest";
|
||||
string actualSignByPrivateKeyPkcs8 = Utilities.RSAUtility.Sign(RSA_PEM_PRIVATE_KEY_PKCS8, msgText)!;
|
||||
string actualSignByPrivateKeyPkcs1 = Utilities.RSAUtility.Sign(RSA_PEM_PRIVATE_KEY_PKCS1, msgText)!;
|
||||
string actualSignByPrivateKeyPkcs8 = Utilities.RSAUtility.SignWithSHA256(RSA_PEM_PRIVATE_KEY_PKCS8, msgText)!;
|
||||
string actualSignByPrivateKeyPkcs1 = Utilities.RSAUtility.SignWithSHA256(RSA_PEM_PRIVATE_KEY_PKCS1, msgText)!;
|
||||
string expectedSign = "EzeVEIoBhzOhXpwbXdJjIuGIGRc6ArKO7sVo2fuAdzYTDgorAEufEnw7lPPXV1GTfFcHOnsAJH9kGJmg7Orwlkh7x7TyOGrkMEhWGulA9SIdmou4iBsHpIZ/TERSgGt/VTmqmfpkzJqrvbQWIQENwo7Lr6uJSJBND0YT3nIBP8TzbO3cHnQb6chHIBHrDF5vOO7HHu+Cga2MZnAtRizhO8BhK0jOmyro32CgIML3EVX8yuPy0kOk6aN1R8xFblZUD4NU2M6zzQpydmxaHr9B1WNFoMwmpoAS5BuKJMYOHO5cc6DhB+0fAGxaWtKp6759KhKCf8M65zh3WKS4l262SGuWq4qG1+AKf2DOgCon769+A4z8flOmvl0iIwoH9FThGJoP156rpAJW7v/bWputSeC6WToUTBRmGWdwWySVwW5AZ26OAFFWs1CmrGp3jF5E2oUy1mQwgfM0QN6DW+wD769ggIYH9HLHqDHbF5UyF7eNh3s8Qy23xXEKZWNMAJ0IdtdMQ7FRRgLFSCai7HELLlBJSCz7P5WTeYZGQpbvnUShkRvzujjO6XlGiKKI0EwKb121z8N6KRpvs4SnRztWBGoXbzHZgnXKXU/BWWADemqB2cvaT3Bj0k3/N3sea0dAEtlNEklRWoyyNUUlscK9zg4LBlHrhbbFo66uuub8ySo=";
|
||||
|
||||
Assert.Equal(expectedSign, actualSignByPrivateKeyPkcs8);
|
||||
Assert.Equal(expectedSign, actualSignByPrivateKeyPkcs1);
|
||||
Assert.True(Utilities.RSAUtility.Verify(RSA_PEM_PUBLIC_KEY_PKCS8, msgText, (EncodedString)actualSignByPrivateKeyPkcs8));
|
||||
Assert.True(Utilities.RSAUtility.Verify(RSA_PEM_PUBLIC_KEY_PKCS1, msgText, (EncodedString)actualSignByPrivateKeyPkcs1));
|
||||
Assert.True(Utilities.RSAUtility.VerifyWithSHA256(RSA_PEM_PUBLIC_KEY_PKCS8, msgText, (EncodedString)actualSignByPrivateKeyPkcs8));
|
||||
Assert.True(Utilities.RSAUtility.VerifyWithSHA256(RSA_PEM_PUBLIC_KEY_PKCS1, msgText, (EncodedString)actualSignByPrivateKeyPkcs1));
|
||||
}
|
||||
|
||||
[Fact(DisplayName = "测试用例:SHA256WithRSA 签名验证")]
|
||||
@ -73,12 +73,12 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
|
||||
string msgText = "SHA256WithRSAVerifyTest";
|
||||
string signText = "aHX+MrmZHDEraMKBEPV2Vnps1B9b25lGbv/rdppx/S7+oaXtjKJprzCq5H7RCpvrKS3xYIeTEPwQGC3Vots7dCdLi8v8ew1vvtXf8qNAnd7CTMHqu3wSohXzgyASTmNbXE2ml9LbWYPPYMvPJXROQbGVjoOrsErWBPPJYXuO3lIckIfwI05OTdl4H3+BvpD/ZoljRp8Qgo9+paGvarBc++TaAh0FXnQf0TGNFUIeHHiAKBee5oCBTuZZM9J5RPw0oIq/g7Wun+e/zWiwVBPHltOgZrV46uagSAE6nBDHk+hlNxDivCxkJdBVCSIYFFmBXIcnGZ/u4ZfBui/k1jGoKibyvPK4z2+6GSlj41Yo81kuSBfzLiSsx33EPR1eIJJkwDTsvap0ymL9pfIqMiLuiteH5kGmL/dyONy9oAJywLEeITfoVyElM/CY6Dc+xDhRnjN7Hu54meYyXRZrnCtQ3YhzEr1immNBn6npgA/qi9aHsuWFOw8b8aSwOHDHTDmjmvV+axI8CVMrR0MjB9QNCWrKLq2B9iQX9MtLgcUyDsQvzAsxUJm/OEfzUjs9SHvmgmyAvzNAuTdO7wLQ+ZmKg0yZne6nvcrJVvfh3lD5ZPt7NY57Y6OIJluqKUT5H+a3H6W9Q1Z+cBMnHGYaaK7Tv8IcDdEYqTIG8hc5BqjFOzE=";
|
||||
|
||||
Assert.True(Utilities.RSAUtility.Verify(RSA_PEM_PUBLIC_KEY_PKCS8, msgText, (EncodedString)signText));
|
||||
Assert.True(Utilities.RSAUtility.Verify(RSA_PEM_PUBLIC_KEY_PKCS1, msgText, (EncodedString)signText));
|
||||
Assert.False(Utilities.RSAUtility.Verify(RSA_PEM_PUBLIC_KEY_PKCS8, msgText, (EncodedString)"FAKE SIGN"));
|
||||
Assert.False(Utilities.RSAUtility.Verify(RSA_PEM_PUBLIC_KEY_PKCS1, msgText, (EncodedString)"FAKE SIGN"));
|
||||
Assert.True(Utilities.RSAUtility.VerifyByCertificate(RSA_PEM_CERTIFICATE, msgText, (EncodedString)signText));
|
||||
Assert.False(Utilities.RSAUtility.VerifyByCertificate(RSA_PEM_CERTIFICATE, msgText, (EncodedString)"FAKE SIGN"));
|
||||
Assert.True(Utilities.RSAUtility.VerifyWithSHA256(RSA_PEM_PUBLIC_KEY_PKCS8, msgText, (EncodedString)signText));
|
||||
Assert.True(Utilities.RSAUtility.VerifyWithSHA256(RSA_PEM_PUBLIC_KEY_PKCS1, msgText, (EncodedString)signText));
|
||||
Assert.False(Utilities.RSAUtility.VerifyWithSHA256(RSA_PEM_PUBLIC_KEY_PKCS8, msgText, (EncodedString)"FAKE SIGN"));
|
||||
Assert.False(Utilities.RSAUtility.VerifyWithSHA256(RSA_PEM_PUBLIC_KEY_PKCS1, msgText, (EncodedString)"FAKE SIGN"));
|
||||
Assert.True(Utilities.RSAUtility.VerifyWithSHA256ByCertificate(RSA_PEM_CERTIFICATE, msgText, (EncodedString)signText));
|
||||
Assert.False(Utilities.RSAUtility.VerifyWithSHA256ByCertificate(RSA_PEM_CERTIFICATE, msgText, (EncodedString)"FAKE SIGN"));
|
||||
}
|
||||
|
||||
[Fact(DisplayName = "测试用例:使用 RSA 公钥加密")]
|
||||
|
Loading…
Reference in New Issue
Block a user