C#对称加密
在.NET库的System.Security.Cryptography命名空间中,包含多种加密数据的类,涉及多种加密算法。加密方法主要分为两大类:对称加密和不对称加密。
对称加密
私钥算法以块为单位加密数据,一次加密一个数据块。因此对称加密支持数据流,是加密流数据的理想方式。
.NET类库使用的私钥算法有RC2、DES、TripleDES和Rijndael。这些算法通过加密将n字节的输入块转换为加密字节的输出块。如果要加密或解密字节序列,必须逐块进行。由于n很小(对于RC2、DES和TripleDES算法,n的值为8字节、16字节或24字节,默认值为16字节;对于Rijndael算法,n的值为32字节),因此每次加密的块的大小必须大于n。实际上,一次读入的数据块是否符合私钥算法要求的块的大小,如果不符合应该如何填充使其符合要求等情况,.NET类库提供的算法类本身会自动处理,编写程序时不需要考虑这些问题。
为了保证数据的安全,.NET基类库中提供的私钥算法类使用称作密码块链(CBC,Cipher Block Chaining)的链模式,算法使用一个密钥和一个初始化向量(IV,Initialization Vector)对数据执行加密转换。密钥和初始化向量IV一起决定如何加密数据,以及如何将数据解密为原始数据。通信双方都必须知道这个密钥和初始化向量才能够加密和解密数据。
初始化向量IV的作用:防止随机产生的明文和密文相同
对称加密算法的优点是保密强度高,加、解密速度快,适合加密大量数据。攻击者如果对加密后的数据进行破译,惟一的办法就是对每个可能的密钥执行穷举搜索。而采用这种加密技术,即使使用最快的计算机执行这种搜索,耗费的时间也相当长。如果使用较大的密钥,破译将会更加困难。在实际应用中,加密数据采用的密钥一般都有时效性,比如几天更换一次密钥和IV,如果攻击者采用穷举法试图破译加密后的数据,等到好不容易试出了密钥,加密者早已采用新的密钥对网络中传输的数据进行加密了,因此利用穷举搜索的方法破译加密后的数据实际上是没有意义的。
.NET Framework中,公共语言运行时CLR(Common Language Runtime)使用面向流的设计实现对称加密,该设计的核心是CryptoStream,实现CryptoStream的任何被加密的对象都可以和实现Stream的任何对象链接起来。实现对称加密算法的类有四种:
• DESCryptoServiceProvider
• RC2CryptoServiceProvider
• RijndaelManaged
• TripleDESCryptoServiceProvider
下面是TripleDES的一个基本操作
private void buttonOK_Click(object sender, EventArgs e)
{
string str = textBoxInput.Text;
//加密
try
{
TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
//随机生成密钥Key和初始化向量IV(也可以自己设定)
tdes.GenerateKey();
tdes.GenerateIV();
textBoxKey.Text = Encoding.UTF8.GetString(tdes.Key);
//得到加密后的字节流
byte[] encryptedBytes = EncryptText(str, tdes.Key, tdes.IV);
//显示加密后的字符串
textBoxEncrypt.Text = Encoding.UTF8.GetString(encryptedBytes);
//解密
string decryptString = DecryptText(encryptedBytes, tdes.Key, tdes.IV);
//显示解密后的字符串
textBoxDecrypt.Text = decryptString;
}
catch (Exception err)
{
MessageBox.Show(err.Message, "出错");
}
}
private byte[] EncryptText(string str, byte[] Key, byte[] IV)
{
//创建一个内存流
MemoryStream memoryStream = new MemoryStream();
//使用传递的私钥和IV创建加密流
CryptoStream cryptoStream = new CryptoStream(memoryStream,
new TripleDESCryptoServiceProvider().CreateEncryptor(Key, IV),
CryptoStreamMode.Write);
//将传递的字符串转换为字节数组
byte[] toEncrypt = Encoding.UTF8.GetBytes(str);
try
{
//将字节数组写入加密流,并清除缓冲区
cryptoStream.Write(toEncrypt, 0, toEncrypt.Length);
cryptoStream.FlushFinalBlock();
//得到加密后的字节数组
byte[] encryptedBytes = memoryStream.ToArray();
return encryptedBytes;
}
catch (CryptographicException err)
{
throw new Exception("加密出错:" + err.Message);
}
finally
{
cryptoStream.Close();
memoryStream.Close();
}
}
private string DecryptText(byte[] dataBytes, byte[] Key, byte[] IV)
{
//根据加密后的字节数组创建一个内存流
MemoryStream memoryStream = new MemoryStream(dataBytes);
//使用传递的私钥、IV和内存流创建解密流
CryptoStream cryptoStream = new CryptoStream(memoryStream,
new TripleDESCryptoServiceProvider().CreateDecryptor(Key, IV),
CryptoStreamMode.Read);
//创建一个字节数组保存解密后的数据
byte[] decryptBytes = new byte[dataBytes.Length];
try
{
//从解密流中将解密后的数据读到字节数组中
cryptoStream.Read(decryptBytes, 0, decryptBytes.Length);
//得到解密后的字符串
string decryptedString = Encoding.UTF8.GetString(decryptBytes);
return decryptedString;
}
catch (CryptographicException err)
{
throw new Exception("解密出错:" + err.Message);
}
finally
{
cryptoStream.Close();
memoryStream.Close();
}
}