对称加密

(本文系张子阳《.net之美》读书笔记,文中多处引用书本内容)

首先简单介绍一下流的概念。

流的最主要用途就是与应用程序外部的文件或数据源进行数据交互。考虑将一个TXT文件从D盘拷贝到C盘。

它的拷贝过程应该是这样的:

源文件在磁盘中,需要建立一个类似管道的东西将文件和内存中的应用程序连接起来,并且将文件按字节发送。创建一个byte[]数组用于存放字节。

接下来,在C盘创建目标文件,同样通过一个管道一样的东西,将字节写入管道中,间接地写到文件中去。

而流,就是这种管道,或者说起到管道的作用。

下面简单学习一下代码:

 1 Stream source = new FileStream("D:\\test.txt", FileMode.Open, FileAccess.Read);//读取“管道”
 2             int size = 10;
 3             byte[] buffer = new byte[size];//用于储存临时字节
 4             int bytesRead;
 5             Stream target = new FileStream("C:\\test.txt", FileMode.Create, FileAccess.Write);//写入“管道”
 6             //因不知源文件字节长度,只能通过循环,每次读取一定数量的字节并写入流
 7             do
 8             {
 9                 bytesRead = source.Read(buffer, 0, size);
10                 target.Write(buffer, 0, bytesRead);//第三个参数是从Buffer中读取的个数,应该是bytesRead不是size
11             } while (bytesRead > 0);
12 
13             source.Dispose();
14             target.Dispose();
View Code

 或者使用流包装器类(不是流),StreamReader和StreamWriter,用法与上面差不多,注意已不是字节流,而是字符流

 1 StreamReader sr = new StreamReader("D:\\test.txt");
 2             StreamWriter sw = new StreamWriter("C:\\test2.txt");
 3             int maxSize = 10;
 4             char[] charBuffer = new char[maxSize];//注意,字符流
 5             int charRead;
 6             do
 7             {
 8                 charRead = sr.Read(charBuffer, 0, maxSize);
 9                 sw.Write(charBuffer, 0, charRead);
10             } while (charRead > 0);
11 
12             sr.Dispose();
13             sw.Dispose();
View Code

流还包括装饰器流,包装器类还包括BinaryReader和BinaryWriter。在这里就不详细展开了。

 

对称加密

加密和解密属于数据安全的范畴,在消息传输时,通过对消息进行特殊编码(即加密),建立一种安全的交流方式,使得只有发送者所期望的接收者能够理解(即解密)。一般场景中有三种角色:发送方,接收方,第三方。

消息加密应同时满足以下三个条件:

1)完整性,消息的可以确定消息在传输途中没有被篡改过,消息是完好无损的。

2)保密性,消息的发送方能够确定消息只有预期的接收方可以理解或解密(不保证第三方无法获得,但保证第三方无法解密)。

3)可认证性,消息的接收方可以确定消息是由谁发送的(接收方可以确认消息确定是由预期的发送方发送的)。

消息加密有散列运算(即Hash运算)、对称加密、非对称加密等,这里介绍一下对称加密(比较简单易于理解)。

对称加密流程如下:

1)发送方和接收方持有相同的密钥,并严格保密。

2)发送方使用密钥对消息进行加密,然后发送消息。

3)接收方收到消息后,使用同样的密钥对消息进行解密。

在上述流程中,第三方可能截取消息,但得到一堆乱码,没有密钥解密。

.net提供了一组类型(命名空间System.Security.Cryptography)来实现对称加密和解密。这些类型拥有共同的基类SymmetricAlgorithm,见下图。

 

 

可以看到上面类型分为CryptoServiceProvider和Managed两类,前者是由托管代码写的,后者调用的是Windows Crypto API,相当于一个包装类。

TripleDES算法加密

假设选择TripleDES算法进行加密,步骤如下:

1)创建一个TripleDESCryptoServiceProvider实例(假定变量名为provider)

2)在provider上指定密钥和IV。密钥通常为128位或192位字节,IV为64位。IV是为了解决同样的字符加密后字符仍一样的问题,例如ABABABCDE加密后,前面三个AB的数据理论上是一样且位置不变,引入IV之后即使是重复的也被打乱了。

3)利用provider创建加密器或解密器。ICryptoTransform定义了加密转换的运算,.net在底层调用这个接口。加密器:CreateEncryptor()方法,解密器:CreateDecryptor()方法。

