.net core linux下的RSA解密

2019-06-20  本文已影响0人  a9b854aded01

基础部分参考https://blog.csdn.net/sD7O95O/article/details/78412745?locationNum=8&fps=1

但是由于这里的RSA加密/解密主要是针对于由OpenSSL生成的公钥/私钥字符串。ssh-keygen -t rsa 命令生成的公钥私钥是不行的。

如果使用带签名的加密方式字符串就会出现

rsa.ImportParameters(rsaParameters);

无法解析到相应byte的问题

如果使用

 rsa = new RSACryptoServiceProvider(keySize, rsaParams);

可以解析带签名的RSA加密字符串,但是在linux下会出现错误

解析出错:System.PlatformNotSupportedException: 'CspParameters' requires Windows Cryptographic API (CAPI), which is not available on this platform.

有依赖包依赖于windows环境下的dll,linux下无法解析。

解决方案:
将参考部分的RSAHelper中rsa.ImportParameters(rsaParameters);获取公钥私钥byte的解析方案用下面解析方式替换掉

   /// <summary>
        /// 用PEM格式密钥对创建RSA,支持PKCS#1、PKCS#8格式的PEM
        /// </summary>
        public static System.Security.Cryptography.RSA FromPEM(string pem)
        {
            var rsa = System.Security.Cryptography.RSA.Create();

            var param = new RSAParameters();

            var base64 = _PEMCode.Replace(pem, "");
            var data = RSA_Unit.Base64DecodeBytes(base64);
            if (data == null)
            {
                throw new Exception("PEM内容无效");
            }
            var idx = 0;

            //读取长度
            Func<byte, int> readLen = (first) => {
                if (data[idx] == first)
                {
                    idx++;
                    if (data[idx] == 0x81)
                    {
                        idx++;
                        return data[idx++];
                    }
                    else if (data[idx] == 0x82)
                    {
                        idx++;
                        return (((int)data[idx++]) << 8) + data[idx++];
                    }
                    else if (data[idx] < 0x80)
                    {
                        return data[idx++];
                    }
                }
                throw new Exception("PEM未能提取到数据");
            };
            //读取块数据
            Func<byte[]> readBlock = () => {
                var len = readLen(0x02);
                if (data[idx] == 0x00)
                {
                    idx++;
                    len--;
                }
                var val = data.sub(idx, len);
                idx += len;
                return val;
            };
            //比较data从idx位置开始是否是byts内容
            Func<byte[], bool> eq = (byts) => {
                for (var i = 0; i < byts.Length; i++, idx++)
                {
                    if (idx >= data.Length)
                    {
                        return false;
                    }
                    if (byts[i] != data[idx])
                    {
                        return false;
                    }
                }
                return true;
            };




            if (pem.Contains("PUBLIC KEY"))
            {
                /****使用公钥****/
                //读取数据总长度
                readLen(0x30);
                if (!eq(_SeqOID))
                {
                    throw new Exception("PEM未知格式");
                }
                //读取1长度
                readLen(0x03);
                idx++;//跳过0x00
                      //读取2长度
                readLen(0x30);

                //Modulus
                param.Modulus = readBlock();

                //Exponent
                param.Exponent = readBlock();
            }
            else if (pem.Contains("PRIVATE KEY"))
            {
                /****使用私钥****/
                //读取数据总长度
                readLen(0x30);

                //读取版本号
                if (!eq(_Ver))
                {
                    throw new Exception("PEM未知版本");
                }

                //检测PKCS8
                var idx2 = idx;
                if (eq(_SeqOID))
                {
                    //读取1长度
                    readLen(0x04);
                    //读取2长度
                    readLen(0x30);

                    //读取版本号
                    if (!eq(_Ver))
                    {
                        throw new Exception("PEM版本无效");
                    }
                }
                else
                {
                    idx = idx2;
                }

                //读取数据
                param.Modulus = readBlock();
                param.Exponent = readBlock();
                param.D = readBlock();
                param.P = readBlock();
                param.Q = readBlock();
                param.DP = readBlock();
                param.DQ = readBlock();
                param.InverseQ = readBlock();
            }
            else
            {
                throw new Exception("pem需要BEGIN END标头");
            }

            rsa.ImportParameters(param);
            return rsa;
        }

依赖方法

 /// <summary>
    /// 封装的一些通用方法
    /// </summary>
    public class RSA_Unit
    {
        static public string Base64EncodeBytes(byte[] byts)
        {
            return Convert.ToBase64String(byts);
        }
        static public byte[] Base64DecodeBytes(string str)
        {
            try
            {
                return Convert.FromBase64String(str);
            }
            catch
            {
                return null;
            }
        }
        /// <summary>
        /// 把字符串按每行多少个字断行
        /// </summary>
        static public string TextBreak(string text, int line)
        {
            var idx = 0;
            var len = text.Length;
            var str = new StringBuilder();
            while (idx < len)
            {
                if (idx > 0)
                {
                    str.Append('\n');
                }
                if (idx + line >= len)
                {
                    str.Append(text.Substring(idx));
                }
                else
                {
                    str.Append(text.Substring(idx, line));
                }
                idx += line;
            }
            return str.ToString();
        }
    }

    static public class Extensions
    {
        /// <summary>
        /// 从数组start开始到指定长度复制一份
        /// </summary>
        static public T[] sub<T>(this T[] arr, int start, int count)
        {
            T[] val = new T[count];
            for (var i = 0; i < count; i++)
            {
                val[i] = arr[start + i];
            }
            return val;
        }
        static public void writeAll(this Stream stream, byte[] byts)
        {
            stream.Write(byts, 0, byts.Length);
        }
    }

这样经过测试上线可以在linux下解析出带签名的RSA加密字符串

       var rsa = new RSAHelper(RSAType.RSA, Encoding.UTF8, rsaprivate);
                Console.WriteLine("原始字符串:" + connection);
                //加密
                // string enStr = rsa.Encrypt(str);

                // Console.WriteLine("加密字符串:" + enStr);

                //解密
                // string deStr = rsa.DecodeOrNull(connection);
                var deStr = rsa.Decrypt(connection);

                Console.WriteLine("解密字符串:" + deStr);
                string finalconnection = MySqlHelper(deStr);

被坑了一下午,在同事的帮助下解决这个问题,希望能帮助到那些还再坑里的同学吧O(∩_∩)O哈哈~

上一篇下一篇

猜你喜欢

热点阅读