2013年11月18日 星期一

字串的加解密CrytoStream使用DES加密法

介紹本章之前
先來簡單介紹一下 什麼是DES ??
原文要如何透過演算法才能轉換讓人短時間
無法解密的訊息呢?

字串的加解密演算法有很多有種
可以在維基百科中找到 這裡不多作介紹了

本章範例使用DES(Data Encryption Standard)
這種古老的演算法來自1975年左右
在強度或複雜度就不便多說了
就是透過 常數與規則演算去增加複雜度
拉長破解時間

DES對稱演算法
簡單來說 原文 與 KEY 經由DES演算後
將會的到一串 加密字串

解密則是相反,加密字串 與KEY 經由DES
反推出 原文 這兩種方式 是對對稱的
所以才叫對稱演算法
加密和解密 都是同一把KEY

首先 我們先來看 CryptoStream類別 中的建構函式
MSDN中的介紹如下:
使用目標資料流、要使用的轉換和資料流模式
來初始化 CryptoStream 類別的新執行個體。

OK! 目標資料流,轉換資料,和資料流模式 3個
再來 來看他的語法!!

public CryptoStream( Stream stream,
ICryptoTransform transform,
CryptoStreamMode mode
)

再來看 MSDN中 參數的解釋如下

參數

stream
型別:System.IO.Stream
要在其上執行密碼編譯轉換的資料流。
transform
型別:System.Security.Cryptography.ICryptoTransform
要在資料流上執行的密碼編譯轉換。
mode
型別:System.Security.Cryptography.CryptoStreamMode
其中一個 CryptoStreamMode 值。
 
 
第一個參數Stream意思是指
要使用哪一種資料流來編譯轉換


第二個參數transform
型別傳回數值為ICryptoTransform介面
待會我們將使用DESCryptoServiceProvider()類別中的
CreateEncryptor(Byte[], Byte[]))方法
他的語法如下
public override ICryptoTransform CreateEncryptor(
byte[] rgbKey,
byte[] rgbIV
剛好回傳 ICryptoTransform 正是CryptoStream()方法
第二參數中所需要回傳的 ICryptoTransform 介面
但是奇怪的是,為何要使用ICryptoTransform 介面
因為CryptoStream類別中並沒有實作或複寫ICryptoTransform介面
此問題先保留 以後發現再回來改

第三個參數mode
將決定此建構函式是要加密 或解密?
如果加密 就CryptoStreamMode.Write
解密則CryptoStreamMode.Read

OK!現在讓我們來看個範例!




來講解一下上圖範例!
首先btn_Encrypt_Click按鍵觸發後
先進入一個If來判斷key的長度是否等於4
如果不是等於4則else
再來進入try與catch
首先try區塊中 最後傳回數據為txt_EncryptStr.Text
而我們實體化 Encrypt類別並且調用類別中的ToEncrypt方法
並且傳入兩個參數txt_password.Text=密碼
txt_str.Text=要加密的字串

再來我們來看一下 Encrypt類別中
是如何處理 密碼與加密字串的

來看一下Encrypt.cs檔案中的類別吧!!


















看上圖我們將使用到Cryptography的命名空間
而Encrypt類中包含兩個Internal的字串方法
關於Internal上一章有詳細介紹!
我們先來看 第一個方法
剛剛說到
ToEncrypt方法傳入兩個字串參數
來看下圖





































看完上圖的註解應該不難理解!
首先 傳入ToEncrypt方法中的兩個字串
一個是Key金鑰,一個是Str原文
而Key中的數字1234每個數字以unicode取值
而unicode是UTF16所以會有16bit 等於2byte
當方法GetBytes的時候會取2個byte陣列
而假如密碼第一個數字是1
ascii碼是49 但是49不足2bytes
所以在P_Byte_Key中 會塞入
一個49另外一個則是0的陣列

而Str也是一樣 轉乘Byte陣列

再來建立記憶體資料流P_Stream_MS

再來建立加密流 CryptoStream
而語法在本文章開端有大概地介紹過了
這裡要注意的是,所需要的參數
記憶體資料流 P_Stream_MS
加密模式
DESCryptoServiceProvider()類別中的
CreateEncryptor(Key,Key)加密方法 並且帶入Key值!
最後CryptoStreamMode.Write為寫入模式

再來寫入P_CryptStream_Stream.Write(P_byte_data, 0, P_byte_data.Length)
參數中的意思應該不用多解釋0是起始length是一個字元種字數
意思將原文全部寫入

再來
 P_CryptStream_Stream.FlushFinalBlock()
msdn解釋如下
以緩衝區的目前狀態更新基礎資料來源或存放庫,並接著清除緩衝區。

因為還沒呼叫Close所以我們先讓 P_CryptStream_Stream裡面的buffer
刷新好讓P_byte_date資料流進P_Stream_MS
 
呼叫 Close 方法將會呼叫 FlushFinalBlock如果不呼叫Close,請呼叫FlushFinalBlock以完成刷新緩衝區。僅在所有資料流活動都完成時呼叫 FlushFinalBlock


最吼取P_Stream_MS中的陣列到P_bt_temp 中
byte[] P_bt_temp = P_Stream_MS.ToArray();

最後將 P_bt_temp 轉成 Base64 回傳
return Convert.ToBase64String(P_bt_temp);

什麼是 Base64 ?

依遞增順序從零起始的 Base-64 位數,包含大寫字元 "A" 到 "Z"、小寫字母 "a" 到 "z"、數字 "0" 到 "9",以及 "+" 和 "/" 符號。
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
不表示數值的 "=" 字元是做為尾端填補。
更多解釋請參考 MSDN維基百科



上面我們已經知道 如何將 原文字串
轉成短時間難以讀取的加密字串了

再來我們將示範如何將字串解密
還原,當初加密前的訊息
請看下圖 ToDecrypt方法一樣送入兩個字串
加密訊息與KEY值
 
注意解密區塊中與加密有稍微的不同
一開始我們一樣 將接收到加密字串與key
的兩個參數,接下來我們要把加密時
轉成Base64的字串用FromBase64String
轉回位元組陣列,這方法回傳byte陣列
 
再來實體化一個MemoryStream並將P_byte_data
寫入記憶體中的buffer
 
 
我們一樣會使用到CryptoStream的加密流
不同的是參數,使用剛剛建立已寫入資料的記憶流
解密一樣使用DESCryptoServiceProvider類別
不同的是使用CreateDecryptor(key, key)對稱解密的方法
而最後一個參數CryptoStreamMode.Read為讀取模式

接下來準備資料流要存取的成員吧
byte[] P_bt_temp = new byte[200] 存取解密字節序列結果

在實體化一個記憶體資料流來寫入P_bt_temp 序列結果!
MemoryStream P_MemoryStream_temp =new MemoryStream();

首先進入一個While判斷式!
CryptoStream.Readhttp有讀取到序列資料則會傳會int
而我們之前也宣告了一個int i = 0;//建立記數器
剛好可以用來進行 While判斷是否大於0代表有獨到資料
而資料回存到剛剛新建的P_bt_temp陣列中

而while 為true時進入程式區塊
並且將解密後的資料放入記憶體流
P_MemoryStream_temp.Write(P_bt_temp, 0, i);

最後 將記憶體資料流以陣列傳給GetString
將指定位元組陣列中的所有位元組解碼成字串
return Encoding.Unicode.GetString(P_MemoryStream_temp.ToArray());
最後將字串輸出

OK!完





沒有留言:

張貼留言