千里之行,始于足下

酌贪泉而觉爽,处涸辙而犹欢

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
  刚刚看了一些 Windows Vista 的宣传资料,感觉就是一个字:炫。显然 Vista 在用户体验上又大大进了一步,不知道能否赶得上当年 Windows 95 对 Windows 3.1 的跨越。只是不知道我的本本将来能不能平滑地跑上 Vista 呢。再看看一些新的技术,不禁大为感慨,心想现有的很多地方还没碰过呢,又有这么多新技术来了,做程序员,真是件既快乐又辛苦的事。好了,闲话少说,接下来说说我对 .net framework 中关于加密部分内容的学习和理解。

  一、对称加密算法

  .net 对于对称加密算法提供了4个类:DESCryptoServiceProvider、RC2CryptoServiceProvider、RijndaelManaged 和 TripleDESCryptoServiceProvider。它们都继承于 System.Security.Cryptography 命名空间中的 SymmetricAlgorithm 类,因此使用方法也基本上是差不多的。前两个分别对应于 DES 和 RC2 算法。相对来说,后面两个更好一些,Rijndael 是 AES (高级加密标准)算法的一种实现,而 TripleDES 则是使用 DES 算法的三次连续迭代,即三重 DES 加密。在密钥长度上,DES 是 56 位,三重 DES 是 112 或者 168 位,AES 则是 128、192 或者 256位。循环次数上,DES 需要 16 次,三重 DES 需要 48 次,AES 根据密钥长度只需要 10、12 或 14 次。从一些数据上来看,或许 AES 确实更好一些呢,不过我还没有进行过测试。

  以一个使用示例来说明。这个例子可以在 .net framework SDK 中找到:

 1TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();          
 2CryptoStream encStream = new CryptoStream(fout, tdes.CreateEncryptor(tdesKey, tdesIV), CryptoStreamMode.Write);
 3               
 4while(rdlen < totlen)
 5{
 6    len = fin.Read(bin, 0100);
 7    encStream.Write(bin, 0, len);
 8    rdlen = rdlen + len;
 9}

10
11encStream.Close();

  .net 中,对称加密和解密是使用过程流来实现的。如第2行中的 CryptoStream,在这里的构造过程中,第一个参数将 CryptoStream 与 fout 进行关联,这里 fout 一般是输出结果的一个 FileStream。第二个参数则是使用了 TripleDESCryptoServiceProvider 类的 CreateEncryptor 方法产生了一个加密器对象,由它来完成实际的加密过程。如果我们需要的是解密,那么这里可以使用 CreateDecryptor 方法。它们返回的其实都是 ICryptoTransform 接口。

  例子中我们可以看到 CreateEncryptor 方法使用了两个参数,第一个参数对应于密钥,这个很好理解,对称加密算法嘛,当然需要一个密钥了。第二个参数对应于一个叫“初始化向量”的东西。在解释初始化向量之前先说一句,如果我们没有事先指定的密钥和初始化向量,也可以让加密类给我们生成一个随机的。

  好,那么什么是“初始化向量”?它起什么作用呢?我们先设想一下,加密过程中当遇到相同的数据时,如果加密出来的结果也是相同的,那么这种加密显然比较容易破解。因此加密算法在加密一个数据块时,需要同时使用密钥和上一个块的加密结果,这样一来,即使是相同的数据块,加密出来的结果就也是不同的了。但是,由于最前头的第一个数据块没有前导输入,怎么办?这里就要用到我们的初始化向量了。它就与密钥一起对第一个块进行加密。

  接下来的几行就很好理解了,从输入流中读取数据,经过加密过程的处理后送到输出流,加密过程就完成了。相应地,在解密的时候,使用相同的密钥和初始化向量创建一个解密器,再处理一次就 OK 了。

  二、不对称加密算法

  不对称加密(dissymmetrical encryption),有时又叫公开密钥算法(public key algorithm)。这种加密算法是这样设计的:用作加密的密钥不同于用作解密的密钥,而且解密密钥不能根据加密密钥计算出来(至少在合理假定的长时间内)。之所以又叫做公开密钥算法是由于加密密钥可以公开,即陌生人可以得到它并用来加密信息,但只有用相应的解密密钥才能解密信息。在这种加密算法中,加密密钥被叫做公开密钥(public key),而解密密钥被叫做私有密钥(private key)。

  前面的原理部分看起来似乎很复杂,不过实际应用中,大部分情况其实还是比较简单的。.net framework 提供的不对称加密类有 RSACryptoServiceProvider 和 DSACryptoServiceProvider 两个,分别对应于 RSA 和 DSA 算法,它们的用法都差不多,举例说明:

 1static public byte[] RSAEncrypt(byte[] DataToEncrypt, RSAParameters RSAKeyInfo, bool DoOAEPPadding)
 2{
 3    try
 4    {    
 5        RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
 6        RSA.ImportParameters(RSAKeyInfo);
 7        return RSA.Encrypt(DataToEncrypt, DoOAEPPadding);
 8    }

 9    catch(CryptographicException e)
10    {
11        //error handling
12    }

13}

