一、 對稱加密
對稱加密,是一種比較傳統的加密方式,其加密運算、解密運算使用的是同樣的密鑰,信息的發送者和信息的接收者在進行信息的傳輸與處理時,必須共同持有該密碼(稱爲對稱密碼)。因此,通信雙方都必須獲得這把鑰匙,並保持鑰匙的祕密。
單鑰密碼系統的安全性依賴於以下兩個因素:
第一、加密算法必須是足夠強的,僅僅基於密文本身去解密信息在實踐上是不可能的。
第二、加密方法的安全性依賴於密鑰的祕密性,而不是算法的祕密性,因此,我們沒有必要確保算法的祕密性(事實上,現實中使用的很多單鑰密碼系統的算法都是公開的),但是我們一定要保證密鑰的祕密性。
DES(Data Encryption Standard)和TripleDES是對稱加密的兩種實現。
DES和TripleDES基本算法一致,只是TripleDES算法提供的key位數更多,加密可靠性更高。
DES使用的密鑰key爲8字節,初始向量IV也是8字節。
TripleDES使用24字節的key,初始向量IV也是8字節。
兩種算法都是以8字節爲一個塊進行加密,一個數據塊一個數據塊的加密,一個8字節的明文加密後的密文也是8字節。如果明文長度不爲8字節的整數倍,添加值爲0的字節湊滿8字節整數倍。所以加密後的密文長度一定爲8字節的整數倍。
本文測試源代碼:http://files.cnblogs.com/files/chnking/TripleDESTest.rar
二、 加密解密過程
1、 生成key和IV
System.Security.Cryptography. TripleDESCryptoServiceProvider類是dotnet中實現TripleDES算法的主要的類。
TripleDESCryptoServiceProvider類只有一個構造方法TripleDESCryptoServiceProvider(),這個方法把一些屬性初始化:
KeySize(加密密鑰長度,以位爲單位)= 192(24字節)
BlockSize(加密處理的數據塊大小,以位爲單位)= 64(8字節)
FeedbackSize(加密數據塊後返回的數據大小,以位爲單位)= 64(8字節)
TripleDESCryptoServiceProvider構造方法同時會初始化一組隨機的key和IV。
默認的TripleDESCryptoServiceProvider的key爲24字節,IV爲8字節,加密數據塊爲8字節。
生成key和IV的代碼很簡單:
TripleDESCryptoServiceProvider tDESalg = new TripleDESCryptoServiceProvider();
byte[] keyArray = tDESalg.Key;
byte[] IVArray = tDESalg.IV;
生成的key和IV在加密過程和解密過程都要使用。
2、 字符串明文轉成某一代碼頁對應的編碼字節流
待加密的數據可能有兩種形式,一種是二進制的數據,本身就是一組字節流,這樣的數據可以跳過這一步,直接進入加密步驟。還有一種情況是字符串數據,字符串中同樣的字符使用不同的代碼頁會生成不同的字節碼,所以從字符串到字節流的轉換是需要指定使用何種編碼的。在解密之後,要從字節流轉換到字符串就要使用相同的代碼頁解碼,否則就會出現亂碼。
// 待加密的字符串
string plainTextString = "Here is some data to encrypt. 這裏是一些要加密的數據。";
// 使用utf-8編碼(也可以使用其它的編碼)
Encoding sEncoding = Encoding.GetEncoding("utf-8");
// 把字符串明文轉換成utf-8編碼的字節流
byte[] plainTextArray = sEncoding.GetBytes(plainTextString);
3、 加密操作
加密的原料是明文字節流,TripleDES算法對字節流進行加密,返回的是加密後的字節流。同時要給定加密使用的key和IV。
// 把字符串明文轉換成utf-8編碼的字節流
byte[] plainTextArray = sEncoding.GetBytes(plainTextString);
public static byte[] EncryptString(byte[] plainTextArray, byte[] Key, byte[] IV)
{
// 建立一個MemoryStream,這裏面存放加密後的數據流
MemoryStream mStream = new MemoryStream();
// 使用MemoryStream 和key、IV新建一個CryptoStream 對象
CryptoStream cStream = new CryptoStream(mStream,
new TripleDESCryptoServiceProvider().CreateEncryptor(Key, IV),
CryptoStreamMode.Write);
// 將加密後的字節流寫入到MemoryStream
cStream.Write(plainTextArray, 0, plainTextArray.Length);
//把緩衝區中的最後狀態更新到MemoryStream,並清除cStream的緩存區
cStream.FlushFinalBlock();
// 把解密後的數據流轉成字節流
byte[] ret = mStream.ToArray();
// 關閉兩個streams.
cStream.Close();
mStream.Close();
return ret;
}
4、 解密操作
解密操作解密上面步驟生成的密文byte[],需要使用到加密步驟使用的同一組Key和IV。
// 調用解密方法,返回已解密數據的byte[]
byte[] finalPlainTextArray = DecryptTextFromMemory(Data, keyArray, IVArray);
public static byte[] DecryptTextFromMemory(byte[] EncryptedDataArray, byte[] Key, byte[] IV)
{
// 建立一個MemoryStream,這裏面存放加密後的數據流
MemoryStream msDecrypt = new MemoryStream(EncryptedDataArray);
// 使用MemoryStream 和key、IV新建一個CryptoStream 對象
CryptoStream csDecrypt = new CryptoStream(msDecrypt,
new TripleDESCryptoServiceProvider().CreateDecryptor(Key, IV),
CryptoStreamMode.Read);
// 根據密文byte[]的長度(可能比加密前的明文長),新建一個存放解密後明文的byte[]
byte[] DecryptDataArray = new byte[EncryptedDataArray.Length];
// 把解密後的數據讀入到DecryptDataArray
csDecrypt.Read(DecryptDataArray, 0, DecryptDataArray.Length);
msDecrypt.Close();
csDecrypt.Close();
return DecryptDataArray;
}
有一點需要注意,DES加密是以數據塊爲單位加密的,8個字節一個數據塊,如果待加密明byte[]的長度不是8字節的整數倍,算法先用值爲“0”的byte補足8個字節,然後進行加密。所以加密後的密文長度一定是8的整數倍。這樣的密文解密後如果補了0值的byte,則解密後這些0值的byte依然存在。比如上例中要加密的明文是:
“Here is some data to encrypt. 這裏是一些要加密的數據。”
轉成明文byte[]後是66個字節,DES算法就會補上6個0值的byte,補到72個字節。這樣加密後再解密回來的密文byte[]解碼後的字符串就是這樣的:
“Here is some data to encrypt. 這裏是一些要加密的數據。\0\0\0\0\0\0”
5、 從編碼字節流轉成字符串明文
// 使用前面定義的Encoding,utf-8的編碼把byte[]轉成字符串
plainTextString = sEncoding.GetString(finalPlainTextArray);