4

C# .NET CORE .NET6 RSA 公钥加密 私钥解密 - runliuv

 1 year ago
source link: https://www.cnblogs.com/runliuv/p/17467994.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

runliuv

runliuv@cnblogs

  博客园 ::

首页 :: 博问 :: 闪存 ::

新随笔 ::

联系 ::

订阅

::

管理 ::

  564 随笔 :: 0 文章 :: 42 评论 ::

69万 阅读

环境说明:

.NET CORE 版本:.NET 6 。

.NET CORE 对于RSA的支持:

1. .NET 6 中内置了对 PKCS1,PKCS8 2种私钥格式的支持。

2. 如果你要部署在Linux,docker ,k8s 中;一定要用 “RSA”这个类,不能是 .NET FRAMEWORK 的 RSACryptoServiceProvider。

3. .NET 中默认加密算法为“RSA/ECB/PKCS1Padding” ,要和JAVA互通,JAVA 那边也得是 RSA/ECB/PKCS1Padding 。

加密解析:

//假设私钥长度为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)

用“支付宝开放平台开发助手”生成一组公私钥:

PKCS8私钥:

MIICeQIBADANBgkqhkiG9w0BAQEFAASCAmMwggJfAgEAAoGBAMz0Czg6QUtTISa2pUkloeQB/TEpHdqrfyroWpKLW9B/LWFSOGH9nyTk1pPZaeadyEZQ6gay/C0pUAetLraq9bMA/Luxq68b87uG7WX7dKytEO2/87qGpGMRs97H+GlkzWil2QO2KK4cHnAcVicPsmi5aZ72U0BWJFyPhtd+qdmrAgMBAAECgYEAvW67iAbgHt0BASVD9C3iSjpEaVHVlC165o/IVzaTcEx8Bz3Ve0zN8W3JnvIO3ebsG4HiLLr2Nk++9rltOc0eNeGMv7F1e/OFot1wN0ON6s1g4bYh1z5Uz8FcYiMWcqHHICrx+oSFeK9x+I2Zge7enQXcsVnqEhm77ZE5YczSryECQQD9nB58e5efYchF+cYbmURioX18cUMuhQbB9Aq2N55cd689Lg35KZqT8JQTp/8tQSdCJG8d2nU8VKspUKTEAuaDAkEAzuKIIoc9PVJvy90LhIPA9c1S8BPCI7EMCaTZqJ5o3VaR2dqvUZDGX7kL3kYkQ+n7mq3KIECvkEFzA+FOP96XuQJBAJQTKHW0T/YeSKoayUHp/lS8R6F2HCy4PRbXn71+wfbpZqcJEd2OHhQM3tiPOV258esbjMlYeSUNppZL4LgVnXMCQQC7Lvs9Ql+GPDAqo7ToEM1lmICR906QPIBHuX+1sJ3wpYMROWumwPa7ZRH36j6ls+6R5OwcgmpWeuE1gYTrBNsBAkEAn2pEtAljX1foQff6CLozYg/J6J9RmVFcJ6qz0LX3052qNFBQYw8CMHB7VkVNzsDIDC8LX5uP2pzTrdPLew+pPA==

与之匹配的 PKCS1 私钥,用助手转换的:

MIICXwIBAAKBgQDM9As4OkFLUyEmtqVJJaHkAf0xKR3aq38q6FqSi1vQfy1hUjhh/Z8k5NaT2WnmnchGUOoGsvwtKVAHrS62qvWzAPy7sauvG/O7hu1l+3SsrRDtv/O6hqRjEbPex/hpZM1opdkDtiiuHB5wHFYnD7JouWme9lNAViRcj4bXfqnZqwIDAQABAoGBAL1uu4gG4B7dAQElQ/Qt4ko6RGlR1ZQteuaPyFc2k3BMfAc91XtMzfFtyZ7yDt3m7BuB4iy69jZPvva5bTnNHjXhjL+xdXvzhaLdcDdDjerNYOG2Idc+VM/BXGIjFnKhxyAq8fqEhXivcfiNmYHu3p0F3LFZ6hIZu+2ROWHM0q8hAkEA/ZwefHuXn2HIRfnGG5lEYqF9fHFDLoUGwfQKtjeeXHevPS4N+Smak/CUE6f/LUEnQiRvHdp1PFSrKVCkxALmgwJBAM7iiCKHPT1Sb8vdC4SDwPXNUvATwiOxDAmk2aieaN1Wkdnar1GQxl+5C95GJEPp+5qtyiBAr5BBcwPhTj/el7kCQQCUEyh1tE/2HkiqGslB6f5UvEehdhwsuD0W15+9fsH26WanCRHdjh4UDN7YjzldufHrG4zJWHklDaaWS+C4FZ1zAkEAuy77PUJfhjwwKqO06BDNZZiAkfdOkDyAR7l/tbCd8KWDETlrpsD2u2UR9+o+pbPukeTsHIJqVnrhNYGE6wTbAQJBAJ9qRLQJY19X6EH3+gi6M2IPyeifUZlRXCeqs9C199OdqjRQUGMPAjBwe1ZFTc7AyAwvC1+bj9qc063Ty3sPqTw=

