前言

这两天主要是公司同事用到了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, , maxBlockSize); while (blockSize > )
{
var blockByte = new byte[blockSize]; Array.Copy(buffer, , blockByte, , blockSize); var encrypts = rsa.Encrypt(blockByte, padding); readStream.Write(encrypts, , encrypts.Length); blockSize = memoryStream.Read(buffer, , maxBlockSize);
} return readStream.ToArray();
}
}
}
} public static byte[] Decrypt(byte[] decryptBytes, RSAEncryptionPadding padding)
{
using (var rsa = RSA.Create())
{
FromXmlString(rsa, privateKey); var maxBlockSize = rsa.KeySize / ; 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, , maxBlockSize); while (blockSize > )
{
var blockByte = new byte[blockSize]; Array.Copy(buffer, , blockByte, , blockSize); var decrypts = rsa.Decrypt(blockByte, padding); readStream.Write(decrypts, , decrypts.Length); blockSize = memoryStream.Read(buffer, , 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 = ;
if (padding.Mode == RSAEncryptionPaddingMode.Pkcs1)
{
offset = ;
}
else
{
if (padding.Equals(RSAEncryptionPadding.OaepSHA1))
{
offset = ;
} if (padding.Equals(RSAEncryptionPadding.OaepSHA256))
{
offset = ;
} if (padding.Equals(RSAEncryptionPadding.OaepSHA384))
{
offset = ;
} if (padding.Equals(RSAEncryptionPadding.OaepSHA512))
{
offset = ;
}
}
return rsa.KeySize / - offset;
}
}

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

        static void Main(string[] args)
{
var encryptString = "";
for (int i = ; i < ; 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环境未经测试,不知是否好使,一试见分晓。

ASP.NET Core RSA加密或解密的更多相关文章

  1. 通过ios实现RSA加密和解密

    在加密和解密中,我们需要了解的知识有什么事openssl:RSA加密算法的基本原理:如何通过openssl生成最后我们需要的der和p12文件. 废话不多说,直接写步骤: 第一步:openssl来生成 ...

  2. C#实现RSA加密和解密详解

    原文:C#实现RSA加密和解密详解 RSA加密解密源码: Code highlighting produced by Actipro CodeHighlighter (freeware) http:/ ...

  3. C#实现RSA加密与解密、签名与认证(转)

    一.RSA简介 RSA公钥加密算法是1977年由Ron Rivest.Adi Shamirh和LenAdleman在(美国麻省理工学院)开发的.RSA取名来自开发他们三者的名字.RSA是目前最有影响力 ...

  4. RSA加密和解密工具类

    import org.apache.commons.codec.binary.Base64; import javax.crypto.Cipher; import java.security.*; i ...

  5. IOS, Android, Java Web Rest : RSA 加密和解密问题

    IOS, Android, Java Web Rest :  RSA 加密和解密问题 一对公钥私钥可以使用 OpenSSL创建, 通常 1024位长度够了. 注意: 1. 公钥私钥是BASE64编码的 ...

  6. C#实现RSA加密与解密、签名与认证

    一.RSA简介 RSA公钥加密算法是1977年由Ron Rivest.Adi Shamirh和LenAdleman在(美国麻省理工学院)开发的.RSA取名来自开发他们三者的名字.RSA是目前最有影响力 ...

  7. C# -- RSA加密与解密

    1.  RSA加密与解密  --  使用公钥加密.私钥解密 public class RSATool { public string Encrypt(string strText, string st ...

  8. python RSA加密、解密、签名

    python RSA加密.解密.签名 python中用于RSA加解密的库有好久个,本文主要讲解rsa.M2Crypto.Crypto这三个库对于RSA加密.解密.签名.验签的知识点. 知识基础 加密是 ...

  9. RSA加密、解密实现原理

    RSA加密.解密实现原理 1.公钥.私钥

随机推荐

  1. 在离线环境中安装Visual Stuido 2017

    在离线环境中安装Visual Stuido 2017 0x00 写在前面的废话 因为工作上大多数都是在离线环境中进行的,进出离线环境很麻烦,所以之前很长一段时间都在使用VS2010.后来尝试换了VS2 ...

  2. webgl自学笔记——深度监测与混合

    这一章中关于webgl中颜色的使用我们将深入研究.我们将从研究颜色在webgl和essl中如何被组装和获取开始.然后我们讨论在物体.光照和场景中颜色的使用.这之后我们将看到当一个物体在另一个物体前面是 ...

  3. Linux 桌面玩家指南:10. 没有 GUI 的时候应该怎么玩

    特别说明:要在我的随笔后写评论的小伙伴们请注意了,我的博客开启了 MathJax 数学公式支持,MathJax 使用$标记数学公式的开始和结束.如果某条评论中出现了两个$,MathJax 会将两个$之 ...

  4. js取数组最大值的四种方式

    var arr = [7,2,0,-3,5];1.apply()应用某一对象的一个方法,用另一个对象替换当前对象 var max = Math.max.apply(null,arr);console. ...

  5. 【工具篇】Sublime Text 2 安装汉化破解、插件包安装教程详解

    Sublime Text概述: Sublime Text是一个代码编辑器,也是HTML和散文先进的文本编辑器. 漂亮的用户界面和非凡的功能,例如:迷你地图,多选择,Python插件,代码段等等. 完全 ...

  6. [Swift-2019力扣杯春季决赛]4. 有效子数组的数目

    给定一个整数数组 A,返回满足下面条件的 非空.连续 子数组的数目: 子数组中,最左侧的元素不大于其他元素. 示例 1: 输入:[1,4,2,5,3] 输出:11 解释:有 11 个有效子数组,分别是 ...

  7. SpringBoot技术栈搭建个人博客【后台开发】

    前言:在之前,我们已经完成了项目的基本准备,那么就可以开始后台开发了,突然又想到一个问题,就是准备的时候只是设计了前台的RESTful APIs,但是后台管理我们同样也是需要API的,那么就在这一篇里 ...

  8. RDIFramework.NET V3.3 WinForm版新增订单管理主从表事例

    功能描述 无论什么系统,除了常规的单表处理外,主从表的应用都是非常普遍的,RDIFramework.NET V3.3 WinForm版本中新增了一个主从表的事例供大家参考.主从表的界面设计大同小异,主 ...

  9. Nginx反向代理和Node.js后端解决跨域问题

    最近在写自己的博客,涉及到跨域的问题,自己捣鼓许久,终于解决了.然后总结一下,记录一下,日后遇到类似的问题的时候也可以得到一些启发. 一.什么是跨域 跨域,指的是浏览器不能执行其他网站的脚本.它是由浏 ...

  10. [TCP/IP] 网络层-抓包分析IP数据包首部

    ip数据包的结构:首部+数据部分 1.版本(v4或者v6)+首部长度(固定的20字节,所以就没有)+区分服务优先级(我的例子是 assured forwarding 31 0x1a 26,保证转发) ...