问题
调用其他支付公司提供的接口(第三方接口是JAVA编写,也只给提供JAVA的调用示例。),给了一个pfx的公钥,直接尝试用C#的签名加密调不通,C#签名加密方法如下:
/// <summary>
/// 公钥加密
/// </summary>
/// <param name="value">要加密的数据</param>
/// <returns></returns>
public static string SignEncrypt2(string value)
{
try
{
//根据路径和密码,读取公钥文件证书
X509Certificate2 pc = new X509Certificate2("\\test.pfx", Config.PrivateLucPwd);
RSACryptoServiceProvider p = (RSACryptoServiceProvider)pc.PublicKey.Key;
byte[] enBytes = p.SignData(Encoding.UTF8.GetBytes(value), new SHA1CryptoServiceProvider());
p.Dispose();
return Convert.ToBase64String(enBytes);
}
catch
{ }
return string.Empty;
}
搜索得知JAVA和C#的RSA加密有很多不同,并且搜到BouncyCastle第三方类库可以解决加密通用问题,但是文档甚少。
一番搜索之后,有把C#的公钥xml格式转为JAVA格式公钥的,也有说自己实现一个bigint的,各种结果可以自己尝试搜一下。
最终解决方案
最终拼凑了一些代码,通过C# xml格式的key,通过BouncyCastle转为pem格式,然后再进行RSA签名加密。测试可用。
感谢前辈们踩坑并贴出代码,代码出处:https://www.cnblogs.com/hubro/p/4538925.html
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Encodings;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Prng;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Pkcs;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.X509;
using System;
using System.Collections;
using System.IO;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
namespace sypay.Admin.Core
{
public static class BouncyCastleRSA
{
private static StreamReader GetStreamReader(string content)
{
byte[] bytes = Encoding.UTF8.GetBytes(content);
var memory = new MemoryStream(bytes);
var reader = new StreamReader(memory);
return reader;
}
/// <summary>
/// BouncyCastle 根据xml格式key,转为Pem格式
/// </summary>
/// <param name="xmlPrivateKey"></param>
/// <returns></returns>
private static RSAParameters GenerateRSAParameterWithXmlPrivateKey(string xmlPrivateKey)
{
var rsa = RSA.Create();
rsa.FromXmlString(xmlPrivateKey);
if (!(DotNetUtilities.GetRsaKeyPair(rsa) is AsymmetricCipherKeyPair asymmetricCipherKeyPair))
{
throw new Exception("Private key format is incorrect");
}
RsaPrivateCrtKeyParameters rsaPrivateCrtKeyParameters =
(RsaPrivateCrtKeyParameters)PrivateKeyFactory.CreateKey(
PrivateKeyInfoFactory.CreatePrivateKeyInfo(asymmetricCipherKeyPair.Private));
var rsap = new RSAParameters();
rsap.Modulus = rsaPrivateCrtKeyParameters.Modulus.ToByteArrayUnsigned();
rsap.Exponent = rsaPrivateCrtKeyParameters.PublicExponent.ToByteArrayUnsigned();
rsap.P = rsaPrivateCrtKeyParameters.P.ToByteArrayUnsigned();
rsap.Q = rsaPrivateCrtKeyParameters.Q.ToByteArrayUnsigned();
rsap.DP = rsaPrivateCrtKeyParameters.DP.ToByteArrayUnsigned();
rsap.DQ = rsaPrivateCrtKeyParameters.DQ.ToByteArrayUnsigned();
rsap.InverseQ = rsaPrivateCrtKeyParameters.QInv.ToByteArrayUnsigned();
rsap.D = rsaPrivateCrtKeyParameters.Exponent.ToByteArrayUnsigned();
return rsap;
}
private static RSAParameters GenerateRSAParameterWithPkcs1PrivateKey(string privateKeyStr)
{
using (var txtreader = GetStreamReader(privateKeyStr))
{
PemReader pr = new PemReader(txtreader);
if (!(pr.ReadObject() is AsymmetricCipherKeyPair asymmetricCipherKeyPair))
{
throw new Exception("Private key format is incorrect");
}
RsaPrivateCrtKeyParameters rsaPrivateCrtKeyParameters =
(RsaPrivateCrtKeyParameters)PrivateKeyFactory.CreateKey(
PrivateKeyInfoFactory.CreatePrivateKeyInfo(asymmetricCipherKeyPair.Private));
var rsap = new RSAParameters();
rsap.Modulus = rsaPrivateCrtKeyParameters.Modulus.ToByteArrayUnsigned();
rsap.Exponent = rsaPrivateCrtKeyParameters.PublicExponent.ToByteArrayUnsigned();
rsap.P = rsaPrivateCrtKeyParameters.P.ToByteArrayUnsigned();
rsap.Q = rsaPrivateCrtKeyParameters.Q.ToByteArrayUnsigned();
rsap.DP = rsaPrivateCrtKeyParameters.DP.ToByteArrayUnsigned();
rsap.DQ = rsaPrivateCrtKeyParameters.DQ.ToByteArrayUnsigned();
rsap.InverseQ = rsaPrivateCrtKeyParameters.QInv.ToByteArrayUnsigned();
rsap.D = rsaPrivateCrtKeyParameters.Exponent.ToByteArrayUnsigned();
return rsap;
}
}
/// <summary>
/// 读取pfx证书,并将密钥存储为PKCS#8格式
/// </summary>
/// <param name="pfxFileName"></param>
/// <param name="password"></param>
public static void ConvertPfxToPkcs8(string pfxFileName, string password)
{
var certificate = ReadX509Certificate(pfxFileName, password);
var rsa = RSA.Create();
rsa.FromXmlString(certificate.PrivateKey.ToXmlString(true));
var bcKeyPair = DotNetUtilities.GetRsaKeyPair(rsa);
var pkcs8Gen = new Pkcs8Generator(bcKeyPair.Private);
var pemObj = pkcs8Gen.Generate();
var pkcs8Out = new StreamWriter(@"d:\privkey.pk8", false);
var pemWriter = new PemWriter(pkcs8Out);
pemWriter.WriteObject(pemObj);
pkcs8Out.Close();
}
/// <summary>
/// 读取密钥证书
/// </summary>
/// <param name="pfxFileName"></param>
/// <param name="password"></param>
/// <returns></returns>
private static X509Certificate2 ReadX509Certificate(string pfxFileName, string password)
{
return new X509Certificate2(pfxFileName, password, X509KeyStorageFlags.Exportable);
}
public static X509Certificate2 ReadX509Certificate(string content)
{
var bytes = Encoding.UTF8.GetBytes(content);
return new X509Certificate2(bytes);
}
/// <summary>
/// 使用PFX证书,对数据进行PKCS#12签名
/// </summary>
/// <param name="data">数据</param>
/// <param name="pfxFileName">密钥证书路径</param>
/// <param name="password">密钥证书读取密码</param>
/// <returns></returns>
public static string SignWithPfx(string data, string pfxFileName, string password)
{
var certificate = ReadX509Certificate(pfxFileName, password);
var rsa = RSA.Create();
rsa.KeySize = certificate.PrivateKey.KeySize;
var rsaPara = GenerateRSAParameterWithXmlPrivateKey(certificate.PrivateKey.ToXmlString(true));
rsa.ImportParameters(rsaPara);
var bytes = Encoding.UTF8.GetBytes(data);
var signBytes = rsa.SignData(bytes, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1);
return Convert.ToBase64String(signBytes);
}
/// <summary>
/// 使用PFX证书,对数据进行签名验证
/// </summary>
/// <param name="data"></param>
/// <param name="pfxFileName"></param>
/// <param name="password"></param>
/// <param name="signature"></param>
/// <returns></returns>
public static bool VerifyWithPfx(string data, string pfxFileName, string password, string signature)
{
var cert = ReadX509Certificate(pfxFileName, password);
return VerifyWithPfx(data, signature, cert);
}
private static bool VerifyWithPfx(string data, string signature, X509Certificate2 cert)
{
var rsa = RSA.Create();
rsa.FromXmlString(cert.PublicKey.Key.ToXmlString(false));
var bcKeyPair = DotNetUtilities.GetRsaPublicKey(rsa);
ISigner signer = SignerUtilities.GetSigner("SHA1withRSA");
signer.Init(false, bcKeyPair);
var expectedSig = Convert.FromBase64String(signature);
var msgBytes = Encoding.UTF8.GetBytes(data);
signer.BlockUpdate(msgBytes, 0, msgBytes.Length);
return signer.VerifySignature(expectedSig);
}
/// <summary>
/// 使用PKCS#12密钥,对数据进行加密
/// </summary>
/// <param name="data"></param>
/// <param name="privateKeyStr">-----BEGIN RSA PRIVATE KEY-----</param>
/// <returns></returns>
public static string SignWithPKC12(string data, string privateKeyStr)
{
using (var txtreader = GetStreamReader(privateKeyStr))
{
var keyPair = (AsymmetricCipherKeyPair)new PemReader(txtreader).ReadObject();
ISigner signer = SignerUtilities.GetSigner("SHA1withRSA");
signer.Init(true, keyPair.Private);
var bytes = Encoding.UTF8.GetBytes(data);
signer.BlockUpdate(bytes, 0, bytes.Length);
byte[] signature = signer.GenerateSignature();
return Convert.ToBase64String(signature);
}
}
/// <summary>
/// 使用公钥证书(-----BEGIN CERTIFICATE-----),对签名进行验证
/// </summary>
/// <param name="data"></param>
/// <param name="signature"></param>
/// <param name="publicKey">-----BEGIN CERTIFICATE-----</param>
/// <returns></returns>
public static bool VerifyWithCert(string data, string signature, string publicKey)
{
var cert = ReadX509Certificate(publicKey);
return VerifyWithPfx(data, signature, cert);
}
/// <summary>
/// 使用PKCS#12公钥(-----BEGIN PUBLIC KEY-----),对签名进行验证
/// </summary>
/// <param name="data"></param>
/// <param name="signature"></param>
/// <param name="publicKeyStr">-----BEGIN PUBLIC KEY-----</param>
/// <returns></returns>
public static bool VerifyWithPKCS12(string data, string signature, string publicKeyStr)
{
using (var sr = GetStreamReader(publicKeyStr))
{
var keyParameter = (AsymmetricKeyParameter)new PemReader(sr).ReadObject();
ISigner signer = SignerUtilities.GetSigner("SHA1withRSA");
signer.Init(false, keyParameter);
var expectedSig = Convert.FromBase64String(signature);
var msgBytes = Encoding.UTF8.GetBytes(data);
signer.BlockUpdate(msgBytes, 0, msgBytes.Length);
return signer.VerifySignature(expectedSig);
}
}
public static string AESEncrypt(string content, string privateKeyStr)
{
var privateKeyBytes = Encoding.UTF8.GetBytes(privateKeyStr);
var encryptBytes = Encoding.UTF8.GetBytes(content);
RijndaelManaged managed = new RijndaelManaged();
managed.Key = privateKeyBytes;
managed.Mode = CipherMode.ECB;
managed.Padding = PaddingMode.PKCS7;
ICryptoTransform transform = managed.CreateEncryptor();
byte[] resultArray = transform.TransformFinalBlock(encryptBytes, 0, encryptBytes.Length);
return Convert.ToBase64String(resultArray, 0, resultArray.Length);
}
public static string AESDecrypt(string encryptStr, string privateKeyStr)
{
var publicKeyBytes = Encoding.UTF8.GetBytes(privateKeyStr);
var encryptBytes = Convert.FromBase64String(encryptStr);
RijndaelManaged managed = new RijndaelManaged();
managed.Key = publicKeyBytes;
managed.Mode = CipherMode.ECB;
managed.Padding = PaddingMode.PKCS7;
ICryptoTransform transform = managed.CreateDecryptor();
byte[] resultArray = transform.TransformFinalBlock(encryptBytes, 0, encryptBytes.Length);
return Encoding.UTF8.GetString(resultArray);
}
public static string RSADecrypt(string encryptStr, string publicKeyStr, int secretLength)
{
var bytesToDecrypt = Convert.FromBase64String(encryptStr);
var decryptEngine = new Pkcs1Encoding(new RsaEngine(), secretLength);
using (var sr = GetStreamReader(publicKeyStr))
{
var keyParameter = (AsymmetricKeyParameter)new PemReader(sr).ReadObject();
decryptEngine.Init(false, keyParameter);
}
var processBlock = decryptEngine.ProcessBlock(bytesToDecrypt, 0, bytesToDecrypt.Length);
var decryptStr = Encoding.UTF8.GetString(processBlock);
return decryptStr;
}
public static string RSAEncrypt(string content, string privateKeyStr)
{
var bytesToEncrypt = Encoding.UTF8.GetBytes(content);
var encryptEngine = new Pkcs1Encoding(new RsaEngine());
using (var txtreader = GetStreamReader(privateKeyStr))
{
var keyPair = (AsymmetricCipherKeyPair)new PemReader(txtreader).ReadObject();
encryptEngine.Init(true, keyPair.Private);
}
var encrypted = Convert.ToBase64String(encryptEngine.ProcessBlock(bytesToEncrypt, 0, bytesToEncrypt.Length));
return encrypted;
}
}
}
调用方式:
var signValue = RSAUtil.SignWithPfx(data, "test.pfx", Config.PrivateLucPwd);
来源:oschina
链接:https://my.oschina.net/CrazyBoy1024/blog/3165991