加密解析:


//假设私钥长度为1024, 1024/8-11=117。

//如果明文的长度小于117,直接全加密,然后转base64。(data.Length <= maxBlockSize)

//如果明文长度大于117,则每117分一段加密,写入到另一个Stream中,最后转base64。while (blockSize > 0)


如果要和其它语言互通,这个分段长度需要和其它语言约定好,不一是 私钥长度/8-11。


解密解析:


//假设私钥长度为1024, 1024/8 =128。

//如果明文的长度小于 128,直接全解密。(data.Length <= maxBlockSize)

//如果明文长度大于 128,则每 128 分一段解密,写入到另一个Stream中,最后 GetString。while (blockSize > 0)


核心重点是拿到 .NET 的RSACryptoServiceProvider 对象。


nuget 中引用 Portable.BouncyCastle。


工具类:


RsaUtil:


using Org.BouncyCastle.Crypto.Parameters;

using Org.BouncyCastle.Security;

using System;

using System.IO;

using System.Security.Cryptography;

using System.Security.Cryptography.X509Certificates;

 

namespace CommonUtils

{

    public static class RsaUtil

    {

        #region 加载私钥

 

 

        /// <summary>

        /// 转换私钥字符串为RSACryptoServiceProvider

        /// </summary>

        /// <param name="privateKeyStr">私钥字符串</param>

        /// <param name="keyFormat">PKCS8,PKCS1</param>

        /// <param name="signType">RSA 私钥长度1024 ,RSA2 私钥长度2048</param>

        /// <returns></returns>

        public static RSACryptoServiceProvider LoadPrivateKey(string privateKeyStr, string keyFormat)

        {

            string signType = "RSA";

            if (privateKeyStr.Length > 1024)

            {

                signType = "RSA2";

            }

            //PKCS8,PKCS1

            if (keyFormat == "PKCS1")

            {

                return LoadPrivateKeyPKCS1(privateKeyStr, signType);

            }

            else

            {

                return LoadPrivateKeyPKCS8(privateKeyStr);

            }

        }

 

        /// <summary>

        /// PKCS1 格式私钥转 RSACryptoServiceProvider 对象

        /// </summary>

        /// <param name="strKey">pcsk1 私钥的文本内容</param>

        /// <param name="signType">RSA 私钥长度1024 ,RSA2 私钥长度2048 </param>

        /// <returns></returns>

        public static RSACryptoServiceProvider LoadPrivateKeyPKCS1(string privateKeyPemPkcs1, string signType)

        {

            try

            {

                privateKeyPemPkcs1 = privateKeyPemPkcs1.Replace("-----BEGIN RSA PRIVATE KEY-----", "").Replace("-----END RSA PRIVATE KEY-----", "").Replace("\r", "").Replace("\n", "").Trim();

                privateKeyPemPkcs1 = privateKeyPemPkcs1.Replace("-----BEGIN PRIVATE KEY-----", "").Replace("-----END PRIVATE KEY-----", "").Replace("\r", "").Replace("\n", "").Trim();

 

                byte[] data = null;

                //读取带

 

                data = Convert.FromBase64String(privateKeyPemPkcs1);

 

 

                RSACryptoServiceProvider rsa = DecodeRSAPrivateKey(data, signType);

                return rsa;

            }

            catch (Exception ex)

            {

                throw ex;

            }

            return null;

        }

 

        private static RSACryptoServiceProvider DecodeRSAPrivateKey(byte[] privkey, string signType)

