天天看點

System.Security.Cryptography實戰

Author:zfive5(zidong)

Email:[email protected]

引子

一直以來認為網絡是me的強項,自然書也買了和看了不少,日子久了,好書壞書靠經驗去分辨, 但往往經驗也同樣會影響我對事物的正确判斷。例如,很早看到過王達寫的網絡方面的書,第一印象覺得有湊數賺錢的嫌疑,連翻的機會都不給它,但上星期去海澱買來一本(感謝網上的評論),察覺到這系列簡直就是網絡基礎的百科全書!雖然不是太深入,但講什麼是A之類的命題足以,我也對PPPoE協定格式了解比以前多些!

寫标準加密雜湊演算法,像DES /MD5之類,都統統用c/c++,覺得隻有在自己代碼裡包含最深層次的code才是正道,任何用其它庫或控件是對這些算法無知的表露! 

這些天看.net比較多! 打開System.Security.Cryptography命名空間後才有了寫它一點的沖動(感謝老天在我閱讀msdn時,讓滑鼠偏了一下)!

正文

System.Security.Cryptography加密算法主要分為:

l        雜湊演算法 (MD5/SHA1/ RIPEMD160/ SHA256 / SHA384等 )

System.Security.Cryptography實戰

l        對稱加密算法 (DES/TRI-DES等)

System.Security.Cryptography實戰

l        非對稱加密算法(RSA/DSA)

System.Security.Cryptography實戰

1.散列

散列,簡單點就是一種變換,使變換後的資料在一定小機率情況下代表變換前資料的“标簽”,這個标簽就是散列,變換就是雜湊演算法,往往這些算法是公開的、不可逆的!因為算法公開的,為了防止大家誰都可以對源資料進行散列,是以出現增加一個KEY的變形雜湊演算法(HMAC算法)。

散列主要用在對資料有效性的驗證方面。例如,BT就是用SHA1驗證收到資料塊是否有效的,Email伺服器的登入就有一中名為HMACMD5的驗證模式!

C#代碼

//對byte資料串進行散列

HashAlgorithm  oTransform = (HashAlgorithm)MD5.Create();

byte[] AInput={0x31,0x31,0x31,0x31};

byte[] AOutput = oTransform.ComputeHash(AInput);

//對檔案流進行散列

FileStream oFile = new FileStream("c://10.vbs", FileMode.Open);

HashAlgorithm oTransform = (HashAlgorithm)MD5.Create();

byte[] AOutput = oTransform.ComputeHash(oFile);

oFile.Close();

//對byte資料串進行HMACMD5

//KeyedHashAlgorithm oHash = (KeyedHashAlgorithm)HMACMD5.Create();

//HMACMD5.Create()其實為傳回一個HMACSHA1,HMACMD5沒有定義Create

KeyedHashAlgorithm oHash = (KeyedHashAlgorithm)new HMACMD5();

byte[] oKey={0x31};

oHash.Key = oKey;

byte[] AInput ={ 0x31, 0x31, 0x31, 0x31 };

byte[] AOutput = oHash.ComputeHash(AInput);

還有要說的MD5與MD5CryptoServiceProvider 為什麼有兩個,它們之間的關系是怎樣的?如果第一次用這個類庫的話,真有點糊塗(此前我在糊塗ing)—“既生瑜,何生亮!”

源碼之下無密碼,開始反編譯:

MD5.Create()   —>

CryptoConfig.CreateFromName(“System.Security.Cryptography.MD5”) —>

CryptoConfig.defaultNameHT[“System.Security.Cryptography.MD5”] —>

Type type1 = (Type) typeof(MD5CryptoServiceProvider); —>

反射一個MD5CryptoServiceProvider執行個體

是以最終使用者使用的還是MD5CryptoServiceProvider,MD5主要起到作用就是簡名的作用!

還有一點疑慮關于算列就剩下了“.net是否包含md2、md4算法?”,其實也是以下代碼給我的靈感的:

//MD5

Utils._CreateHash(Utils.Static ProvHandle, 0x8003, ref handle1);

 this._safeHashHandle = handle1;

//SHA1     

 Utils._CreateHash(Utils.StaticProvHandle, 0x8004, ref handle1);

 this._safeHashHandle = handle1;

是否0x8001<->MD2 , 0x8002<->MD4 ,這隻是我的猜想,由于保護機制,無法在自己的類中使用SafeHashHandle 類(真不知道ms為什麼不暴露出這個類呢?),但使用者完全可以模仿SHA1Managed類寫一個MD4類!

2.對稱加密

所謂對稱就是指加密解密中使用的key值是一樣的,這種加密算法也是我們大家日常用的最多的加密算法了,這類加密算法一般公開, 遭受考驗的也主要是key的長度,當然了你也完全寫一個不公開的算法,隻要能在數學上證明有一個可逆過程與其一一對應就可以了!

想象A加完密的密文發送給B,如果B想知道原文,還要根據解密算法解開才可以 ! 是以key值的保密性在這類應用中的重中之重!

對稱加密要注意的地方主要就是塊加密模式(這個也不是對稱獨有的,在非對稱中也存在模式概念)!CipherMode類型定義如下:

public enum CipherMode

{

     CBC = 1,

     ECB = 2,

     OFB = 3,

     CFB = 4,

     CTS = 5

}

關于CipherMode的解釋見

ms-help://MS.VSCC.v80/MS.MSDN.v80/MS.NETDEVFX.v20.chs/cpref11/html/T_System_Security_Cryptography_CipherMode.htm

本來打算ctrl+c/ ctrl+v的,但看了半天都不知道在說什麼,真不知道翻譯的人是不懂呢?還是其它原因?現在隻能自己寫這部分了。

ECB 電子密碼本

