• C#.NET Framework 使用BC库(BouncyCastle) RSA 公钥加密 私钥解密 ver:20230706


    C#.NET Framework 使用BC库(BouncyCastle) RSA 公钥加密 私钥解密 ver:20230706

     

    环境说明:

    .NET Framework 4.6 的控制台程序 。

     

    2020年以后 ,有部分PKCS8私钥(openssl生成)无法用RsaUtil.LoadPrivateKey(strPriPkcs8, "PKCS8")来解析 (https://www.cnblogs.com/runliuv/p/17474269.html)

     可以尝试用BC库来处理。

    另外,在.NET中:私钥加密,公钥解密。也只能用BC库实现。 

     

    加密解析:

    //假设私钥长度为1024, 1024/8-11=117。
    //如果明文的长度小于117,直接全加密,然后转base64。(data.Length <= maxBlockSize)
    //如果明文长度大于117,则每117分一段加密,写入到另一个Stream中,最后转base64。

     

     

     

    解密解析:

    //假设私钥长度为1024, 1024/8 =128。
    //如果明文的长度小于 128,直接全解密。(data.Length <= maxBlockSize)
    //如果明文长度大于 128,则每 128 分一段解密,写入到另一个Stream中,最后 GetString。

     

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

    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

     

    BCSignUtil 辅助类,nuget 中引用 Portable.BouncyCastle。

    复制代码
    using Org.BouncyCastle.Crypto;
    using Org.BouncyCastle.Crypto.Encodings;
    using Org.BouncyCastle.Crypto.Engines;
    using Org.BouncyCastle.Security;
    using System;
    using System.IO;
    using System.Text;
    
    namespace CommonUtils
    {
        public static class BCSignUtil
        {
            /// 
            /// 签名
            /// 
            /// 原数据字符串
            /// 必须是PKCS8的
            /// 算法
            /// 
            public static string SignData(string orgData, string privateKeyPKCS8, string algorithm)
            {
                if (string.IsNullOrEmpty(orgData))
                    throw new Exception("字符串不能为空!");
    
                if (string.IsNullOrEmpty(privateKeyPKCS8))
                    throw new Exception("privateKeyPKCS8不能为空!");
    
                if (string.IsNullOrEmpty(privateKeyPKCS8))
                    throw new Exception("algorithm 不能为空!");
    
                AsymmetricKeyParameter priKey = GetPrivateKeyParameter(privateKeyPKCS8);
    
                byte[] byteData = Encoding.UTF8.GetBytes(orgData);
    
                ISigner normalSig = SignerUtilities.GetSigner(algorithm);
                normalSig.Init(true, priKey);
                normalSig.BlockUpdate(byteData, 0, byteData.Length);//注意:是byte数组和数组长度,别写成string的长度了
                byte[] normalResult = normalSig.GenerateSignature(); //签名结果
                string sign = Convert.ToBase64String(normalResult);
    
                return sign;
            }
    
            private static AsymmetricKeyParameter GetPrivateKeyParameter(string privateKeyPem)
            {
                //获取私钥纯字符串
                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();
    
                byte[] privateInfoByte = Convert.FromBase64String(privateKeyPem);
    
                AsymmetricKeyParameter priKey = PrivateKeyFactory.CreateKey(privateInfoByte);
                return priKey;
            }
    
            /// 
            /// 验证签名
            /// 
            /// 原数据字符串
            /// 公钥
            /// 对方的签名串
            /// 算法
            /// 
            public static bool VerifySignature(string orgData, string publicKeyPem, string responseSign, string algorithm)
            {
    
                AsymmetricKeyParameter pubKey = GetPublicKeyParameter(publicKeyPem);
    
    
                byte[] signBytes = Convert.FromBase64String(responseSign);
                byte[] plainBytes = Encoding.UTF8.GetBytes(orgData);
    
                ISigner verifier = SignerUtilities.GetSigner(algorithm);
                verifier.Init(false, pubKey);
                verifier.BlockUpdate(plainBytes, 0, plainBytes.Length);//注意:是byte数组和数组长度,别写成string的长度了
    
                bool isOK = verifier.VerifySignature(signBytes); //验签结果
                return isOK;
            }
    
            private static AsymmetricKeyParameter GetPublicKeyParameter(string publicKeyPem)
            {
                //获取公钥纯字符串
                publicKeyPem = publicKeyPem.Replace("-----BEGIN PUBLIC KEY-----", "").Replace("-----END PUBLIC KEY-----", "").Replace("\r", "").Replace("\n", "").Trim();
    
                byte[] publicInfoByte = Convert.FromBase64String(publicKeyPem);
    
                AsymmetricKeyParameter pubKey = PublicKeyFactory.CreateKey(publicInfoByte);
                return pubKey;
            }
    
            /// 
            /// RSA加密
            /// 
            /// 数据
            /// 私钥、公钥
            /// 是否为公钥
            /// 私钥长度,一般是1024或2048
            /// 
            public static string EncryptByKey(string orgData, string key, bool isPublicKey, int privateKeySize)
            {
                //非对称加密算法,加解密用  
                IAsymmetricBlockCipher engine = new Pkcs1Encoding(new RsaEngine());
                //加密  
    
                //1024长度是117,双方协商好
                int maxBlockSize = privateKeySize / 8 - 11; //加密块最大长度限制
    
                engine.Init(true, isPublicKey ? GetPublicKeyParameter(key) : GetPrivateKeyParameter(key));
                byte[] byteData = System.Text.Encoding.UTF8.GetBytes(orgData);
    
                int inputLen = byteData.Length;
                MemoryStream ms = new MemoryStream();
                int offSet = 0;
                byte[] cache;
                int i = 0;
                // 对数据分段加密
                while (inputLen - offSet > 0)
                {
                    if (inputLen - offSet > maxBlockSize)
                    {
                        cache = engine.ProcessBlock(byteData, offSet, maxBlockSize);
                    }
                    else
                    {
                        cache = engine.ProcessBlock(byteData, offSet, inputLen - offSet);
                    }
                    ms.Write(cache, 0, cache.Length);
                    i++;
                    offSet = i * maxBlockSize;
                }
                byte[] encryptedData = ms.ToArray();
    
                //var ResultData = engine.ProcessBlock(byteData, 0, byteData.Length);
                return Convert.ToBase64String(encryptedData);
                //Console.WriteLine("密文(base64编码):" + Convert.ToBase64String(testData) + Environment.NewLine);
    
            }
            /// 
            /// RSA解密
            /// 
            /// 数据
            /// 私钥、公钥
            /// 是否为公钥
            /// 私钥长度,一般是1024或2048
            /// 
            public static string DecryptByKey(string orgData, string key, bool isPublicKey, int privateKeySize)
            {
                orgData = orgData.Replace("\r", "").Replace("\n", "").Replace(" ", "");
                //非对称加密算法,加解密用  
                IAsymmetricBlockCipher engine = new Pkcs1Encoding(new RsaEngine());
    
    
                //解密  
    
    
                //1024长度是128,双方协商好
                int maxBlockSize = privateKeySize / 8; //解密块最大长度限制
    
                engine.Init(false, isPublicKey ? GetPublicKeyParameter(key) : GetPrivateKeyParameter(key));
                byte[] byteData = Convert.FromBase64String(orgData);
    
                int inputLen = byteData.Length;
                MemoryStream ms = new MemoryStream();
                int offSet = 0;
                byte[] cache;
                int i = 0;
                // 对数据分段加密
                while (inputLen - offSet > 0)
                {
                    if (inputLen - offSet > maxBlockSize)
                    {
                        cache = engine.ProcessBlock(byteData, offSet, maxBlockSize);
                    }
                    else
                    {
                        cache = engine.ProcessBlock(byteData, offSet, inputLen - offSet);
                    }
                    ms.Write(cache, 0, cache.Length);
                    i++;
                    offSet = i * maxBlockSize;
                }
                byte[] encryptedData = ms.ToArray();
    
                //var ResultData = engine.ProcessBlock(byteData, 0, byteData.Length);
                return Encoding.UTF8.GetString(ms.ToArray());
                //Console.WriteLine("密文(base64编码):" + Convert.ToBase64String(testData) + Environment.NewLine);
    
            }
    
        }
    }
    复制代码

     

    使用代码:

     

    复制代码
    using CommonUtils;
    using System;
    
    namespace ConsoleNetFxRsa加密签名使用BC库
    {
        class Program
        {
            static void Main(string[] args)
            {
                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);                
    
                    #region 一、私钥签名
                    //string algorithm = "SHA1withRSA";
                    string algorithm = "SHA256withRSA";
                    string strSigned = BCSignUtil.SignData(strDJM, strPriPkcs8, algorithm); //PKCS8
                    Console.WriteLine("签名值:" + strSigned);
                    #endregion
    
                    #region 二、公钥验签(验证签名)
                    //二、公钥验签(验证签名)
                    //验证签名
                    bool bCheck = BCSignUtil.VerifySignature(strDJM, strPub, strSigned, algorithm);//验证签名双方要保持一致
                    Console.WriteLine("验证签名:" + bCheck.ToString());
                    #endregion
    
              //私钥长度,常用 1024 或 2048 int privateKeySize = 1024; //公钥加密 string strJiamihou= BCSignUtil.EncryptByKey(strDJM, strPub,true, privateKeySize); Console.WriteLine("加密后:" + strJiamihou); //私钥解密 string strJiemihou = BCSignUtil.DecryptByKey(strJiamihou, strPriPkcs8, false, privateKeySize); Console.WriteLine("解密后:" + strJiemihou); //私钥加密 strJiamihou = BCSignUtil.EncryptByKey(strDJM, strPriPkcs8, false, privateKeySize); Console.WriteLine("私钥加密后:" + strJiamihou); //公钥解密 strJiemihou = BCSignUtil.DecryptByKey(strJiamihou, strPub, true, privateKeySize); Console.WriteLine("公钥解密后:" + strJiemihou); } catch (Exception ex) { Console.WriteLine("ex:" + ex.Message); } Console.WriteLine("hello END."); Console.ReadKey(); } } }
    复制代码

     

    这里演示了2组:

    1:公钥加密,私钥解密。

    2:私钥加密,公钥解密。

  • 相关阅读:
    STL总结
    腾讯云直播updateRemoteVideo报错
    Linux磁盘管理
    linux安全--Nginx与Tomcat实现负载均衡
    HBuilder开发者必备!Windows上传IPA文件的软件分享
    python 动态导入模块,实现模块热更新
    ManoMano、eMAG等跨境平台如何实现快速出单?测评自养号助你快速突破!
    10_Linux基础-SHELL入门1
    网络基础原理概述
    企业怎样做好工厂生产人员管理?
  • 原文地址:https://www.cnblogs.com/runliuv/p/17531440.html