Files
DotNetCore.SKIT.FlurlHttpCl…/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Utilities/RSAUtility.cs

272 lines
13 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.X509;
namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Utilities
{
/// <summary>
/// RSA 算法工具类。
/// </summary>
public static class RSAUtility
{
// REF: https://github.com/bcgit/bc-csharp/blob/master/crypto/src/security/CipherUtilities.cs
private const string RSA_CIPHER_ALG = "RSA/ECB/PKCS1";
// REF: https://github.com/bcgit/bc-csharp/blob/master/crypto/src/security/SignerUtilities.cs
private const string RSA_SIGNER_ALG = "SHA-256withRSA";
/// <summary>
/// 使用私钥基于 SHA-256 算法生成签名。
/// </summary>
/// <param name="privateKeyBytes">PKCS#8 私钥字节数组。</param>
/// <param name="plainBytes">待签名的数据字节数组。</param>
/// <returns>签名字节数组。</returns>
public static byte[] SignWithSHA256(byte[] privateKeyBytes, byte[] plainBytes)
{
if (privateKeyBytes == null) throw new ArgumentNullException(nameof(privateKeyBytes));
if (plainBytes == null) throw new ArgumentNullException(nameof(plainBytes));
RsaKeyParameters rsaKeyParams = (RsaKeyParameters)PrivateKeyFactory.CreateKey(privateKeyBytes);
return SignWithSHA256(rsaKeyParams, plainBytes);
}
/// <summary>
/// 使用私钥基于 SHA-256 算法生成签名。
/// </summary>
/// <param name="privateKey">PKCS#8 私钥pem 格式)。</param>
/// <param name="plainText">待签名的文本数据。</param>
/// <returns>经 Base64 编码的签名。</returns>
public static string SignWithSHA256(string privateKey, string plainText)
{
if (privateKey == null) throw new ArgumentNullException(nameof(privateKey));
if (plainText == null) throw new ArgumentNullException(nameof(plainText));
byte[] privateKeyBytes = ConvertPkcs8PrivateKeyToByteArray(privateKey);
byte[] plainBytes = Encoding.UTF8.GetBytes(plainText);
byte[] signBytes = SignWithSHA256(privateKeyBytes, plainBytes);
return Convert.ToBase64String(signBytes);
}
/// <summary>
/// 使用公钥基于 SHA-256 算法验证签名。
/// </summary>
/// <param name="publicKeyBytes">PKCS#8 公钥字节数据。</param>
/// <param name="plainBytes">待验证的数据字节数据。</param>
/// <param name="signBytes">待验证的签名字节数据。</param>
/// <returns>验证结果。</returns>
public static bool VerifyWithSHA256(byte[] publicKeyBytes, byte[] plainBytes, byte[] signBytes)
{
if (publicKeyBytes == null) throw new ArgumentNullException(nameof(publicKeyBytes));
if (plainBytes == null) throw new ArgumentNullException(nameof(plainBytes));
if (signBytes == null) throw new ArgumentNullException(nameof(signBytes));
RsaKeyParameters rsaKeyParams = (RsaKeyParameters)PublicKeyFactory.CreateKey(publicKeyBytes);
return VerifyWithSHA256(rsaKeyParams, plainBytes, signBytes);
}
/// <summary>
/// 使用公钥基于 SHA-256 算法验证签名。
/// </summary>
/// <param name="publicKey">PKCS#8 公钥pem 格式)。</param>
/// <param name="plainText">待验证的文本数据。</param>
/// <param name="signature">经 Base64 编码的待验证的签名。</param>
/// <returns>验证结果。</returns>
public static bool VerifyWithSHA256(string publicKey, string plainText, string signature)
{
if (publicKey == null) throw new ArgumentNullException(nameof(publicKey));
if (plainText == null) throw new ArgumentNullException(nameof(plainText));
if (signature == null) throw new ArgumentNullException(nameof(signature));
byte[] publicKeyBytes = ConvertPkcs8PublicKeyToByteArray(publicKey);
byte[] plainBytes = Encoding.UTF8.GetBytes(plainText);
byte[] signBytes = Convert.FromBase64String(signature);
return VerifyWithSHA256(publicKeyBytes, plainBytes, signBytes);
}
/// <summary>
/// 使用证书基于 SHA-256 算法验证签名。
/// </summary>
/// <param name="certificate">证书cer 格式)。</param>
/// <param name="plainText">待验证的文本数据。</param>
/// <param name="signature">经 Base64 编码的待验证的签名。</param>
/// <returns>验证结果。</returns>
public static bool VerifyWithSHA256ByCertificate(string certificate, string plainText, string signature)
{
if (certificate == null) throw new ArgumentNullException(nameof(certificate));
if (plainText == null) throw new ArgumentNullException(nameof(plainText));
if (signature == null) throw new ArgumentNullException(nameof(signature));
RsaKeyParameters rsaKeyParams = ConvertCertificateToPublicKeyParams(certificate);
byte[] plainBytes = Encoding.UTF8.GetBytes(plainText);
byte[] signBytes = Convert.FromBase64String(signature);
return VerifyWithSHA256(rsaKeyParams, plainBytes, signBytes);
}
/// <summary>
/// 使用私钥基于 ECB 模式解密数据。
/// </summary>
/// <param name="privateKeyBytes">PKCS#8 私钥字节数据。</param>
/// <param name="cipherBytes">待解密的数据字节数据。</param>
/// <returns>解密后的数据字节数组。</returns>
public static byte[] DecryptWithECB(byte[] privateKeyBytes, byte[] cipherBytes)
{
if (privateKeyBytes == null) throw new ArgumentNullException(nameof(privateKeyBytes));
if (cipherBytes == null) throw new ArgumentNullException(nameof(cipherBytes));
RsaKeyParameters rsaKeyParams = (RsaKeyParameters)PrivateKeyFactory.CreateKey(privateKeyBytes);
return DecryptWithECB(rsaKeyParams, cipherBytes);
}
/// <summary>
/// 使用私钥基于 ECB 模式解密数据。
/// </summary>
/// <param name="privateKey">PKCS#8 私钥pem 格式)。</param>
/// <param name="cipherText">经 Base64 编码的待解密数据。</param>
/// <returns>解密后的文本数据。</returns>
public static string DecryptWithECB(string privateKey, string cipherText)
{
if (privateKey == null) throw new ArgumentNullException(nameof(privateKey));
if (cipherText == null) throw new ArgumentNullException(nameof(cipherText));
byte[] privateKeyBytes = ConvertPkcs8PrivateKeyToByteArray(privateKey);
byte[] cipherBytes = Convert.FromBase64String(cipherText);
byte[] plainBytes = DecryptWithECB(privateKeyBytes, cipherBytes);
return Encoding.UTF8.GetString(plainBytes);
}
/// <summary>
/// 使用公钥基于 ECB 模式加密数据。
/// </summary>
/// <param name="publicKeyBytes">PKCS#8 公钥字节数据。</param>
/// <param name="plainBytes">待加密的数据字节数据。</param>
/// <returns>加密后的数据字节数组。</returns>
public static byte[] EncryptWithECB(byte[] publicKeyBytes, byte[] plainBytes)
{
if (publicKeyBytes == null) throw new ArgumentNullException(nameof(publicKeyBytes));
if (plainBytes == null) throw new ArgumentNullException(nameof(plainBytes));
RsaKeyParameters rsaKeyParams = (RsaKeyParameters)PublicKeyFactory.CreateKey(publicKeyBytes);
return EncryptWithECB(rsaKeyParams, plainBytes);
}
/// <summary>
/// 使用公钥基于 ECB 模式加密数据。
/// </summary>
/// <param name="publicKey">PKCS#8 公钥pem 格式)。</param>
/// <param name="plainText">待加密的文本数据。</param>
/// <returns>经 Base64 编码的加密数据。</returns>
public static string EncryptWithECB(string publicKey, string plainText)
{
if (publicKey == null) throw new ArgumentNullException(nameof(publicKey));
if (plainText == null) throw new ArgumentNullException(nameof(plainText));
byte[] publicKeyBytes = ConvertPkcs8PublicKeyToByteArray(publicKey);
byte[] plainBytes = Encoding.UTF8.GetBytes(plainText);
byte[] cipherBytes = EncryptWithECB(publicKeyBytes, plainBytes);
return Convert.ToBase64String(cipherBytes);
}
/// <summary>
/// 使用证书基于 ECB 模式加密数据。
/// </summary>
/// <param name="certificate">证书cer 格式)。</param>
/// <param name="plainText">待加密的文本数据。</param>
/// <returns>经 Base64 编码的加密数据。</returns>
public static string EncryptWithECBByCertificate(string certificate, string plainText)
{
if (certificate == null) throw new ArgumentNullException(nameof(certificate));
if (plainText == null) throw new ArgumentNullException(nameof(plainText));
RsaKeyParameters rsaKeyParams = ConvertCertificateToPublicKeyParams(certificate);
byte[] plainBytes = Encoding.UTF8.GetBytes(plainText);
byte[] cipherBytes = EncryptWithECB(rsaKeyParams, plainBytes);
return Convert.ToBase64String(cipherBytes);
}
/// <summary>
/// <para>从 CER 证书中提取 PKCS#8 公钥。</para>
/// <para>
/// 即从 -----BEGIN CERTIFICATE----- ... -----END CERTIFICATE-----
/// 转为 -----BEGIN PUBLIC KEY----- ..... -----END PUBLIC KEY-----
/// </para>
/// </summary>
/// <param name="certificate">证书cer 格式)。</param>
/// <returns>PKCS#8 公钥pem 格式)。</returns>
public static string ExportPublicKey(string certificate)
{
using (TextWriter swriter = new StringWriter())
{
RsaKeyParameters rsaKeyParams = ConvertCertificateToPublicKeyParams(certificate);
PemWriter pemWriter = new PemWriter(swriter);
pemWriter.WriteObject(rsaKeyParams);
pemWriter.Writer.Flush();
return swriter.ToString()!;
}
}
private static byte[] ConvertPkcs8PrivateKeyToByteArray(string privateKey)
{
privateKey = privateKey
.Replace("-----BEGIN PRIVATE KEY-----", "")
.Replace("-----END PRIVATE KEY-----", "");
privateKey = Regex.Replace(privateKey, "\\s+", "");
return Convert.FromBase64String(privateKey);
}
private static byte[] ConvertPkcs8PublicKeyToByteArray(string publicKey)
{
publicKey = publicKey
.Replace("-----BEGIN PUBLIC KEY-----", "")
.Replace("-----END PUBLIC KEY-----", "");
publicKey = Regex.Replace(publicKey, "\\s+", "");
return Convert.FromBase64String(publicKey);
}
private static RsaKeyParameters ConvertCertificateToPublicKeyParams(string certificate)
{
using (TextReader sreader = new StringReader(certificate))
{
PemReader pemReader = new PemReader(sreader);
X509Certificate cert = (X509Certificate)pemReader.ReadObject();
return (RsaKeyParameters)cert.GetPublicKey();
}
}
private static byte[] SignWithSHA256(RsaKeyParameters rsaKeyParams, byte[] plainBytes)
{
ISigner signer = SignerUtilities.GetSigner(RSA_SIGNER_ALG);
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_ALG);
signer.Init(false, rsaKeyParams);
signer.BlockUpdate(plainBytes, 0, plainBytes.Length);
return signer.VerifySignature(signBytes);
}
private static byte[] EncryptWithECB(RsaKeyParameters rsaKeyParams, byte[] plainBytes)
{
IBufferedCipher cipher = CipherUtilities.GetCipher(RSA_CIPHER_ALG);
cipher.Init(true, rsaKeyParams);
return cipher.DoFinal(plainBytes);
}
private static byte[] DecryptWithECB(RsaKeyParameters rsaKeyParams, byte[] cipherBytes)
{
IBufferedCipher cipher = CipherUtilities.GetCipher(RSA_CIPHER_ALG);
cipher.Init(false, rsaKeyParams);
return cipher.DoFinal(cipherBytes);
}
}
}