14
15static public byte[] RSADecrypt(byte[] DataToDecrypt, RSAParameters RSAKeyInfo,bool DoOAEPPadding)
16{
17    try
18    {
19        RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
20        RSA.ImportParameters(RSAKeyInfo);
21        return RSA.Decrypt(DataToDecrypt, DoOAEPPadding);
22    }

23    catch(CryptographicException e)
24    {
25        //error handling
26    }

27}

28
29
30RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
31encryptedData = RSAEncrypt(dataToEncrypt,RSA.ExportParameters(false), false);
32decryptedData = RSADecrypt(encryptedData,RSA.ExportParameters(true), false);

  从第 30 行看起,首先值得我们注意的是 ExportParameters 方法,它返回一个 RSAParameters 结构。它包含了 RSA 算法所需要的信息。这个方法带一个 bool 型的参数,当它为 true 时,会将公钥和私钥一起导出;当它为 false 时,只导出公钥。

  从 ExportParameters 导出的信息随后可以被另一个 RSACryptoServiceProvider 类以 ImportParameters 方法获取,随后就可以调用 Encrypt 方法进行加密过程。注意第7行中,参数 DoOAEPPadding 指定加密过程是否使用 OAEP 填充,注意它只能在 Windows XP 或更高版本的 Windows 中为 true。

  这个例子中可以很明显地看出来,在进行加密的时候,使用的信息是不包括私钥的,也就是说只须使用公钥即可完成加密过程。然而解密过程就必须要使用私钥了。所以第 32 行中,ExportParameters 方法的参数必须为 true。

  非对称加密算法的一个重要应用就是数字签名。可以使用加密类的 SignData 和 VerifyData 方法来完成这一过程。

1RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
2rsa.FromXmlString(fullKey);
3byte[] signature = rsa.SignData(originalData, "SHA1");
4
5rsa.FromXmlString(publicKey);
6bool result = rsa.VerifyData(verifyData, "SHA1", signature);
7


  第二行中的 fullKey 和第五行中的 publicKey 是预先从 XML 文件中读入的,fullKey 中包含了公钥和私钥信息,publicKey 则只包含公钥信息。这些信息都是同 RSAParameters 结构的数据对应的。区别只在于 publicKey 只包含了 Modulus 和 Exponent,而 fullKey 还含有 P、Q、DP、DQ、InverseQ 和 D。

  我们看到,在设定密钥信息后,即可调用 SignData 方法对 orginalData 使用 SHA1 算法进行签名,获得 signature。随后它就可以被 VerifyData 方法用来做验证。verifyData 参数则是需要验证的数据。

  与此类似的还有 SignHash 和 VerifyHash 方法,这两个方法的使用,在 .net framework SDK 中有详细的例子,这里不再列了。

  顺便摘一段关于数字签名的一种技术实现过程。(原文来自中国烟台网商务频道)

  ============================

  加入数字签名和验证的文件传输过程如下:

  1、发送方首先用哈希函数从原文得到数字签名,然后采用公开密钥体系用发送方的私有密钥对数字签名进行加密,并把加密后的数字签名附加在要发送的原文后面。

  2、发送方选择一个秘密密钥对文件进行加密,并把加密后的文件通过网络传输到接收方。

  3、发送方用接收方的公开密钥对密秘密钥进行加密,并通过网络把加密后的秘密密钥传输到接收方。

  4、接受方使用自己的私有密钥对密钥信息进行解密,得到秘密密钥的明文。

  5、接收方用秘密密钥对文件进行解密,得到经过加密的数字签名。

  6、接收方用发送方的公开密钥对数字签名进行解密,得到数字签名的明文。

  7、接收方用得到的明文和哈希函数重新计算数字签名,并与解密后的数字签名进行对比。如果两个数字签名是相同的,说明文件在传输过程中没有被破坏。

  如果第三方冒充发送方发出了一个文件,因为接收方在对数字签名进行解密时使用的是发送方的公开密钥,只要第三方不知道发送方的私有密钥,解密出来的数字签名和经过计算的数字签名必然是不相同的。这就提供了一个安全的确认发送方身份的方法。

  数字签名的加密解密过程和秘密密钥的加密解密过程虽然都使用公开密钥体系,但实现的过程正好相反,使用的密钥对也不同。数字签名使用的是发送方的密钥对,发送方用自己的私有密钥进行加密,接收方用发送方的公开密钥进行解密。这是一个一对多的关系:任何拥有发送方公开窃钥的人都可以验证数字签名的正确性,而秘密密钥的加密解密则使用的是接收方的密切对,这是多对一的关系:任何知道接收方公开密钥的人都可以向接收方发送加密信息,只有唯一拥有接收方私有密钥的人才能对信息解密。这是一个复杂但又很有趣的过程。在实用过程中,通常一个用户拥有两个密钥对一一一个密钥对用来对数字签名进行加密解密,一个密钥对用来对秘密密钥进行加密解密。这种方式提供了更高的安全性。

  ============================

  摘抄的这一段,有哪些高人能够完全看懂?反正我还没完全弄明白~~~~困了,要睡觉了,先搁这儿,过几天再来回头琢磨罢!

posted on 2006-04-06 22:45  sunwaywei  阅读(2396)  评论(3编辑  收藏  举报