在
.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();
}
}