非对称加密RSA的应用及在C#中的实现
一说到数据的加密,常常会涉及到这几个单词:算法、原文、密文和密钥。通常,发送者把原文通过一个加密的算法,用密钥进行加密后将密文发送给接收者,然后接收者再用密钥对密文进行解密,得到原文。由于常用的加密算法都是公开的,所以,对原文的加密的关键,就是密钥了。对于这种加解密都使用同样的密钥的算法,我们称之为对称加密,对称加密的代表算法就是DES家族了。那么这种对称加密有什么缺陷呢?由于加解密使用相同的密钥,那么这个密钥最少要保存在两个地方,如果加密的数据要发给多人,那么就会有更多的人知道密钥,这大大增加了密钥泄露的风险;并且密钥需要由发送方传递给接收方,那么如何保证密钥的传递的安全,则成了另外一个头疼的事情。为了解决这个问题,相对于对称加密,又出现了非对称加密。
什么是非对称加密?所谓的非对称加密,就是指加密和解密使用不同的密钥的一类加密算法。这类加密算法通常有两个密钥A和B,使用密钥A加密数据得到的密文,只有密钥B可以进行解密操作(即使密钥A也无法解密),相反,使用了密钥B加密数据得到的密文,只有密钥A可以解密。这两个密钥分别称为私钥和公钥,顾名思义,私钥就是你个人保留,不能公开的密钥,而公钥则是公开给加解密操作的另一方的。根据不同用途,对数据进行加密所使用的密钥也不相同(有时用公钥加密,私钥解密;有时相反用私钥加密,公钥解密)。非对称加密的代表算法是RSA算法。
那么非对称加密到底有哪些用途?
第一个用途当然是做数据加密。
请大家想象一下,如果我不想让除了接收方以外的其他人,知道我发送的数据的内容的话,需要用哪种密钥对数据进行加密?如果我使用私钥加密,那么根据非对称加密的原理,接收方需要使用公钥来解密,而公钥我已经公开给接收方了,这个方案似乎是可行的,可是这样做问题就出现在公钥上了。在非对称加密中,公钥的公开不仅仅指对接收方的公开,而是指这个密钥彻底的公开,任何人需要都可以得到,这样的话你发送的数据就没有任何秘密可言了。反过来,如果我使用公钥对数据加密,那么对于接收方来说就需要使用私钥进行数据解密,由于私钥只保存在接收方手中,这样其他人就不会得到数据的内容了。这样看来,在非对称加密中,如果需要保护你的数据不被第三者得到,密钥需要由接收方产生,然后接收方将公钥公开出去,发送方使用这个公开的公钥对数据进行加密后传输给接收方,接收方使用自己的私钥进行解密,从而保证了数据的安全性。所以非对称加密又称为公钥加密。
非对称加密的执行效率要远低于对称加密,所以我们不会对一个大的文件或数据使用非对称加密算法。那么我们如何加密一个大的文件呢?通常情况我们可以选择对称加密算法加密文件,然后使用非对称算法加密对称算法的密钥,这样就保证了对称算法密钥传递的安全性。
非对称加密的另外一个用途就是用来进行数字签名。
什么是数字签名?数字签名同我们在合同上的签字一样,接收方可以用它来证明收到的数据或文件是由你发送的。举个例子:假设发送方需要将一串数据D发送给接收方,那么接收方如何判断数据D是发送方发送的呢?
Step 1:发送方先产生成一对密钥,并将公钥公开给接收方;
Step 2:发送方将数据D用私钥进行加密得到密文M,然后将数据D和密文M一起发送给接收方;
Step 3:接收方得到数据D和密文M后,用公钥将密文M解密得到d;
Step 4:比较D和d,相等则证明D是由发送方发送的。
在实际的操作中,我们并不会直接用私钥去加密要发送的数据或文件,这是因为非对称加密的算法非常耗时并且密文的长度要大于明文的长度,直接加密系统的开销非常大。那么如何实解决这个问题呢?
首先,我们需要了解另外一个概念:消息摘要。所谓的消息摘要就是通过一种单向算法计算出来的唯一对应一个文件或数据的固定长度的值,也被称作数字摘要。根据不同的算法,消息摘要的长度一般为128位或160位。常用的消息摘要的算法有MD5和SHA1。一个文件的消息摘要就同一个人的指纹一样,它可以唯一代表这个文件,如果这个文件被修改了,那么它的消息摘要也一定会发生变化,所以,我们可以通过对一个文件的消息摘要进行签名来代替对它本身进行签名。并且,我们还可以通过验证消息摘要,来确定发送的数据是否完整或曾经被修改过。这样,上面的例子大致可以变为下面这样:
Step 1:发送方先产生成一对密钥,并将公钥公开给接收方;
Step 2:发送方将数据D进行消息摘要,得到Q;
Step 3:用私钥对Q进行加密得到密文MQ,然后将数据D和密文MQ一起发送给接收方;
Step 4:接收方得到数据D和密文MQ后,用公钥将密文MQ解密得到q1;
Step 5:接收方使用相同的算法对数据D进行消息摘要,得到q2;
Step 6:比较q1和q2,相等则证明D是由发送方发送的,且没有被修改过。
好了,非对称加密的使用介绍了一大堆,后面我们来看看如何用C#来实现RSA非对称加密。
.Net中的加密操作所涉及的对象都在命名空间System.Security.Cryptography下,所以请先在你的程序中添加using System.Security.Cryptography; 其中,RSA加密算法由RSACryptoServiceProvider对象实现。下面的代码分别实现了数据的加密解密和签名与验证。
1: string PublicKey, PrivateKey;
2: RSACryptoServiceProvider rsaProvider;
3: void Initial()
4: {
5: //声明一个RSA算法的实例,由RSACryptoServiceProvider类型的构造函数指定了密钥长度为1024位
6: //实例化RSACryptoServiceProvider后,RSACryptoServiceProvider会自动生成密钥信息。
7: rsaProvider = new RSACryptoServiceProvider(1024);
8: //将RSA算法的公钥导出到字符串PublicKey中,参数为false表示不导出私钥
9: PublicKey = rsaProvider.ToXmlString(false);
10: //将RSA算法的私钥导出到字符串PrivateKey中,参数为true表示导出私钥
11: PrivateKey = rsaProvider.ToXmlString(true);
12:
13:
14: byte[] EncryptData(byte[] data)
15: {
16: RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(1024);
17: //将公钥导入到RSA对象中,准备加密;
18: rsa.FromXmlString(PublicKey);
19: //对数据data进行加密,并返回加密结果;
20: //第二个参数用来选择Padding的格式
21: return rsa.Encrypt(data, false);
22: }
23:
24: byte[] DecryptData(byte[] data)
25: {
26: RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(1024);
27: //将私钥导入RSA中,准备解密;
28: rsa.FromXmlString(PrivateKey);
29: //对数据进行解密,并返回解密结果;
30: return rsa.Decrypt(data, false);
31: }
32:
33: byte[] Sign(byte[] data)
34: {
35: RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(1024);
36: //导入私钥,准备签名
37: rsa.FromXmlString(PrivateKey);
38: //将数据使用MD5进行消息摘要,然后对摘要进行签名并返回签名数据
39: return rsa.SignData(data, "MD5");
40: }
41:
42: bool Verify(byte[] data, byte[] Signature)
43: {
44: RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(1024);
45: //导入公钥,准备验证签名
46: rsa.FromXmlString(PublicKey);
47: //返回数据验证结果
48: return rsa.VerifyData(data, "MD5", Signature);
49: }
关于RSA更多的内容,大家可以参照MSDN和网络上的教程自己动手进行练习。我会在后面的文章中继续讲解关于密钥的保存方面的内容,希望大家喜欢。
另外希望大家到网上查查RSA的具体算法,非常有意思,并且非常佩服设计出这些算法的人,真不知道他们的脑袋里装的都是什么~~