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!完





2013年11月15日 星期五

存取範圍層級internal與DLL介紹

本文參考文章連結
在理解什麼是Internal的時候在MSDN找到解釋是

第一
internal 修飾詞讓類別、介面或成員只能在目前封裝內看得見。
目前封裝外部的程式碼不能存取 internal 成員。

上文意思是指
限於在DLL或EXE中使用被修飾的類別 介面成員
意思是如果開新Windiws Form專案將DLL加入參考
DLL中被internal修飾的成員將無法調用

第二
類別和介面可以使用 internal 修飾詞來標記。
在全域範圍中,internal 修飾詞與 public 修飾詞相同。
類別或介面的任何成員都可以使用 internal 修飾詞來標記。

意思是指 類別或介面 在使用Internal修飾 如同Public
待會我們將會示範這個疑點

第三
您不能將 internal 修飾詞與其他任何可視性的
修飾詞 (publicprivateprotected) 結合使用。
可視性修飾詞與它們所定義的範圍有關。
例如,internal 類別的 public 方法不能公開存取
但是任何可以存取此類別的程式碼都可以存取此方法。

意思是指 public 與 Internal 不能共存拉 不對外公開只對內
就用internal就好,公開就public了唷~

來看範例比較快理解
首先我們先建立一個WindowsForm
而在此專案在新建一個Class檔
如下圖








建立的Class叫C1.cs
C1.cs檔案中的內容如下

 
 
 
首先來看上圖 第一個類別 公開的Class1
裡面的成員如上,將被Class2繼承
注意到不是只有protected可以被繼承喔
注意到internal同等public差別在於
internal只對內公開不對外
來看下圖Class2如何繼承Class1吧
 


 
上圖清楚看到
繼承了Class1成員完全沒問題啊
注意Public string GetProtectedInternal()
中的方法調用的是一個Internal
可以證明Internal是一個對內的Public
 
下圖將介紹Class3 Class4
 


 
上圖可以看到
Internal Class3
被Class4繼承
這兩個類別我們等等會在
新專案中把此類別加入參考
並且證明 Class3 與 Class4 是不會被調用的
下圖Class5則是證明
實體化物件中的internal成員如同
public也可以被調用 如下圖






















上圖 注意實體化的cla1與cla3
可以調用 Internal的成員喔!!



再來我們將 新建一個專案
再將上面OP專案中的C1.CS加入參考
將證明 internal Class3與Class4不會被調用

首先 開新專案


 
 
 
加入參考

 
 
選擇剛剛的專案位置op.exe


 
 
再來我們在專案中加入OP的命名空間

並且實體化類別
看可不可以調用類別中的成員
以及證明internal是不能被其他專案調用的
請看下圖即可明瞭




上圖Class3 與 Class4 因為是internal所以不會顯示
而C1.str則是公開成員 Class1 中的internal成員將不會顯示
C2也是

本章節介紹到此