对称加密(4) NET对称加密实践
在使用.NET框架提供的加密算法实现类来执行加密任务时,需要准备加密密钥和初始化向量(Initialization Vector,IV)。基于对称加密的特点,在加密数据之后一定要保存好密钥和初始化向量,因为解密要用到它们。但是对于不同的数据加密,要使用不同的密钥和初始化向量,理论上每次新的加密过程都应该使用全新的密钥和初始化向量。
通常需要将加密密钥和初始化向量传递给另一个人,这时候需要使用非对称加密算法来加密密钥和初始化向量,然后在网络上传输。本节主要演示如何使用加密实践类,更多的应用内容会在本书的第四部分介绍。
那么如何创建加密密钥和初始化向量呢?有两种基本方法,一种是使用加密算法实现类的构造函数,另一种是使用GenerateIV()和GenerateKey()方法生成密钥和初始化向量。
使用构造函数创建密钥和初始化向量
先测试构造函数的方法,如代码清单6-5。
代码清单6-5 使用构造函数创建密钥和初始化向量
using System;
using System.Text;
using System.Security.Cryptography;
namespace Encription
{
classProgram
{
staticvoid Main(string[] args)
{
AesCryptoServiceProvider acsp = new AesCryptoServiceProvider();
WriteKeyAndIV(acsp);
AesManaged am = newAesManaged();
WriteKeyAndIV(am);
DESCryptoServiceProvider dsp = new DESCryptoServiceProvider();
WriteKeyAndIV(dsp);
TripleDESCryptoServiceProvider tdsp = newTripleDESCryptoServiceProvider();
WriteKeyAndIV(tdsp);
RijndaelManaged rm = new RijndaelManaged();
WriteKeyAndIV(rm);
Console.Read();
}
staticvoid WriteKeyAndIV(SymmetricAlgorithm sa)
{
Console.WriteLine(GetStringFromByte(sa.Key));
Console.WriteLine("*******");
Console.WriteLine(GetStringFromByte(sa.IV));
Console.WriteLine("--------------------------");
}
staticstring GetStringFromByte(byte[] bytes)
{
string s="";
for (int i = 0; i < bytes.Length; i++)
{
s += bytes[i].ToString()+" ";
}
return s;
}
}
}
以上代码中一共有三个方法,Main方法用来初始化.NET提供的5种对称加密实例;WriteKeyAndIV方法用来输出每个实例的密钥和初始化向量;GetStringFromByte方法用来输出byte数组的原始值。现在看输出结果,是不是如预料的,已经初始化了加密密钥和初始化向量呢?如图6-11所示。
图6-11 代码清单6-5输出结果
如图6-11所示,在控制台输出了每个加密实例的密钥和初始化向量。
使用GenerateIV()和GenerateKey()方法
当需要多个密钥或者多个初始化向量的时候,就要采用GenerateIV()和GenerateKey()方法。下面对代码清单6-5做简要的修改,如代码清单6-6所示。
代码清单6-6 使用GenerateIV()和GenerateKey()方法
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
namespace Encription
{
classProgram
{
staticvoid Main(string[] args)
{
AesCryptoServiceProvider acsp = new AesCryptoServiceProvider();
WriteKeyAndIV(acsp);
acsp.GenerateIV();
acsp.GenerateKey();
WriteKeyAndIV(acsp);
Console.Read();
}
staticvoid WriteKeyAndIV(SymmetricAlgorithm sa)
{
Console.WriteLine(GetStringFromByte(sa.Key));
Console.WriteLine("*******");
Console.WriteLine(GetStringFromByte(sa.IV));
Console.WriteLine("--------------------------");
}
staticstring GetStringFromByte(byte[] bytes)
{
string s="";
for (int i = 0; i < bytes.Length; i++)
{
s += bytes[i].ToString()+" ";
}
return s;
}
}
}
修改很简单,Main方法中只保留了AesCryptoServiceProvider实例,再初始化该实例后,又调用它的GenerateIV和GenerateKey方法,看是否产生了新的加密密钥和初始化向量。结果如图6-12所示。
图6-12 代码清单6-6运行结果
如图6-12所示,可以看到使用GenerateIV和GenerateKey方法后,生成了新的密钥和初始化向量。
准备工作完成了,下面要开始真正的加密之旅了。对称加密需要和CryptoStream类的实例配合,使用加密流来实现数据加密(.NET中的内存流、文件流、网络流都可以使用)。为了示例更明了,以AesCryptoServiceProvider类为例,使用内存流来演示如何使用对称加密类加密、解密数据。先看代码清单6-7。
代码清单6-7 加密解密数据示例
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
using System.IO;
namespace Sample
{
classProgram
{
staticAesCryptoServiceProvider acsp = newAesCryptoServiceProvider();
staticvoid Main(string[] args)
{
byte[] key = acsp.Key;
byte[] iv = acsp.IV;
string s = @"xuanhun加密测试";
byte[] sbyt = Encoding.Default.GetBytes(s);
byte []Enb = Encript(sbyt, key, iv);
byte []Deb = Decript(Enb, key, iv);
Console.WriteLine(Encoding.Default.GetString(Enb));
Console.WriteLine(Encoding.Default.GetString(Deb));
Console.Read();
}
publicstaticbyte[] Encript(byte[] s1, byte[] key, byte[] iv)
{
using (MemoryStream msEncrypt = new MemoryStream())
{ using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, acsp.CreateEncryptor(key, iv), CryptoStreamMode.Write)) {
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{ //Write all data to the stream.
var s = Convert.ToBase64String(s1);
swEncrypt.Write(s);
}
byte[] outb1 = msEncrypt.ToArray();
return outb1;
}
}
}
publicstaticbyte[] Decript(byte[] s2, byte[] key, byte[] iv)
{
using (MemoryStream msDecrypt = new MemoryStream(s2)) { using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, acsp.CreateDecryptor(key, iv), CryptoStreamMode.Read)) { using (StreamReader srDecrypt = new StreamReader(csDecrypt)) { var s= Convert.FromBase64String(srDecrypt.ReadToEnd()); return s; } } }
}
publicstaticbyte[] GetByteFromstring(string s)
{
returnEncoding.Default.GetBytes(s);
}
}
}
以上代码首先创建了AesCryptoServiceProvider实例,然后在Main方法中使用了局部变量key和iv来保存该实例的加密密钥和初始化向量,字符串s是要加密的原始字符串。局部变量sbyte保存了将字符串s转化为byte数组后的结果。加密解密过程都是围绕该byte数组进行的。
Main方法中调用两个静态方法Encript和Decript方法,分别用来实现加密和解密。在Encript方法中,首先初始化内存流MemoryStream的实例mstream,然后以mstream为参数创建CryptoStream实例。CryptoStream构造函数需要3个参数:第一个是流实例,第二个是加密或者解密器,在加密函数中使用CreateEncryptor方法做参数,在解密方法中使用CreateDecryptor做参数;CreateEncryptor和CreateDecryptor方法需要传入准备好的加密密钥和初始化向量。第三个参数是CryptoStreamMode枚举,该枚举有两个值Write和Read,用来指示流的操作。比如在网络流中,加密并输出数据时要设置Write属性,接收并解密的一方要设置Read属性。本例中把加密和解密的数据都写入内存流,所以都设置了Write属性。在初始化CryptoStream实例之后,调用该实例的Write方法,将加密后的数据写入内存流。然后再调用内存流的ToArray方法读出加密数据,返回到Main方法中,通过Encoding.Default.GetString方法,获得加密后的字符串。解密过程与此类似,不再赘述。
现在看改程序的运行结果,如图6-13所示。
图6-13 代码清单6-7运行结果
如图6-7所示,已经成功实现了简单的对称加密解密过程。.NET中的其他对称加密实现类的使用方法与此类似。
----------------------注:本文部分内容改编自《.NET安全揭秘》
本文转自悬魂博客园博客,原文链接:http://www.cnblogs.com/xuanhun/archive/2012/06/23/2559537.html,如需转载请自行联系原作者