与之匹配的公钥:

MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDM9As4OkFLUyEmtqVJJaHkAf0xKR3aq38q6FqSi1vQfy1hUjhh/Z8k5NaT2WnmnchGUOoGsvwtKVAHrS62qvWzAPy7sauvG/O7hu1l+3SsrRDtv/O6hqRjEbPex/hpZM1opdkDtiiuHB5wHFYnD7JouWme9lNAViRcj4bXfqnZqwIDAQAB

加密工具类:

RsaEncryptUtil

using System.Security.Cryptography;
using System.Text;

namespace CommonUtils
{
    public static class RsaEncryptUtil
    {
        #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)                 

                //转为纯字符串,不带格式
                publicKeyPem = publicKeyPem.Replace("-----BEGIN PUBLIC KEY-----", "").Replace("-----END PUBLIC KEY-----", "").Replace("\r", "").Replace("\n", "").Trim();

                RSA rsa = RSA.Create();
                rsa.ImportSubjectPublicKeyInfo(Convert.FromBase64String(publicKeyPem), out _);

                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, RSAEncryptionPadding.Pkcs1);
                    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, RSAEncryptionPadding.Pkcs1);
                    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)                                 

                //转为纯字符串,不带格式
                privateKeyPem = privateKeyPem.Replace("-----BEGIN RSA PRIVATE KEY-----", "").Replace("-----END RSA PRIVATE KEY-----", "").Replace("\r", "").Replace("\n", "").Trim();
                privateKeyPem = privateKeyPem.Replace("-----BEGIN PRIVATE KEY-----", "").Replace("-----END PRIVATE KEY-----", "").Replace("\r", "").Replace("\n", "").Trim();


                RSA rsaCsp = RSA.Create();
                if (keyFormat == "PKCS8")
                    rsaCsp.ImportPkcs8PrivateKey(Convert.FromBase64String(privateKeyPem), out _);
                else if (keyFormat == "PKCS1")
                    rsaCsp.ImportRSAPrivateKey(Convert.FromBase64String(privateKeyPem), out _);
                else
                    throw new Exception("只支持PKCS8,PKCS1");

                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, RSAEncryptionPadding.Pkcs1);
                    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, RSAEncryptionPadding.Pkcs1);
                    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

    }
}

调用代码:

// See https://aka.ms/new-console-template for more information


using CommonUtils;