        {

            byte[] MODULUS, E, D, P, Q, DP, DQ, IQ;

 

            // --------- Set up stream to decode the asn.1 encoded RSA private key ------

            MemoryStream mem = new MemoryStream(privkey);

            BinaryReader binr = new BinaryReader(mem);  //wrap Memory Stream with BinaryReader for easy reading

            byte bt = 0;

            ushort twobytes = 0;

            int elems = 0;

            try

            {

                twobytes = binr.ReadUInt16();

                if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81)

                    binr.ReadByte();    //advance 1 byte

                else if (twobytes == 0x8230)

                    binr.ReadInt16();    //advance 2 bytes

                else

                    return null;

 

                twobytes = binr.ReadUInt16();

                if (twobytes != 0x0102) //version number

                    return null;

                bt = binr.ReadByte();

                if (bt != 0x00)

                    return null;

 

 

                //------ all private key components are Integer sequences ----

                elems = GetIntegerSize(binr);

                MODULUS = binr.ReadBytes(elems);

 

                elems = GetIntegerSize(binr);

                E = binr.ReadBytes(elems);

 

                elems = GetIntegerSize(binr);

                D = binr.ReadBytes(elems);

 

                elems = GetIntegerSize(binr);

                P = binr.ReadBytes(elems);

 

                elems = GetIntegerSize(binr);

                Q = binr.ReadBytes(elems);

 

                elems = GetIntegerSize(binr);

                DP = binr.ReadBytes(elems);

 

                elems = GetIntegerSize(binr);

                DQ = binr.ReadBytes(elems);

 

                elems = GetIntegerSize(binr);

                IQ = binr.ReadBytes(elems);

 

 

                // ------- create RSACryptoServiceProvider instance and initialize with public key -----

                CspParameters CspParameters = new CspParameters();

                CspParameters.Flags = CspProviderFlags.UseMachineKeyStore;

 

                int bitLen = 1024;

                if ("RSA2".Equals(signType))

                {

                    bitLen = 2048;

                }

 

                RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(bitLen, CspParameters);

                //RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();

 

                RSAParameters RSAparams = new RSAParameters();

                RSAparams.Modulus = MODULUS;

                RSAparams.Exponent = E;

                RSAparams.D = D;

                RSAparams.P = P;

                RSAparams.Q = Q;

                RSAparams.DP = DP;

                RSAparams.DQ = DQ;

                RSAparams.InverseQ = IQ;

                RSA.ImportParameters(RSAparams);

                return RSA;

            }

            catch (Exception ex)

            {

                throw ex;

                // return null;

            }

            finally

            {

                binr.Close();

            }

        }

 

        private static int GetIntegerSize(BinaryReader binr)

        {

            byte bt = 0;

            byte lowbyte = 0x00;

            byte highbyte = 0x00;

            int count = 0;

            bt = binr.ReadByte();

            if (bt != 0x02)        //expect integer

                return 0;

            bt = binr.ReadByte();

 

            if (bt == 0x81)

                count = binr.ReadByte();    // data size in next byte

            else

                if (bt == 0x82)

            {

                highbyte = binr.ReadByte(); // data size in next 2 bytes

                lowbyte = binr.ReadByte();

                byte[] modint = { lowbyte, highbyte, 0x00, 0x00 };

                count = BitConverter.ToInt32(modint, 0);

            }

            else

            {

                count = bt;     // we already have the data size

            }

 

            while (binr.ReadByte() == 0x00)

            {    //remove high order zeros in data

                count -= 1;

            }

            binr.BaseStream.Seek(-1, SeekOrigin.Current);        //last ReadByte wasn't a removed zero, so back up a byte

            return count;

        }

 

        /// <summary>

        /// PKCS8 文本转RSACryptoServiceProvider 对象

        /// </summary>

        /// <param name="privateKeyPemPkcs8"></param>

        /// <returns></returns>

        public static RSACryptoServiceProvider LoadPrivateKeyPKCS8(string privateKeyPemPkcs8)

        {

 

            try

            {

                //PKCS8是“BEGIN PRIVATE KEY”

                privateKeyPemPkcs8 = privateKeyPemPkcs8.Replace("-----BEGIN RSA PRIVATE KEY-----", "").Replace("-----END RSA PRIVATE KEY-----", "").Replace("\r", "").Replace("\n", "").Trim();

                privateKeyPemPkcs8 = privateKeyPemPkcs8.Replace("-----BEGIN PRIVATE KEY-----", "").Replace("-----END PRIVATE KEY-----", "").Replace("\r", "").Replace("\n", "").Trim();

 

                //pkcs8 文本先转为 .NET XML 私钥字符串

                string privateKeyXml = RSAPrivateKeyJava2DotNet(privateKeyPemPkcs8);

 

                RSACryptoServiceProvider publicRsa = new RSACryptoServiceProvider();

                publicRsa.FromXmlString(privateKeyXml);

                return publicRsa;

            }

            catch (Exception ex)

            {

                throw ex;

            }

        }

 

