在使用NET框架提供的加密算法实现类来执行加密任务时我们需要准备加密密钥和初始化向量(IV)基于对称加密的特点我们在加密数据之后一定要保存好密钥和初始化向量因为解密要用到它们但是对于不同的数据加密我们要使用不同的密钥和初始化向量理论上每次新的加密过程都应该使用全新的密钥和初始化向量
通常我们需要将加密密钥和初始化向量传递给另一个人这时候需要使用非对称加密算法来加密密钥和初始化向量然后在网络上传输
那么如何创建加密密钥和初始化向量呢?有两种基本方法一种是使用加密算法实现类的构造函数一种是使用GenerateIV()和GenerateKey()方法生成密钥和初始化向量我们先测试构造函数的方法如代码清单
代码清单 使用构造函数创建密钥和初始化向量
using System;
using SystemText;
using SystemSecurityCryptography;
namespace Encription
{
class Program
{
static void Main(string[] args)
{
AesCryptoServiceProvider acsp = new AesCryptoServiceProvider();
WriteKeyAndIV(acsp);
AesManaged am = new AesManaged();
WriteKeyAndIV(am);
DESCryptoServiceProvider dsp = new DESCryptoServiceProvider();
WriteKeyAndIV(dsp);
TripleDESCryptoServiceProvider tdsp = new TripleDESCryptoServiceProvider();
WriteKeyAndIV(tdsp);
RijndaelManaged rm = new RijndaelManaged();
WriteKeyAndIV(rm);
ConsoleRead();
}
static void WriteKeyAndIV(SymmetricAlgorithm sa)
{
ConsoleWriteLine(GetStringFromByte(saKey));
ConsoleWriteLine(*******);
ConsoleWriteLine(GetStringFromByte(saIV));
ConsoleWriteLine();
}
static string GetStringFromByte(byte[] bytes)
{
string s=;
for (int i = ; i < bytesLength; i++)
{
s += bytes[i]ToString()+ ;
}
return s;
}
}
}
如代码清单所示一共有三个方法Main方法用来初始化NET提供的种对称加密实例WriteKeyAndIV方法用来输出每个实例的密钥和初始化向量GetStringFromByte方法用来输出byte数组的原始值那么现在我们看下输出结果是不是如我们预料到的已经初始化了加密密钥和初始化向量呢?如图所示
图 代码清单输出结果
如图在控制台输出了每个加密实例的密钥和初始化向量当我们需要多个密钥或者多个初始化向量的时候就需要采用GenerateIV()和GenerateKey()方法下面我们对代码清单做简要的修改如代码清单所示
代码清单 使用GenerateIV()和GenerateKey()方法
using System;
using SystemCollectionsGeneric;
using SystemLinq;
using SystemText;
using SystemSecurityCryptography;
namespace Encription
{
class Program
{
static void Main(string[] args)
{
AesCryptoServiceProvider acsp = new AesCryptoServiceProvider();
WriteKeyAndIV(acsp);
acspGenerateIV();
acspGenerateKey();
WriteKeyAndIV(acsp);
ConsoleRead();
}
static void WriteKeyAndIV(SymmetricAlgorithm sa)
{
ConsoleWriteLine(GetStringFromByte(saKey));
ConsoleWriteLine(*******);
ConsoleWriteLine(GetStringFromByte(saIV));
ConsoleWriteLine();
}
static string GetStringFromByte(byte[] bytes)
{
string s=;
for (int i = ; i < bytesLength; i++)
{
s += bytes[i]ToString()+ ;
}
return s;
}
}
}
如代码清单我们所做的修改很简单Main方法中只保留了AesCryptoServiceProvider实例再初始化该实例后又调用它的GenerateIV和GenerateKey方法看是否产生了新的加密密钥和初始化向量结果如图所示
图 代码清单运行结果
如图我们可以看到使用GenerateIV和GenerateKey方法后生成了新的密钥和初始化向量
我们的准备工作完成了下面要开始真正的加密之旅了对称加密需要和CryptoStream类的实例配合加密流来实现数据加密NET中的内存流文件流网络流都可以使用为了示例更明了我们以AesCryptoServiceProvider类为例使用内存流来演示如何使用对称加密类加密解密数据先看代码清单
代码清单 加密解密数据示例
using System;
using SystemCollectionsGeneric;
using SystemLinq;
using SystemText;
using SystemSecurityCryptography;
using SystemIO;
namespace Sample
{
class Program
{
static AesCryptoServiceProvider acsp = new AesCryptoServiceProvider();
static void Main(string[] args)
{
byte[] key = acspKey;
byte[] iv = acspIV;
string s = @xuanhun加密测试;
byte[] sbyt = EncodingDefaultGetBytes(s);
byte []Enb = Encript(sbyt key iv);
byte []Deb = Decript(Enb key iv);
ConsoleWriteLine(EncodingDefaultGetString(Enb));
ConsoleWriteLine(EncodingDefaultGetString(Deb));
ConsoleRead();
}
public static byte[] Encript(byte[] s byte[] key byte[] iv)
{
MemoryStream mstream = new MemoryStream();
CryptoStream cstream = new CryptoStream(mstream acspCreateEncryptor(key iv) CryptoStreamModeWrite);
cstreamWrite(s sLength);
cstreamFlushFinalBlock();
byte[] outb = mstreamToArray();
cstreamClose();
mstreamClose();
return outb;
}
public static byte[] Decript(byte[] s byte[] key byte[] iv)
{
MemoryStream mtream = new MemoryStream();
CryptoStream deStreame = new CryptoStream(mtream acspCreateDecryptor(key iv) CryptoStreamModeWrite);
deStreameWrite(s sLength);
deStreameFlushFinalBlock();
byte[] outs = mtreamToArray();
mtreamClose();
deStreameClose();
return outs;
}
public static byte[] GetByteFromstring(string s)
{
return EncodingDefaultGetBytes(s);
}
}
}
如代码清单我们首先创建了AesCryptoServiceProvider实例然后再Main方法中使用了局部变量key和iv来保存该实例的加密密钥和初始化向量字符串s是要加密的原始字符串局部变量sbyte保存了将字符串s转化为byte数组后的结果我们的加密解密过程都是围绕该byte数组进行的
接下来我们介绍Main方法中调用的两个静态方法Encript和Decript方法分别用来实现加密和解密在Encript方法中我们首先初始化内存流MemoryStream的实例mstream然后以mstream为参数创建CryptoStream实例CryptoStream构造函数需要三个参数第一个是流实例第二个是加密或者解密器在加密函数中使用CreateEncryptor方法做参数在解密方法中使用CreateDecryptor做参数CreateEncryptor和CreateDecryptor方法需要传入我们准备好的加密密钥和初始化向量第三个参数是CryptoStreamMode枚举该枚举有两个值Write和Read用来指示流的操作比如在网络流中加密并输出数据时要设置Write属性接收并解密的一方要设置Read属性本例中把加密和解密的数据都写入内存流所以都设置了Write属性在初始化CryptoStream实例之后调用该实例的Write方法将加密后的数据写入内存流然后再调用内存流的ToArray方法读出加密数据返回到Main方法中通过EncodingDefaultGetString方法获得加密后的字符串解密过程与此类似不再赘述
现在我们看看改程序的运行结果如图所示
图 代码清单运行结果
从图上看我们已经成功的实现了简单的对称加密解密过程NET中的其他对称加密实现类的使用方法与此类似