2022-11-09 20:48:03 +08:00
|
|
|
|
using System;
|
2022-05-09 19:28:47 +08:00
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Text.RegularExpressions;
|
|
|
|
|
using Org.BouncyCastle.Crypto;
|
|
|
|
|
using Org.BouncyCastle.Crypto.Parameters;
|
|
|
|
|
using Org.BouncyCastle.Security;
|
|
|
|
|
|
|
|
|
|
namespace SKIT.FlurlHttpClient.Wechat.TenpayBusiness.Utilities
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// RSA 算法工具类。
|
|
|
|
|
/// </summary>
|
|
|
|
|
public static class RSAUtility
|
|
|
|
|
{
|
|
|
|
|
private const string RSA_CIPHER_ALGORITHM_ECB = "RSA/ECB";
|
|
|
|
|
private const string RSA_CIPHER_PADDING_OAEP_WITH_SHA1_AND_MGF1 = "OAEPWITHSHA1ANDMGF1PADDING";
|
|
|
|
|
private const string RSA_SIGNER_ALGORITHM_SHA256 = "SHA-256withRSA";
|
|
|
|
|
|
2022-11-11 22:45:03 +08:00
|
|
|
|
private static byte[] ConvertPrivateKeyPkcs8PemToByteArray(string privateKey)
|
2022-11-09 23:02:53 +08:00
|
|
|
|
{
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-11 22:45:03 +08:00
|
|
|
|
private static byte[] ConvertPublicKeyPkcs8PemToByteArray(string publicKey)
|
2022-11-09 23:02:53 +08:00
|
|
|
|
{
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-09 19:28:47 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 使用私钥基于 SHA-256 算法生成签名。
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="privateKeyBytes">PKCS#8 私钥字节数组。</param>
|
2022-11-09 23:02:53 +08:00
|
|
|
|
/// <param name="msgBytes">待签名的数据字节数组。</param>
|
2022-05-09 19:28:47 +08:00
|
|
|
|
/// <returns>签名字节数组。</returns>
|
2022-11-09 23:02:53 +08:00
|
|
|
|
public static byte[] SignWithSHA256(byte[] privateKeyBytes, byte[] msgBytes)
|
2022-05-09 19:28:47 +08:00
|
|
|
|
{
|
2024-01-29 23:12:15 +08:00
|
|
|
|
if (privateKeyBytes is null) throw new ArgumentNullException(nameof(privateKeyBytes));
|
|
|
|
|
if (msgBytes is null) throw new ArgumentNullException(nameof(msgBytes));
|
2022-05-09 19:28:47 +08:00
|
|
|
|
|
2022-11-11 22:45:03 +08:00
|
|
|
|
RsaKeyParameters rsaPrivateKeyParams = (RsaKeyParameters)PrivateKeyFactory.CreateKey(privateKeyBytes);
|
|
|
|
|
return SignWithSHA256(rsaPrivateKeyParams, msgBytes);
|
2022-05-09 19:28:47 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 使用私钥基于 SHA-256 算法生成签名。
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="privateKey">PKCS#8 私钥(PEM 格式)。</param>
|
2022-11-09 23:02:53 +08:00
|
|
|
|
/// <param name="message">待签名的文本数据。</param>
|
2022-05-09 19:28:47 +08:00
|
|
|
|
/// <returns>经 Base64 编码的签名。</returns>
|
2022-11-09 23:02:53 +08:00
|
|
|
|
public static string SignWithSHA256(string privateKey, string message)
|
2022-05-09 19:28:47 +08:00
|
|
|
|
{
|
2024-01-29 23:12:15 +08:00
|
|
|
|
if (privateKey is null) throw new ArgumentNullException(nameof(privateKey));
|
|
|
|
|
if (message is null) throw new ArgumentNullException(nameof(message));
|
2022-05-09 19:28:47 +08:00
|
|
|
|
|
2022-11-11 22:45:03 +08:00
|
|
|
|
byte[] privateKeyBytes = ConvertPrivateKeyPkcs8PemToByteArray(privateKey);
|
2022-11-09 23:02:53 +08:00
|
|
|
|
byte[] msgBytes = Encoding.UTF8.GetBytes(message);
|
|
|
|
|
byte[] signBytes = SignWithSHA256(privateKeyBytes, msgBytes);
|
2022-05-09 19:28:47 +08:00
|
|
|
|
return Convert.ToBase64String(signBytes);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 使用公钥基于 SHA-256 算法验证签名。
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="publicKeyBytes">PKCS#8 公钥字节数据。</param>
|
2022-11-09 23:02:53 +08:00
|
|
|
|
/// <param name="msgBytes">待验证的数据字节数据。</param>
|
2022-05-09 19:28:47 +08:00
|
|
|
|
/// <param name="signBytes">待验证的签名字节数据。</param>
|
|
|
|
|
/// <returns>验证结果。</returns>
|
2022-11-09 23:02:53 +08:00
|
|
|
|
public static bool VerifyWithSHA256(byte[] publicKeyBytes, byte[] msgBytes, byte[] signBytes)
|
2022-05-09 19:28:47 +08:00
|
|
|
|
{
|
2024-01-29 23:12:15 +08:00
|
|
|
|
if (publicKeyBytes is null) throw new ArgumentNullException(nameof(publicKeyBytes));
|
|
|
|
|
if (msgBytes is null) throw new ArgumentNullException(nameof(msgBytes));
|
|
|
|
|
if (signBytes is null) throw new ArgumentNullException(nameof(signBytes));
|
2022-05-09 19:28:47 +08:00
|
|
|
|
|
2022-11-11 22:45:03 +08:00
|
|
|
|
RsaKeyParameters rsaPublicKeyParams = (RsaKeyParameters)PublicKeyFactory.CreateKey(publicKeyBytes);
|
|
|
|
|
return VerifyWithSHA256(rsaPublicKeyParams, msgBytes, signBytes);
|
2022-05-09 19:28:47 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 使用公钥基于 SHA-256 算法验证签名。
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="publicKey">PKCS#8 公钥(PEM 格式)。</param>
|
2022-11-09 23:02:53 +08:00
|
|
|
|
/// <param name="message">待验证的文本数据。</param>
|
2022-05-09 19:28:47 +08:00
|
|
|
|
/// <param name="signature">经 Base64 编码的待验证的签名。</param>
|
|
|
|
|
/// <returns>验证结果。</returns>
|
2022-11-09 23:02:53 +08:00
|
|
|
|
public static bool VerifyWithSHA256(string publicKey, string message, string signature)
|
2022-05-09 19:28:47 +08:00
|
|
|
|
{
|
2024-01-29 23:12:15 +08:00
|
|
|
|
if (publicKey is null) throw new ArgumentNullException(nameof(publicKey));
|
|
|
|
|
if (message is null) throw new ArgumentNullException(nameof(message));
|
|
|
|
|
if (signature is null) throw new ArgumentNullException(nameof(signature));
|
2022-05-09 19:28:47 +08:00
|
|
|
|
|
2022-11-11 22:45:03 +08:00
|
|
|
|
byte[] publicKeyBytes = ConvertPublicKeyPkcs8PemToByteArray(publicKey);
|
2022-11-09 23:02:53 +08:00
|
|
|
|
byte[] msgBytes = Encoding.UTF8.GetBytes(message);
|
2022-05-09 19:28:47 +08:00
|
|
|
|
byte[] signBytes = Convert.FromBase64String(signature);
|
2022-11-09 23:02:53 +08:00
|
|
|
|
return VerifyWithSHA256(publicKeyBytes, msgBytes, signBytes);
|
2022-05-09 19:28:47 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 使用私钥基于 ECB 模式解密数据。
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="privateKeyBytes">PKCS#8 私钥字节数据。</param>
|
|
|
|
|
/// <param name="cipherBytes">待解密的数据字节数据。</param>
|
|
|
|
|
/// <param name="paddingAlgorithm">填充算法。(默认值:<see cref="RSA_CIPHER_PADDING_OAEP_WITH_SHA1_AND_MGF1"/>)</param>
|
|
|
|
|
/// <returns>解密后的数据字节数组。</returns>
|
|
|
|
|
public static byte[] DecryptWithECB(byte[] privateKeyBytes, byte[] cipherBytes, string paddingAlgorithm = RSA_CIPHER_PADDING_OAEP_WITH_SHA1_AND_MGF1)
|
|
|
|
|
{
|
2024-01-29 23:12:15 +08:00
|
|
|
|
if (privateKeyBytes is null) throw new ArgumentNullException(nameof(privateKeyBytes));
|
|
|
|
|
if (cipherBytes is null) throw new ArgumentNullException(nameof(cipherBytes));
|
2022-05-09 19:28:47 +08:00
|
|
|
|
|
2022-11-11 22:45:03 +08:00
|
|
|
|
RsaKeyParameters rsaPrivateKeyParams = (RsaKeyParameters)PrivateKeyFactory.CreateKey(privateKeyBytes);
|
|
|
|
|
return DecryptWithECB(rsaPrivateKeyParams, cipherBytes, paddingAlgorithm);
|
2022-05-09 19:28:47 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 使用私钥基于 ECB 模式解密数据。
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="privateKey">PKCS#8 私钥(PEM 格式)。</param>
|
|
|
|
|
/// <param name="cipherText">经 Base64 编码的待解密数据。</param>
|
|
|
|
|
/// <param name="paddingAlgorithm">填充算法。(默认值:<see cref="RSA_CIPHER_PADDING_OAEP_WITH_SHA1_AND_MGF1"/>)</param>
|
|
|
|
|
/// <returns>解密后的文本数据。</returns>
|
|
|
|
|
public static string DecryptWithECB(string privateKey, string cipherText, string paddingAlgorithm = RSA_CIPHER_PADDING_OAEP_WITH_SHA1_AND_MGF1)
|
|
|
|
|
{
|
2024-01-29 23:12:15 +08:00
|
|
|
|
if (privateKey is null) throw new ArgumentNullException(nameof(privateKey));
|
|
|
|
|
if (cipherText is null) throw new ArgumentNullException(nameof(cipherText));
|
2022-05-09 19:28:47 +08:00
|
|
|
|
|
2022-11-11 22:45:03 +08:00
|
|
|
|
byte[] privateKeyBytes = ConvertPrivateKeyPkcs8PemToByteArray(privateKey);
|
2022-05-09 19:28:47 +08:00
|
|
|
|
byte[] cipherBytes = Convert.FromBase64String(cipherText);
|
|
|
|
|
byte[] plainBytes = DecryptWithECB(privateKeyBytes, cipherBytes, paddingAlgorithm);
|
|
|
|
|
return Encoding.UTF8.GetString(plainBytes);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 使用公钥基于 ECB 模式加密数据。
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="publicKeyBytes">PKCS#8 公钥字节数据。</param>
|
|
|
|
|
/// <param name="plainBytes">待加密的数据字节数据。</param>
|
|
|
|
|
/// <param name="paddingAlgorithm">填充算法。(默认值:<see cref="RSA_CIPHER_PADDING_OAEP_WITH_SHA1_AND_MGF1"/>)</param>
|
|
|
|
|
/// <returns>加密后的数据字节数组。</returns>
|
|
|
|
|
public static byte[] EncryptWithECB(byte[] publicKeyBytes, byte[] plainBytes, string paddingAlgorithm = RSA_CIPHER_PADDING_OAEP_WITH_SHA1_AND_MGF1)
|
|
|
|
|
{
|
2024-01-29 23:12:15 +08:00
|
|
|
|
if (publicKeyBytes is null) throw new ArgumentNullException(nameof(publicKeyBytes));
|
|
|
|
|
if (plainBytes is null) throw new ArgumentNullException(nameof(plainBytes));
|
2022-05-09 19:28:47 +08:00
|
|
|
|
|
2022-11-11 22:45:03 +08:00
|
|
|
|
RsaKeyParameters rsaPublicKeyParams = (RsaKeyParameters)PublicKeyFactory.CreateKey(publicKeyBytes);
|
|
|
|
|
return EncryptWithECB(rsaPublicKeyParams, plainBytes, paddingAlgorithm);
|
2022-05-09 19:28:47 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 使用公钥基于 ECB 模式加密数据。
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="publicKey">PKCS#8 公钥(PEM 格式)。</param>
|
|
|
|
|
/// <param name="plainText">待加密的文本数据。</param>
|
|
|
|
|
/// <param name="paddingAlgorithm">填充算法。(默认值:<see cref="RSA_CIPHER_PADDING_OAEP_WITH_SHA1_AND_MGF1"/>)</param>
|
|
|
|
|
/// <returns>经 Base64 编码的加密数据。</returns>
|
|
|
|
|
public static string EncryptWithECB(string publicKey, string plainText, string paddingAlgorithm = RSA_CIPHER_PADDING_OAEP_WITH_SHA1_AND_MGF1)
|
|
|
|
|
{
|
2024-01-29 23:12:15 +08:00
|
|
|
|
if (publicKey is null) throw new ArgumentNullException(nameof(publicKey));
|
|
|
|
|
if (plainText is null) throw new ArgumentNullException(nameof(plainText));
|
2022-05-09 19:28:47 +08:00
|
|
|
|
|
2022-11-11 22:45:03 +08:00
|
|
|
|
byte[] publicKeyBytes = ConvertPublicKeyPkcs8PemToByteArray(publicKey);
|
2022-05-09 19:28:47 +08:00
|
|
|
|
byte[] plainBytes = Encoding.UTF8.GetBytes(plainText);
|
|
|
|
|
byte[] cipherBytes = EncryptWithECB(publicKeyBytes, plainBytes, paddingAlgorithm);
|
|
|
|
|
return Convert.ToBase64String(cipherBytes);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|