C#使用BouncyCastle实现RSA签名加密,与JAVA互通

泄露秘密 提交于 2020-02-28 07:24:41

问题

调用其他支付公司提供的接口(第三方接口是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);

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!