        /// <summary>

        /// PKCS8 私钥文本 转 .NET XML 私钥文本

        /// </summary>

        /// <param name="privateKeyPemPkcs8"></param>

        /// <returns></returns>

        public static string RSAPrivateKeyJava2DotNet(string privateKeyPemPkcs8)

        {

            RsaPrivateCrtKeyParameters privateKeyParam = (RsaPrivateCrtKeyParameters)PrivateKeyFactory.CreateKey(Convert.FromBase64String(privateKeyPemPkcs8));

            return string.Format("<RSAKeyValue><Modulus>{0}</Modulus><Exponent>{1}</Exponent><P>{2}</P><Q>{3}</Q><DP>{4}</DP><DQ>{5}</DQ><InverseQ>{6}</InverseQ><D>{7}</D></RSAKeyValue>",

            Convert.ToBase64String(privateKeyParam.Modulus.ToByteArrayUnsigned()),

            Convert.ToBase64String(privateKeyParam.PublicExponent.ToByteArrayUnsigned()),

            Convert.ToBase64String(privateKeyParam.P.ToByteArrayUnsigned()),

            Convert.ToBase64String(privateKeyParam.Q.ToByteArrayUnsigned()),

            Convert.ToBase64String(privateKeyParam.DP.ToByteArrayUnsigned()),

            Convert.ToBase64String(privateKeyParam.DQ.ToByteArrayUnsigned()),

            Convert.ToBase64String(privateKeyParam.QInv.ToByteArrayUnsigned()),

            Convert.ToBase64String(privateKeyParam.Exponent.ToByteArrayUnsigned()));

        }

 

        #endregion

 

 

        /// <summary>

        /// 加载公钥证书

        /// </summary>

        /// <param name="publicKeyCert">公钥证书文本内容</param>

        /// <returns></returns>

        public static RSACryptoServiceProvider LoadPublicCert(string publicKeyCert)

        {

 

            publicKeyCert = publicKeyCert.Replace("-----BEGIN CERTIFICATE-----", "").Replace("-----END CERTIFICATE-----", "").Replace("\r", "").Replace("\n", "").Trim();

 

            byte[] bytesCerContent = Convert.FromBase64String(publicKeyCert);

            X509Certificate2 x509 = new X509Certificate2(bytesCerContent);

            RSACryptoServiceProvider rsaPub = (RSACryptoServiceProvider)x509.PublicKey.Key;

            return rsaPub;

 

        }

 

        /// <summary>

        /// pem 公钥文本 转  .NET RSACryptoServiceProvider。

        /// </summary>

        /// <param name="publicKeyPem"></param>

        /// <returns></returns>

        public static RSACryptoServiceProvider LoadPublicKey(string publicKeyPem)

        {

 

            publicKeyPem = publicKeyPem.Replace("-----BEGIN PUBLIC KEY-----", "").Replace("-----END PUBLIC KEY-----", "").Replace("\r", "").Replace("\n", "").Trim();

 

            //pem 公钥文本 转  .NET XML 公钥文本。

            string publicKeyXml = RSAPublicKeyJava2DotNet(publicKeyPem);

 

            RSACryptoServiceProvider publicRsa = new RSACryptoServiceProvider();

            publicRsa.FromXmlString(publicKeyXml);

            return publicRsa;

 

 

        }

 

        /// <summary>

        /// pem 公钥文本 转  .NET XML 公钥文本。

        /// </summary>

        /// <param name="publicKey"></param>

        /// <returns></returns>

        private static string RSAPublicKeyJava2DotNet(string publicKey)

        {

            RsaKeyParameters publicKeyParam = (RsaKeyParameters)PublicKeyFactory.CreateKey(Convert.FromBase64String(publicKey));

            return string.Format("<RSAKeyValue><Modulus>{0}</Modulus><Exponent>{1}</Exponent></RSAKeyValue>",

                Convert.ToBase64String(publicKeyParam.Modulus.ToByteArrayUnsigned()),

                Convert.ToBase64String(publicKeyParam.Exponent.ToByteArrayUnsigned()));

        }

 

 

    }

}

