• ASP.NET Core RSA加密或解密


    前言

    这两天主要是公司同事用到了RSA加密,事后也看了下,以为很简单,最终利用RSACryptoServiceProvider来实现RSA加密,然后大致了解到RSACryptoServiceProvider不支持跨平台,此类原先存在于.NET Framework中,本文我讲讲利用RSA.Create来实现各种加密模式统一封装。

    RSA加密或解密

    主要是在查找资料时看到了dudu老大写的有关RSA加密的文章(http://www.cnblogs.com/dudu/p/dotnet-core-rsa-openssl.html),刚好找到了我们项目中需要用到的openssl加密模式对应.NET Core中的Pkcs1,这里实现代码实在有点多,然后自己也遇到如评论中所说加密长度超出的情况,这个时候只能采取分段加密的方式。接下来我们来看看。首先看看如下代码:

                var privateKey = "<RSAKeyValue><Modulus>0wE26IHp4U9OLtPhJ+fT8ej6aWORFP8pd++MjUuhkQQm/zhcImbxQbjxtSAftz+kkDwGDFJpSldQPyigOGcUx7PofTc6VhiFik9E9SsxV9n0iEEtqUndDfmBJfPAWt+4UDMwKakgZqFoapDuwjKlTErFvKCyKCs+qN9OZvZwKWk=</Modulus><Exponent>AQAB</Exponent><P>8Ei6NIsZtgV3DQjuGHfGLS6o1O+IUXxzjqLxdMm77yhEPUxR9YPIxODJ2VVTddXSAHxViJJt30yJ7JhVz6cpQw==</P><Q>4M49NrmalgVQFMsea2RMB1qN8fAPfIw5G9q9hzsLcWSCmkeRRIQlvPYflVEKAYKiDVVzENETbnnduFXWBABx4w==</Q><DP>t+JQbemN0Zi5FQaif6MZzHYKynpNTl75aE0Wj5Pa+RlNr8N6bXNe8Bw/HM2Jw4HQ5oJASvYUk3DVlHS4JuP8VQ==</DP><DQ>lT62iv9brp9mU/epgVh71SH8PJPIZEJfo6tryjyb0zMMNcqvmZI1z6aCv0mm3+vPFBUXqCF1yhFj7n4l8FAvSw==</DQ><InverseQ>flrvgxHvf4l+fdymEVDgKjsfGqshOpppoNgZj9kpeWBto3o8z++Ki6eSLQT3nVnpx2QCZeTWkxTED4nhSLKscw==</InverseQ><D>cQTCg1Eqk7sltmFYxUYgOP/AOPjSufteG9acYwYymPkvZh6rAuY+rSRBmvGE62NUYskzuB/gM6iG2/2HrA5SixfNgCvZ+nsK+kX5pzQRsYdD71ViQW0hOanXwj45I2zHRgBiuTtCUP0fs5pISmQkaeJkDL5pO2l+wvlgl+wunj0=</D></RSAKeyValue>";
                var publicKey = "<RSAKeyValue><Modulus>0wE26IHp4U9OLtPhJ+fT8ej6aWORFP8pd++MjUuhkQQm/zhcImbxQbjxtSAftz+kkDwGDFJpSldQPyigOGcUx7PofTc6VhiFik9E9SsxV9n0iEEtqUndDfmBJfPAWt+4UDMwKakgZqFoapDuwjKlTErFvKCyKCs+qN9OZvZwKWk=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";
    
                using (var rsa = RSA.Create())
                {
                    rsa.FromXmlString(publicKey);
                }

    经到github上查找解决方案,我们需要手动设置值,如下:

            public static void FromXmlString(RSA rsa, string xmlString)
            {
                RSAParameters parameters = new RSAParameters();
    
                XmlDocument xmlDoc = new XmlDocument();
                xmlDoc.LoadXml(xmlString);
    
                if (xmlDoc.DocumentElement.Name.Equals("RSAKeyValue"))
                {
                    foreach (XmlNode node in xmlDoc.DocumentElement.ChildNodes)
                    {
                        switch (node.Name)
                        {
                            case "Modulus": parameters.Modulus = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
                            case "Exponent": parameters.Exponent = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
                            case "P": parameters.P = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
                            case "Q": parameters.Q = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
                            case "DP": parameters.DP = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
                            case "DQ": parameters.DQ = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
                            case "InverseQ": parameters.InverseQ = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
                            case "D": parameters.D = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
                        }
                    }
                }
                else
                {
                    throw new Exception("Invalid XML RSA key.");
                }
    
                rsa.ImportParameters(parameters);
            }

    其中经过很多尝试,要么是Base64格式不正确,要么是待解密的数据长度和Key Size无效,我第一次尝试是返回的加密字符串,然后进行解密,就是有问题,最后还是返回字节数组来进行加密和解密,直接看代码,这里解决了加密数据长度超出问题以及各种加密模式的统一,如下RSAHelper。

        public static class RSAHelper
        {
            private const string privateKey = "<RSAKeyValue><Modulus>0wE26IHp4U9OLtPhJ+fT8ej6aWORFP8pd++MjUuhkQQm/zhcImbxQbjxtSAftz+kkDwGDFJpSldQPyigOGcUx7PofTc6VhiFik9E9SsxV9n0iEEtqUndDfmBJfPAWt+4UDMwKakgZqFoapDuwjKlTErFvKCyKCs+qN9OZvZwKWk=</Modulus><Exponent>AQAB</Exponent><P>8Ei6NIsZtgV3DQjuGHfGLS6o1O+IUXxzjqLxdMm77yhEPUxR9YPIxODJ2VVTddXSAHxViJJt30yJ7JhVz6cpQw==</P><Q>4M49NrmalgVQFMsea2RMB1qN8fAPfIw5G9q9hzsLcWSCmkeRRIQlvPYflVEKAYKiDVVzENETbnnduFXWBABx4w==</Q><DP>t+JQbemN0Zi5FQaif6MZzHYKynpNTl75aE0Wj5Pa+RlNr8N6bXNe8Bw/HM2Jw4HQ5oJASvYUk3DVlHS4JuP8VQ==</DP><DQ>lT62iv9brp9mU/epgVh71SH8PJPIZEJfo6tryjyb0zMMNcqvmZI1z6aCv0mm3+vPFBUXqCF1yhFj7n4l8FAvSw==</DQ><InverseQ>flrvgxHvf4l+fdymEVDgKjsfGqshOpppoNgZj9kpeWBto3o8z++Ki6eSLQT3nVnpx2QCZeTWkxTED4nhSLKscw==</InverseQ><D>cQTCg1Eqk7sltmFYxUYgOP/AOPjSufteG9acYwYymPkvZh6rAuY+rSRBmvGE62NUYskzuB/gM6iG2/2HrA5SixfNgCvZ+nsK+kX5pzQRsYdD71ViQW0hOanXwj45I2zHRgBiuTtCUP0fs5pISmQkaeJkDL5pO2l+wvlgl+wunj0=</D></RSAKeyValue>";
            private const string publicKey = "<RSAKeyValue><Modulus>0wE26IHp4U9OLtPhJ+fT8ej6aWORFP8pd++MjUuhkQQm/zhcImbxQbjxtSAftz+kkDwGDFJpSldQPyigOGcUx7PofTc6VhiFik9E9SsxV9n0iEEtqUndDfmBJfPAWt+4UDMwKakgZqFoapDuwjKlTErFvKCyKCs+qN9OZvZwKWk=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";
    
            public static byte[] Encrypt(byte[] encryptBytes, RSAEncryptionPadding padding)
            {
                using (var rsa = RSA.Create())
                {
    
                    FromXmlString(rsa, publicKey);
    
                    var maxBlockSize = GetMaxBlockSize(rsa, padding);
    
                    if (encryptBytes.Length <= maxBlockSize)
                    {
                        var @bytes = rsa.Encrypt(encryptBytes, padding);
                        return @bytes;
                    }
    
                    using (var memoryStream = new MemoryStream(encryptBytes))
                    {
                        using (var readStream = new MemoryStream())
                        {
                            byte[] buffer = new byte[maxBlockSize];
    
                            int blockSize = memoryStream.Read(buffer, 0, maxBlockSize);
    
                            while (blockSize > 0)
                            {
                                var blockByte = new byte[blockSize];
    
                                Array.Copy(buffer, 0, blockByte, 0, blockSize);
    
                                var encrypts = rsa.Encrypt(blockByte, padding);
    
                                readStream.Write(encrypts, 0, encrypts.Length);
    
                                blockSize = memoryStream.Read(buffer, 0, maxBlockSize);
                            }
    
                            return readStream.ToArray();
                        }
                    }
                }
            }
    
            public static byte[] Decrypt(byte[] decryptBytes, RSAEncryptionPadding padding)
            {
                using (var rsa = RSA.Create())
                {
                    FromXmlString(rsa, privateKey);
    
                    var maxBlockSize = rsa.KeySize / 8;
    
                    if (decryptBytes.Length <= maxBlockSize)
                    {
                        var @bytes = rsa.Decrypt(decryptBytes, padding);
                        return @bytes;
                    }
    
                    using (var memoryStream = new MemoryStream(decryptBytes))
                    {
                        using (var readStream = new MemoryStream())
                        {
                            var buffer = new byte[maxBlockSize];
    
                            var blockSize = memoryStream.Read(buffer, 0, maxBlockSize);
    
                            while (blockSize > 0)
                            {
                                var blockByte = new byte[blockSize];
    
                                Array.Copy(buffer, 0, blockByte, 0, blockSize);
    
                                var decrypts = rsa.Decrypt(blockByte, padding);
    
                                readStream.Write(decrypts, 0, decrypts.Length);
    
                                blockSize = memoryStream.Read(buffer, 0, maxBlockSize);
                            }
    
                            return readStream.ToArray();
                        }
                    }
                }
            }
    
            public static void FromXmlString(RSA rsa, string xmlString)
            {
                RSAParameters parameters = new RSAParameters();
    
                XmlDocument xmlDoc = new XmlDocument();
                xmlDoc.LoadXml(xmlString);
    
                if (xmlDoc.DocumentElement.Name.Equals("RSAKeyValue"))
                {
                    foreach (XmlNode node in xmlDoc.DocumentElement.ChildNodes)
                    {
                        switch (node.Name)
                        {
                            case "Modulus": parameters.Modulus = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
                            case "Exponent": parameters.Exponent = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
                            case "P": parameters.P = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
                            case "Q": parameters.Q = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
                            case "DP": parameters.DP = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
                            case "DQ": parameters.DQ = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
                            case "InverseQ": parameters.InverseQ = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
                            case "D": parameters.D = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
                        }
                    }
                }
                else
                {
                    throw new Exception("Invalid XML RSA key.");
                }
    
                rsa.ImportParameters(parameters);
            }
    
            static int GetMaxBlockSize(RSA rsa, RSAEncryptionPadding padding)
            {
                var offset = 0;
                if (padding.Mode == RSAEncryptionPaddingMode.Pkcs1)
                {
                    offset = 11;
                }
                else
                {
                    if (padding.Equals(RSAEncryptionPadding.OaepSHA1))
                    {
                        offset = 42;
                    }
    
                    if (padding.Equals(RSAEncryptionPadding.OaepSHA256))
                    {
                        offset = 66;
                    }
    
                    if (padding.Equals(RSAEncryptionPadding.OaepSHA384))
                    {
                        offset = 98;
                    }
    
                    if (padding.Equals(RSAEncryptionPadding.OaepSHA512))
                    {
                        offset = 130;
                    }
                }
                return rsa.KeySize / 8 - offset;
            }
        }

    我们开始进行如下测试,加密数据长度为6890,如下。

            static void Main(string[] args)
            {
                var encryptString = "0";
                for (int i = 1; i < 2000; i++)
                {
                    encryptString += i;
                }
    
                Console.WriteLine(encryptString.Length);
    
                var encryptBytes = Encoding.UTF8.GetBytes(encryptString);
    
                //加密后字节数组
                var resultBytes = RSAHelper.Encrypt(encryptBytes, RSAEncryptionPadding.Pkcs1);
    
                //解密后字节数组
                var decryptBytes = RSAHelper.Decrypt(resultBytes, RSAEncryptionPadding.Pkcs1);
    
                //解密结果
                var result = Encoding.UTF8.GetString(decryptBytes);
    
                //比较加密字符串和解密结果是否相等
                Console.WriteLine(encryptString == result);
                Console.ReadKey();
            }

    总结

    本文通过实现RSA加密和解密,同时也对加密数据超出采取分段加密的方式,测试在windows上通过,由于没有linux和mac环境未经测试,不知是否好使,一试见分晓。 

  • 相关阅读:
    React.render和reactDom.render的区别
    CSS中position的4种定位详解
    React.js入门必须知道的那些事
    JS处理事件小技巧
    React.js深入学习详细解析
    React.js实现原生js拖拽效果及思考
    Linux ./configure && make && make install 编译安装和卸载
    Redis set集合结构及命令详解
    Redis数据过期策略
    Redis TTL命令
  • 原文地址:https://www.cnblogs.com/CreateMyself/p/9853736.html
Copyright © 2020-2023  润新知