把加密串分成64bit一組,不足部分添齊(這裡留到後面說),然後對每一個塊單獨加密,最終一塊塊的密文塊組成密文,解密過程相反!如圖:

System.Security.Cryptography實戰

CBC密碼塊鍊

CBC模式的出現 就是為了補救ECB模式的一些缺點(密文一樣原文也一樣),過程如圖所示,這裡就不畫蛇了:

System.Security.Cryptography實戰

OFB 輸出反潰模式

下圖E’是加密函數E的一種變換,具體過程可以看書,這裡主要展示的它的大至過程:

System.Security.Cryptography實戰

CFB 密碼回報模式

與上面的OFB類似,也是對OFB模式的一種加強,E’函數與OFB一樣

System.Security.Cryptography實戰

CTR 記數模式

這種模式用IV加密,再與明文異或得到密文塊,且下次加密塊用到的IV是先前的IV加1,過程如圖:

System.Security.Cryptography實戰

 C#代碼

//這樣就可以實作檔案或記憶體塊的加密了,解密類似!

//這裡需要注意的是:SymmetricAlgorithm預設的加密模式為CBC,見下代碼:

//protected SymmetricAlgorithm ()

//{

//  this.ModeValue = CipherMode.CBC;

//  this.PaddingValue = PaddingMode.PKCS7;

//}

//這樣當64位塊一樣時,出現同樣的密文可能性很小!

//使用者可以通過改變SymmetricAlgorithm成員ModeValue來改變加密模式來比較一下了!

//看上SymmetricAlgorithm構造函數發現pad也是可選的,後面可以看msdn,總算可以看明白了,感謝翻譯!

SymmetricAlgorithm oSym = DES.Create();

MemoryStream oMem=new MemoryStream();

byte [] AKey={0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31};

byte [] AIV= {0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31};

CryptoStream oStream = new CryptoStream(oMem, oSym.CreateEncryptor(AKey,AIV), CryptoStreamMode.Write);

byte[] AInput ={ 0x31, 0x31, 0x31, 0x31, 0x31, 0x31,0x31,0x31,0x31 };

oStream.Write(AInput, 0, AInput.Length);

oStream.Close();

byte[] AOutput=oMem.ToArray();

這裡還的引用一下msdn的關于pad的描述:

ms-help://MS.VSCC.v80/MS.MSDN.v80/MS.NETDEVFX.v20.chs/cpref11/html/T_System_Security_Cryptography_PaddingMode.htm

ANSIX923

ANSIX923 填充字元串由一個位元組序列組成,此位元組序列的最後一個位元組填充位元組序列的長度,其餘位元組均填充數字零。

下面的示例示範此模式的工作原理。假定塊長度為 8,資料長度為 9,則填充用八位位元組數等于 7,資料等于 FF FF FF FF FF FF FF FF FF:

資料: FF FF FF FF FF FF FF FF FF

X923 填充: FF FF FF FF FF FF FF FF FF 00 00 00 00 00 00 07

ISO10126

ISO10126 填充字元串由一個位元組序列組成,此位元組序列的最後一個位元組填充位元組序列的長度,其餘位元組填充随機資料。

下面的示例示範此模式的工作原理。假定塊長度為 8,資料長度為 9,則填充用八位位元組數等于 7,資料等于 FF FF FF FF FF FF FF FF FF:

資料: FF FF FF FF FF FF FF FF FF

ISO10126 填充: FF FF FF FF FF FF FF FF FF 7D 2A 75 EF F8 EF 07

None 不填充。

PKCS7

PKCS #7 填充字元串由一個位元組序列組成,每個位元組填充該位元組序列的長度。 

下面的示例示範這些模式的工作原理。假定塊長度為 8,資料長度為 9,則填充用八位位元組數等于 7,資料等于 FF FF FF FF FF FF FF FF FF:

資料: FF FF FF FF FF FF FF FF FF

PKCS7 填充: FF FF FF FF FF FF FF FF FF 07 07 07 07 07 07 07

Zeros

填充字元串由設定為零的位元組組成。

以上紅字部分出自《MSDN》

3.非對稱加密

意指加解密的密鑰是不一樣的,加密一個,解密一個!一個叫公鑰,一個叫私鑰!加密方式的安全性要比對稱的安全些,但安全不是絕對的!這種算法最主要運用場景就是數字簽名!像RSA/DSA!

 C#代碼

//加解密資料

//生成公私鑰

RSACryptoServiceProvider oRSA = new RSACryptoServiceProvider();

string privatekey=oRSA.ToXmlString(true);

string publickey=oRSA.ToXmlString(false);

byte[] AOutput;

//公鑰加密

RSACryptoServiceProvider oRSA1 = new RSACryptoServiceProvider();

oRSA1.FromXmlString(publickey);

byte[] AInput={0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31};

AOutput = oRSA1.Encrypt(AInput,false);

//私鑰解密

RSACryptoServiceProvider oRSA2 = new RSACryptoServiceProvider();

oRSA2.FromXmlString(privatekey);           

AInput = oRSA2.Decrypt(AOutput, false);

//私鑰簽名

RSACryptoServiceProvider oRSA3 = new RSACryptoServiceProvider();

oRSA3.FromXmlString(privatekey);

AOutput = oRSA3.SignData(AInput, "MD5");

//公鑰驗證

RSACryptoServiceProvider oRSA4 = new RSACryptoServiceProvider();

oRSA4.FromXmlString(publickey);

bool  bVerify= oRSA4.VerifyData(AInput, "MD5",AOutput);

這裡需要提到的是DSA隻能運用到數字簽名和驗證,加解密還的用RSA,關于最後一個參數“false:是什麼意思,可以參考msdn,這裡也不想添足了!

繼續閱讀