try
{
    //PKCS8格式私钥
    string strPriPkcs8 = "MIICeQIBADANBgkqhkiG9w0BAQEFAASCAmMwggJfAgEAAoGBAMz0Czg6QUtTISa2pUkloeQB/TEpHdqrfyroWpKLW9B/LWFSOGH9nyTk1pPZaeadyEZQ6gay/C0pUAetLraq9bMA/Luxq68b87uG7WX7dKytEO2/87qGpGMRs97H+GlkzWil2QO2KK4cHnAcVicPsmi5aZ72U0BWJFyPhtd+qdmrAgMBAAECgYEAvW67iAbgHt0BASVD9C3iSjpEaVHVlC165o/IVzaTcEx8Bz3Ve0zN8W3JnvIO3ebsG4HiLLr2Nk++9rltOc0eNeGMv7F1e/OFot1wN0ON6s1g4bYh1z5Uz8FcYiMWcqHHICrx+oSFeK9x+I2Zge7enQXcsVnqEhm77ZE5YczSryECQQD9nB58e5efYchF+cYbmURioX18cUMuhQbB9Aq2N55cd689Lg35KZqT8JQTp/8tQSdCJG8d2nU8VKspUKTEAuaDAkEAzuKIIoc9PVJvy90LhIPA9c1S8BPCI7EMCaTZqJ5o3VaR2dqvUZDGX7kL3kYkQ+n7mq3KIECvkEFzA+FOP96XuQJBAJQTKHW0T/YeSKoayUHp/lS8R6F2HCy4PRbXn71+wfbpZqcJEd2OHhQM3tiPOV258esbjMlYeSUNppZL4LgVnXMCQQC7Lvs9Ql+GPDAqo7ToEM1lmICR906QPIBHuX+1sJ3wpYMROWumwPa7ZRH36j6ls+6R5OwcgmpWeuE1gYTrBNsBAkEAn2pEtAljX1foQff6CLozYg/J6J9RmVFcJ6qz0LX3052qNFBQYw8CMHB7VkVNzsDIDC8LX5uP2pzTrdPLew+pPA==";
    //PKCS1格式私钥
    string strPriPkcs1 = "MIICXwIBAAKBgQDM9As4OkFLUyEmtqVJJaHkAf0xKR3aq38q6FqSi1vQfy1hUjhh/Z8k5NaT2WnmnchGUOoGsvwtKVAHrS62qvWzAPy7sauvG/O7hu1l+3SsrRDtv/O6hqRjEbPex/hpZM1opdkDtiiuHB5wHFYnD7JouWme9lNAViRcj4bXfqnZqwIDAQABAoGBAL1uu4gG4B7dAQElQ/Qt4ko6RGlR1ZQteuaPyFc2k3BMfAc91XtMzfFtyZ7yDt3m7BuB4iy69jZPvva5bTnNHjXhjL+xdXvzhaLdcDdDjerNYOG2Idc+VM/BXGIjFnKhxyAq8fqEhXivcfiNmYHu3p0F3LFZ6hIZu+2ROWHM0q8hAkEA/ZwefHuXn2HIRfnGG5lEYqF9fHFDLoUGwfQKtjeeXHevPS4N+Smak/CUE6f/LUEnQiRvHdp1PFSrKVCkxALmgwJBAM7iiCKHPT1Sb8vdC4SDwPXNUvATwiOxDAmk2aieaN1Wkdnar1GQxl+5C95GJEPp+5qtyiBAr5BBcwPhTj/el7kCQQCUEyh1tE/2HkiqGslB6f5UvEehdhwsuD0W15+9fsH26WanCRHdjh4UDN7YjzldufHrG4zJWHklDaaWS+C4FZ1zAkEAuy77PUJfhjwwKqO06BDNZZiAkfdOkDyAR7l/tbCd8KWDETlrpsD2u2UR9+o+pbPukeTsHIJqVnrhNYGE6wTbAQJBAJ9qRLQJY19X6EH3+gi6M2IPyeifUZlRXCeqs9C199OdqjRQUGMPAjBwe1ZFTc7AyAwvC1+bj9qc063Ty3sPqTw=";
    //公钥
    string strPub = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDM9As4OkFLUyEmtqVJJaHkAf0xKR3aq38q6FqSi1vQfy1hUjhh/Z8k5NaT2WnmnchGUOoGsvwtKVAHrS62qvWzAPy7sauvG/O7hu1l+3SsrRDtv/O6hqRjEbPex/hpZM1opdkDtiiuHB5wHFYnD7JouWme9lNAViRcj4bXfqnZqwIDAQAB";

    string strDJM = "泰酷拉!123ABC";//待加密字符串
    strDJM = "泰酷拉!123ABC泰酷拉!123ABC泰酷拉!123ABC泰酷拉!123ABC泰酷拉!123ABC泰酷拉!123ABC泰酷拉!123ABC泰酷拉!123ABC泰酷拉!123ABC泰酷拉!123ABC泰酷拉!123ABC泰酷拉!123ABC泰酷拉!123ABC泰酷拉!123ABC泰酷拉!123ABC泰酷拉!123ABC泰酷拉!123ABC";//待加密字符串,超过117字符的测试

    Console.WriteLine("待加密字符串:" + strDJM);
    string charSet = "UTF-8";
    string strJMH = RsaEncryptUtil.RSAEncrypt(strDJM, charSet, strPub);//密文
    Console.WriteLine("密文:" + strJMH);

    string strDecryptedByPkcs8 = RsaEncryptUtil.RSADecrypt(strJMH, charSet, strPriPkcs8, "PKCS8");//使用PKCS8格式私钥解密
    Console.WriteLine("PKCS8 解密后:" + strDecryptedByPkcs8);

    string strDecryptedByPkcs1 = RsaEncryptUtil.RSADecrypt(strJMH, charSet, strPriPkcs1, "PKCS1");//使用PKCS1格式私钥解密

    Console.WriteLine("PKCS1 解密后:" + strDecryptedByPkcs1);

}
catch (Exception ex)
{

    Console.WriteLine("ex:" + ex.Message);
}

Console.WriteLine("Hello, World!");
Console.ReadKey();

Recommend

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK