.NET_RSA加密全接触(重、难点解析)
2011-03-08 14:18
351 查看
.NET_RSA加密全接触(重、难点解析)
.NET Framework提供了两个类供我们使用RSA算法,分别是:用于加密数据的RSACryptoServiceProvider和用于数字签名的DSACryptoServiceProvider,本文主要谈论RSACryptoServiceProvider的使用以及微软实现RSA算法时的一些主要特点。
1、.NET中RSA密钥格式
RSA的密钥有两种表现形式,一种是通过RSAParameters对象来表现,另一种是通过XML字符串来表现,当通过默认构造函数构造一个RSACryptoServiceProvider实例的时候,会自动生成一对公私钥,可以通过调用其ExportParameters()方法或ToXmlString()方法导出密钥(分别对应前面所述的两种表现形式)。这两种表现形式的本质是一样的,前者是一个含有八个字段的结构体,后者是一个含有八个XML配置节的XMLNODE,这八个元素的名称分别为:
D、DP、DQ、Exponent、InverseQ、Modulus、Q
要了解这些元素的意义,首先需要了解构造公私钥的过程
A) 找到两个大素数P和q,相乘得n
B) 选择一个数e,它小于n且与n互素,得到公钥(e,n)
C) 得到一个数d,它满足(d*e)mod ((p-1)*(q-1))=1,得到私钥(d,n)
D) 纯文本m到密文c的加密过程c=(m^e)mod n,解密过程为m=(c^d)mod n,加密解密过程是可逆的。
了解了密钥的构造过程,下面是这八个元素的详细解释:
第三列的“PKCS”指的是一种RSA加密标准,类似于这样的标准有多个,下文会进行叙述!
2、.NET中加密结果的不确定性
Net环境下对同一个字符串用相同的RSA公钥加密,每次的结果都会不一样!如下程序所示:
class Program
{
static void Main(string[] args)
{
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
byte[] c=rsa.Encrypt(UTF8Encoding.UTF8.GetBytes("hello"),true);
Console.WriteLine(Convert.ToBase64String(c));
Console.ReadLine();
}
}
出现这种结果不确定的原因在于:.Net为了加强RSA加密算法的安全性,在每次加密的时候都会生成一定的随机数和原始数据一起被加密,这显然不是单纯标准的RSA加密 。
其实这些随机数的生成也是遵循算法标准的,更专业的说是随机填充算法,比如NoPadding、ISO10126Padding、OAEPPadding、PKCS1Padding、PKCS5Padding、SSL3Padding,而最常见的应该是OAEPPadding【Optimal Asymmetric Encryption Padding】、PKCS1Padding;.Net支持PKCS1Padding或OAEPPadding,其中OAEPPadding仅在XP或更高版本的操作系统上可用。此处不在讨论这些填充算法的具体细节,读者朋友只需知道有这些填充标准即可,需要强调的一点是:不论是.net,java或者是C++等,只要他们用相同的填充标准,即使每次加密的结果都不一样,不同语言之间照样可以互通!
3、关于密钥的Base64编码(AQAB=65537是怎样得到的?)
大家都知道RSACryptoServiceProvider的ToXmlString()方法可以将公私钥导出到一个XML
字符串中,并且是以Base64编码的形式导出的。感兴趣的读者可以用Reflector反编译微软的dll文件,你会发现,这个方法导出的字符串就是分别对RSAParameters的八个字段(八个字节数组)进行Base64编码,然后串在一起得到的。
前面说到,当我们通过默认构造函数创建一个RSACryptoServiceProvider的实例的时候,会自动产生对应于该实例的一对儿公私钥,这种情况下微软选择的公钥都是一样的,都是65537,这个65537转化成的字节数组就是RSAParameters的Exponent的值,AQAB就是由65537编码而来。
65537的转化成的字节数组是什么样的?可能有读者会说,非常简单,一条语句就够了,用Convert.ToBase64Array(“65537”)即可!错!这样想的读者应该思考一下,此处的65537是什么?对,它是一个大素数,是一个数字,并不是一个字符串,我们应该将其转化为二进制串,然后每八位一截取,得到其对应的字节数组!此处限于篇幅不在详细叙述得到“AQAB”的详细过程,读者朋友可以参见该博客所述:/article/4717811.html
4、密钥的保存
对于临时会话,无需保存密钥,但是很多情况下我们需要重复的使用一组密钥,此时就需要将密钥保存下来,在.NET中保存密钥主要有三种方法:
1、 将密钥导出到本地文件,然后对文件进行加密;
2、 利用Windows系统的数据保护API;
从Windows2000开始,Windows操作系统提供了一套密码学方面的API,称为DAPI(Data Protection API,数据保护API)。这套API由crypt32.dll库实现,可以实现用户、进程、会话或机器级别上的数据加密保护,从而确保它们的机密性,这样就使我们不再需要负责密钥的管理。
.Net中我们可以将密钥对儿保存到密钥容器中,这个密钥容器由操作系统管理,可以是用户级别的容器,也可以是机器级别的容器。密钥容器是公用的,只不过在不同的语言中有不同的实现,这样在.net中创建的公私钥对儿,C、C++程序也都可以读取。
.NET中可以使用CspParameters对象创建或使用密钥容器
1)实例化CspParameters对象CspParameters cspPara = new CspParameters();
2)指定CspParameters对象实例的名称 ,cspPara.KeyContainerName = "test"。如果名称为key_container_test的密钥容器不存在,RSA对象会创建这个密钥容器;如果名称为key_container_test的密钥容器已经存在,RSA对象会使用这个密钥容
器。
3)设置密钥类型为Exchange ,cspPara.KeyNumber = 1;
4)设置密钥容器保存到计算机密钥库(默认为用户密钥库,cspPara.Flags = CspProviderFlags.UseMachineKeyStore
3、 利用数字证书
此处不再详述,参考文档1、“.NET中非对称加密RSA算法的密钥保存”
2、“了解计算机级别和用户级别的 RSA 密钥容器”
5、.net和java端的RSA互通
.net和java的RSA互通要谈论的东西比较多,请参见另一篇文章“.NET和Java的RSA互通,仅此而已!”
.NET Framework提供了两个类供我们使用RSA算法,分别是:用于加密数据的RSACryptoServiceProvider和用于数字签名的DSACryptoServiceProvider,本文主要谈论RSACryptoServiceProvider的使用以及微软实现RSA算法时的一些主要特点。
1、.NET中RSA密钥格式
RSA的密钥有两种表现形式,一种是通过RSAParameters对象来表现,另一种是通过XML字符串来表现,当通过默认构造函数构造一个RSACryptoServiceProvider实例的时候,会自动生成一对公私钥,可以通过调用其ExportParameters()方法或ToXmlString()方法导出密钥(分别对应前面所述的两种表现形式)。这两种表现形式的本质是一样的,前者是一个含有八个字段的结构体,后者是一个含有八个XML配置节的XMLNODE,这八个元素的名称分别为:
D、DP、DQ、Exponent、InverseQ、Modulus、Q
要了解这些元素的意义,首先需要了解构造公私钥的过程
A) 找到两个大素数P和q,相乘得n
B) 选择一个数e,它小于n且与n互素,得到公钥(e,n)
C) 得到一个数d,它满足(d*e)mod ((p-1)*(q-1))=1,得到私钥(d,n)
D) 纯文本m到密文c的加密过程c=(m^e)mod n,解密过程为m=(c^d)mod n,加密解密过程是可逆的。
了解了密钥的构造过程,下面是这八个元素的详细解释:
RSAParameters 字段 | Contains | 对应的 PKCS #1 字段 |
D | d,私钥指数 | privateExponent |
DP | d mod (p - 1) | exponent1 |
DQ | d mod (q - 1) | exponent2 |
Exponent | e,公钥指数 | publicExponent |
InverseQ | (InverseQ)(q) = 1 mod p | Coefficient |
Modulus | N | Modulus |
P | P | prime1 |
Q | Q | prime2 |
2、.NET中加密结果的不确定性
Net环境下对同一个字符串用相同的RSA公钥加密,每次的结果都会不一样!如下程序所示:
class Program
{
static void Main(string[] args)
{
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
byte[] c=rsa.Encrypt(UTF8Encoding.UTF8.GetBytes("hello"),true);
Console.WriteLine(Convert.ToBase64String(c));
Console.ReadLine();
}
}
出现这种结果不确定的原因在于:.Net为了加强RSA加密算法的安全性,在每次加密的时候都会生成一定的随机数和原始数据一起被加密,这显然不是单纯标准的RSA加密 。
其实这些随机数的生成也是遵循算法标准的,更专业的说是随机填充算法,比如NoPadding、ISO10126Padding、OAEPPadding、PKCS1Padding、PKCS5Padding、SSL3Padding,而最常见的应该是OAEPPadding【Optimal Asymmetric Encryption Padding】、PKCS1Padding;.Net支持PKCS1Padding或OAEPPadding,其中OAEPPadding仅在XP或更高版本的操作系统上可用。此处不在讨论这些填充算法的具体细节,读者朋友只需知道有这些填充标准即可,需要强调的一点是:不论是.net,java或者是C++等,只要他们用相同的填充标准,即使每次加密的结果都不一样,不同语言之间照样可以互通!
3、关于密钥的Base64编码(AQAB=65537是怎样得到的?)
大家都知道RSACryptoServiceProvider的ToXmlString()方法可以将公私钥导出到一个XML
字符串中,并且是以Base64编码的形式导出的。感兴趣的读者可以用Reflector反编译微软的dll文件,你会发现,这个方法导出的字符串就是分别对RSAParameters的八个字段(八个字节数组)进行Base64编码,然后串在一起得到的。
前面说到,当我们通过默认构造函数创建一个RSACryptoServiceProvider的实例的时候,会自动产生对应于该实例的一对儿公私钥,这种情况下微软选择的公钥都是一样的,都是65537,这个65537转化成的字节数组就是RSAParameters的Exponent的值,AQAB就是由65537编码而来。
65537的转化成的字节数组是什么样的?可能有读者会说,非常简单,一条语句就够了,用Convert.ToBase64Array(“65537”)即可!错!这样想的读者应该思考一下,此处的65537是什么?对,它是一个大素数,是一个数字,并不是一个字符串,我们应该将其转化为二进制串,然后每八位一截取,得到其对应的字节数组!此处限于篇幅不在详细叙述得到“AQAB”的详细过程,读者朋友可以参见该博客所述:/article/4717811.html
4、密钥的保存
对于临时会话,无需保存密钥,但是很多情况下我们需要重复的使用一组密钥,此时就需要将密钥保存下来,在.NET中保存密钥主要有三种方法:
1、 将密钥导出到本地文件,然后对文件进行加密;
2、 利用Windows系统的数据保护API;
从Windows2000开始,Windows操作系统提供了一套密码学方面的API,称为DAPI(Data Protection API,数据保护API)。这套API由crypt32.dll库实现,可以实现用户、进程、会话或机器级别上的数据加密保护,从而确保它们的机密性,这样就使我们不再需要负责密钥的管理。
.Net中我们可以将密钥对儿保存到密钥容器中,这个密钥容器由操作系统管理,可以是用户级别的容器,也可以是机器级别的容器。密钥容器是公用的,只不过在不同的语言中有不同的实现,这样在.net中创建的公私钥对儿,C、C++程序也都可以读取。
.NET中可以使用CspParameters对象创建或使用密钥容器
1)实例化CspParameters对象CspParameters cspPara = new CspParameters();
2)指定CspParameters对象实例的名称 ,cspPara.KeyContainerName = "test"。如果名称为key_container_test的密钥容器不存在,RSA对象会创建这个密钥容器;如果名称为key_container_test的密钥容器已经存在,RSA对象会使用这个密钥容
器。
3)设置密钥类型为Exchange ,cspPara.KeyNumber = 1;
4)设置密钥容器保存到计算机密钥库(默认为用户密钥库,cspPara.Flags = CspProviderFlags.UseMachineKeyStore
3、 利用数字证书
此处不再详述,参考文档1、“.NET中非对称加密RSA算法的密钥保存”
2、“了解计算机级别和用户级别的 RSA 密钥容器”
5、.net和java端的RSA互通
.net和java的RSA互通要谈论的东西比较多,请参见另一篇文章“.NET和Java的RSA互通,仅此而已!”
相关文章推荐
- .NET_RSA加密全接触(重、难点解析)
- .NET加密方式解析--散列加密
- Java与.Net 在RSA加密方面能不能互相通讯操作???
- Android 与 .net 互通的RSA加密
- C# RSA加密、解密、加签、验签、支持JAVA格式公钥私钥、PEM格式公钥私钥、.NET格式公钥私钥、一般模式【支持公钥加密,私钥解密】(一)
- Android RSA加密解密算法解析
- Java与.Net环境下RSA加密解密交互不成功的问题解决
- .NET中RSA使用数字证书加密解密
- Android中的RSA加密解析
- .net中RSA的加密与解密
- java与.net平台之间进行RSA加密验证
- ios客户端RSA公钥加密 .net后台私钥解密解决方案(基于Openssl)
- .NET加密方式解析--散列加密
- Android AES DES RSA 加密解密 解析
- Java与.Net环境下RSA加密解密交互不成功的问题解决【续】
- .NET使用RSA加密解密
- .net下RSA加密解密的封装
- .net中RSA的加密与解密
- Android 与 .net 互通的RSA加密
- RSA加解密使用总结,.net私钥加密公钥解密,WinCE平台RSA加解密