RsaEncryptUtil:


using Org.BouncyCastle.Crypto;

using Org.BouncyCastle.Crypto.Parameters;

using Org.BouncyCastle.Security;

using System;

using System.IO;

using System.Security.Cryptography;

using System.Text;

 

namespace CommonUtils

{

    public static class RsaEncryptUtil

    {

 

        #region 非标准的-私钥加密-公钥解密

 

        /// <summary>

        /// 私钥加密 .Net平台默认是使用公钥进行加密,私钥进行解密。私钥加密需要自己实现或者使用第三方dll

        /// </summary>

        /// <param name="data"></param>

        /// <param name="key">私钥,格式:PKCS8</param>

        /// <returns></returns>

        public static byte[] encryptByPrivateKey(String data, String key)

        {

            String priKey = key.Trim();

            String xmlPrivateKey = RSAPrivateKeyJava2DotNet(priKey);

            //加载私钥  

            RSACryptoServiceProvider privateRsa = new RSACryptoServiceProvider();

            privateRsa.FromXmlString(xmlPrivateKey);

            //转换密钥  

            AsymmetricCipherKeyPair keyPair = DotNetUtilities.GetKeyPair(privateRsa);

            IBufferedCipher c = CipherUtilities.GetCipher("RSA/ECB/PKCS1Padding");// 参数与Java中加密解密的参数一致       

            c.Init(true, keyPair.Private); //第一个参数为true表示加密,为false表示解密;第二个参数表示密钥 

            byte[] DataToEncrypt = Encoding.UTF8.GetBytes(data);

            byte[] outBytes = c.DoFinal(DataToEncrypt);//加密  

            return outBytes;

 

        }

 

        /// <summary>

        /// 私钥加密

        /// </summary>

        /// <param name="data">明文</param>

        /// <param name="key">私钥</param>

        /// <param name="keyFormat">私钥格式:PKCS1,PKCS8</param>

        /// <returns></returns>

        public static byte[] encryptByPrivateKey(String data, String key, string keyFormat)

        {

            String priKey = key.Trim();

 

            //加载私钥  

            RSACryptoServiceProvider privateRsa = RsaUtil.LoadPrivateKey(key, keyFormat);

 

            //转换密钥  

            AsymmetricCipherKeyPair keyPair = DotNetUtilities.GetKeyPair(privateRsa);

            IBufferedCipher c = CipherUtilities.GetCipher("RSA/ECB/PKCS1Padding");// 参数与Java中加密解密的参数一致       

            c.Init(true, keyPair.Private); //第一个参数为true表示加密,为false表示解密;第二个参数表示密钥 

            byte[] DataToEncrypt = Encoding.UTF8.GetBytes(data);

            byte[] outBytes = c.DoFinal(DataToEncrypt);//加密  

            return outBytes;

 

        }

 

        /// <summary>

        /// RSA私钥格式转换,java->.net

        /// </summary>

        /// <param name="privateKey"></param>

        /// <returns></returns>

        private static string RSAPrivateKeyJava2DotNet(string privateKey)

        {

            RsaPrivateCrtKeyParameters privateKeyParam = (RsaPrivateCrtKeyParameters)PrivateKeyFactory.CreateKey(Convert.FromBase64String(privateKey));

 

            return string.Format("<RSAKeyValue><Modulus>{0}</Modulus><Exponent>{1}</Exponent><P>{2}</P><Q>{3}</Q><DP>{4}</DP><DQ>{5}</DQ><InverseQ>{6}</InverseQ><D>{7}</D></RSAKeyValue>",

                Convert.ToBase64String(privateKeyParam.Modulus.ToByteArrayUnsigned()),

                Convert.ToBase64String(privateKeyParam.PublicExponent.ToByteArrayUnsigned()),

                Convert.ToBase64String(privateKeyParam.P.ToByteArrayUnsigned()), Convert.ToBase64String(privateKeyParam.Q.ToByteArrayUnsigned()),

                Convert.ToBase64String(privateKeyParam.DP.ToByteArrayUnsigned()),

                Convert.ToBase64String(privateKeyParam.DQ.ToByteArrayUnsigned()),

                Convert.ToBase64String(privateKeyParam.QInv.ToByteArrayUnsigned()),

                Convert.ToBase64String(privateKeyParam.Exponent.ToByteArrayUnsigned()));

        }

 