4).net采用流的方式进行加密和解密,运算过程会涉及两个流,一个是明文流,包含加密前的数据,一个是密文流,包含加密后的数据。在两者之间,有一个中介者,负责将明文流转换为密文流,以及将密文流转换为明文流。这个中介者也是一个流类型,叫CryptoStream,它的构造函数有三个参数 

public CryptoStream(Stream stream, ICryptoTransform transform, CryptoStreamMode mode),其中每次传入的流都是密文流,根据需要传入加密器或解密器,以及写或读模式。

5)创建完以上几个对象,就可以进行转换了,加密过程为:明文流读字节,CryptoStream写密文流;解密过程为:CryptoStream读密文流,明文流写字节。

密钥应注意一点:3DES算法,如果1重、2重和3重密钥(每8位)有一个相同,算法会退化为2重或1重,运行报错。见下图:

加解密过程可以简单归纳如下:

1)创建TripleDESCryptoServiceProvider对象,指定密钥和IV,创建加密器或解密器

2)创建明文流和密文流

3)创建转换中介者CryptoStream对象,将密文流传入。

4)加密:明文流读字节,CryptoStream写密文流;解密:CryptoStream读密文流,明文流写字节。

实例

加密帮助类

 1 using System;
 2 using System.Security.Cryptography;
 3 using System.IO;
 4 using System.Text;
 5 
 6 namespace ch09
 7 {
 8     class EncryptorHelper
 9     {
10         //密钥应注意一点:3DES算法,如果1重、2重和3重密钥(每8位)有一个相同,算法会退化为2重或1重,运行报错
11         private static string _rgbKey = "thisishelloworld";
12         private static byte[] _rgbIV = new byte[] { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF };
13 
14         public static string Encryptor(string plainText)
15         {
16             TripleDESCryptoServiceProvider provider = new TripleDESCryptoServiceProvider();//创建provider,利用其产生加密器
17             provider.Key = Encoding.Default.GetBytes(_rgbKey);
18             provider.IV = _rgbIV;
19             ICryptoTransform encryptor = provider.CreateEncryptor();//加密器
20             byte[] plainBytes = Encoding.GetEncoding("gb2312").GetBytes(plainText);
21             MemoryStream plainStream = new MemoryStream(plainBytes);//创建明文流
22             MemoryStream cipherStream = new MemoryStream();//创建密文流
23             CryptoStream enCryptoStream = new CryptoStream(cipherStream, encryptor, CryptoStreamMode.Write);//创建加密中介
24             int maxSize = 10;
25             byte[] buffer = new byte[maxSize];
26             int bytesRead = 0;
27             do
28             {
29                 bytesRead = plainStream.Read(buffer, 0, maxSize);
30                 enCryptoStream.Write(buffer, 0, bytesRead);//谨记这里应该是写入读出的长度,而不是buffer本身的长度
31             } while (bytesRead > 0);
32             enCryptoStream.FlushFinalBlock();
33             return Convert.ToBase64String(cipherStream.ToArray());
34 
35         }
36 
37 
38         public static string Decryptor(string cipherText)
39         {
40             TripleDESCryptoServiceProvider provider = new TripleDESCryptoServiceProvider();
41             provider.Key = Encoding.Default.GetBytes(_rgbKey);
42             provider.IV = _rgbIV;
43             ICryptoTransform decryptor = provider.CreateDecryptor();
44             byte[] cipherByte = Convert.FromBase64String(cipherText);
45             MemoryStream plainStream = new MemoryStream();
46             MemoryStream cipherStream = new MemoryStream(cipherByte);
47             CryptoStream deCryptoStream = new CryptoStream(cipherStream, decryptor, CryptoStreamMode.Read);
48             int maxSize = 10;
49             byte[] buffer = new byte[maxSize];
50             int bytesRead = 0;
51             do
52             {
53                 bytesRead = deCryptoStream.Read(buffer, 0, maxSize);
54                 plainStream.Write(buffer, 0, bytesRead);
55             } while (bytesRead > 0);
56 
57             deCryptoStream.Dispose();
58             return Encoding.GetEncoding("gb2312").GetString(plainStream.ToArray());
59         }
60     }
61 }
View Code

使用帮助类

1  string plainText = "我要握住一个最美的梦,给未来的自己~~real me!";
2             Console.WriteLine("原文:" + plainText);
3             string encryptedString = EncryptorHelper.Encryptor(plainText);
4             Console.WriteLine("加密后:" + encryptedString);
5             Console.WriteLine("解密:" + EncryptorHelper.Decryptor(encryptedString));
6             Console.Read();
View Code

输出

posted @ 2014-03-20 22:47  kingsleylam  阅读(754)  评论(0编辑  收藏  举报