        /// <summary>

        /// 用公钥解密

        /// </summary>

        /// <param name="data"></param>

        /// <param name="key"></param>

        /// <returns></returns>

        public static byte[] decryptByPublicKey(String data, String key)

        {

            String pubKey = key.Trim();

            String xmlPublicKey = RSAPublicKeyJava2DotNet(pubKey);

 

            RSACryptoServiceProvider publicRsa = new RSACryptoServiceProvider();

            publicRsa.FromXmlString(xmlPublicKey);

 

            AsymmetricKeyParameter keyPair = DotNetUtilities.GetRsaPublicKey(publicRsa);

            //转换密钥  

            // AsymmetricCipherKeyPair keyPair = DotNetUtilities.GetRsaKeyPair(publicRsa);

            IBufferedCipher c = CipherUtilities.GetCipher("RSA/ECB/PKCS1Padding");// 参数与Java中加密解密的参数一致       

            c.Init(false, keyPair); //第一个参数为true表示加密,为false表示解密;第二个参数表示密钥 

            byte[] DataToEncrypt = Convert.FromBase64String(data);

            byte[] outBytes = c.DoFinal(DataToEncrypt);//解密  

            return outBytes;

        }

 

        /// <summary>

        /// RSA公钥格式转换,java->.net

        /// </summary>

        /// <param name="publicKey"></param>

        /// <returns></returns>

        private static string RSAPublicKeyJava2DotNet(string publicKey)

        {

            RsaKeyParameters publicKeyParam = (RsaKeyParameters)PublicKeyFactory.CreateKey(Convert.FromBase64String(publicKey));

            return string.Format("<RSAKeyValue><Modulus>{0}</Modulus><Exponent>{1}</Exponent></RSAKeyValue>",

                Convert.ToBase64String(publicKeyParam.Modulus.ToByteArrayUnsigned()),

                Convert.ToBase64String(publicKeyParam.Exponent.ToByteArrayUnsigned()));

        }

 

        #endregion

 

 

        #region 标准的-公钥加密-私钥解密

 

        /** 默认编码字符集 */

        private static string DEFAULT_CHARSET = "UTF-8";

 

        /// <summary>

        /// 公钥加密(超过 私钥长度 / 8 - 11,分段加密)

        /// </summary>

        /// <param name="content">明文</param>

        /// <param name="charset">编码</param>

        /// <param name="publicKeyPem">公钥</param>

        /// <returns></returns>

        /// <exception cref="Exception"></exception>

        public static string RSAEncrypt(string content, string charset, string publicKeyPem)

        {

            try

            {

                //假设私钥长度为1024, 1024/8-11=117。

                //如果明文的长度小于117,直接全加密,然后转base64。(data.Length <= maxBlockSize)

                //如果明文长度大于117,则每117分一段加密,写入到另一个Stream中,最后转base64。while (blockSize > 0)

 

                RSACryptoServiceProvider rsa = RsaUtil.LoadPublicKey(publicKeyPem);

                //string sPublicKeyPEM = File.ReadAllText(publicKeyPem);

                //RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();

                //rsa.PersistKeyInCsp = false;

                //RSACryptoServiceProviderExtension.LoadPublicKeyPEM(rsa, sPublicKeyPEM);

                if (string.IsNullOrEmpty(charset))

                {

                    charset = DEFAULT_CHARSET;

                }

                byte[] data = Encoding.GetEncoding(charset).GetBytes(content);

                int maxBlockSize = rsa.KeySize / 8 - 11; //加密块最大长度限制

                if (data.Length <= maxBlockSize)

                {

                    byte[] cipherbytes = rsa.Encrypt(data, false);

                    return Convert.ToBase64String(cipherbytes);

                }

                MemoryStream plaiStream = new MemoryStream(data);

                MemoryStream crypStream = new MemoryStream();

                Byte[] buffer = new Byte[maxBlockSize];

                int blockSize = plaiStream.Read(buffer, 0, maxBlockSize);

                while (blockSize > 0)

                {

                    Byte[] toEncrypt = new Byte[blockSize];

                    Array.Copy(buffer, 0, toEncrypt, 0, blockSize);

                    Byte[] cryptograph = rsa.Encrypt(toEncrypt, false);

                    crypStream.Write(cryptograph, 0, cryptograph.Length);

                    blockSize = plaiStream.Read(buffer, 0, maxBlockSize);

                }

 

                return Convert.ToBase64String(crypStream.ToArray(), Base64FormattingOptions.None);

            }

            catch (Exception ex)

            {

                throw new Exception("EncryptContent = " + content + ",charset = " + charset, ex);

            }

        }

 

        /// <summary>

        /// 私钥解密(超过 私钥长度 / 8 - 11,分段加密)

        /// </summary>

        /// <param name="content">密文</param>

        /// <param name="charset">编码</param>

        /// <param name="privateKeyPem">私钥</param>

        /// <param name="keyFormat">私钥格式 PKCS1,PKCS8</param>

        /// <returns></returns>

        /// <exception cref="Exception"></exception>

        public static string RSADecrypt(string content, string charset, string privateKeyPem, string keyFormat)

        {

            try

            {

                //假设私钥长度为1024, 1024/8 =128。

                //如果明文的长度小于 128,直接全解密。(data.Length <= maxBlockSize)

                //如果明文长度大于 128,则每 128 分一段解密,写入到另一个Stream中,最后 GetString。while (blockSize > 0)

 

                RSACryptoServiceProvider rsaCsp = RsaUtil.LoadPrivateKey(privateKeyPem, keyFormat);

 

                //RSACryptoServiceProvider rsaCsp = LoadCertificateFile(privateKeyPem, signType);

                if (string.IsNullOrEmpty(charset))

                {

                    charset = DEFAULT_CHARSET;

                }

                byte[] data = Convert.FromBase64String(content);

                int maxBlockSize = rsaCsp.KeySize / 8; //解密块最大长度限制

                if (data.Length <= maxBlockSize)

                {

                    byte[] cipherbytes = rsaCsp.Decrypt(data, false);

                    return Encoding.GetEncoding(charset).GetString(cipherbytes);

                }

                MemoryStream crypStream = new MemoryStream(data);

                MemoryStream plaiStream = new MemoryStream();

                Byte[] buffer = new Byte[maxBlockSize];

                int blockSize = crypStream.Read(buffer, 0, maxBlockSize);

                while (blockSize > 0)

                {

                    Byte[] toDecrypt = new Byte[blockSize];

                    Array.Copy(buffer, 0, toDecrypt, 0, blockSize);

                    Byte[] cryptograph = rsaCsp.Decrypt(toDecrypt, false);

                    plaiStream.Write(cryptograph, 0, cryptograph.Length);

                    blockSize = crypStream.Read(buffer, 0, maxBlockSize);

                }

 

                return Encoding.GetEncoding(charset).GetString(plaiStream.ToArray());

            }

            catch (Exception ex)

            {

                throw new Exception("DecryptContent = " + content + ",charset = " + charset, ex);

            }

        }

 

 

        #endregion

 

 

    }

}

使用:


支持超出  私钥长度/8 -11 的长度明文,分段加密。


公钥加密:


private void btnPubKeyEncrypt_Click(object sender, EventArgs e)

        {

            try

            {

                string rst = RsaEncryptUtil.RSAEncrypt(txtMingWen.Text, "UTF-8", txtPubKey.Text);

                txtJiaMiHou.Text = rst;

            }

            catch (Exception ex)

            {

                MessageBox.Show(ex.Message);

            }

        }

私钥解密 :


private void btnPrivateKeyDecrypt_Click(object sender, EventArgs e)

        {

            try

            {

                string strRst = RsaEncryptUtil.RSADecrypt(txtJiaMiHou.Text, "UTF-8", txtPrivateKey.Text, cbxPrivateKeyFormat.Text);

                txtJieMiHou.Text = strRst;

            }

            catch (Exception ex)

            {

                MessageBox.Show(ex.Message);

            }

        }

END

————————————————

版权声明:本文为CSDN博主「runliuv」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/runliuv/article/details/124937542


标签: none

添加新评论