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等 )
l 對稱加密算法 (DES/TRI-DES等)
l 非對稱加密算法(RSA/DSA)
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一組,不足部分添齊(這裡留到後面說),然後對每一個塊單獨加密,最終一塊塊的密文塊組成密文,解密過程相反!如圖:
CBC密碼塊鍊
CBC模式的出現 就是為了補救ECB模式的一些缺點(密文一樣原文也一樣),過程如圖所示,這裡就不畫蛇了:
OFB 輸出反潰模式
下圖E’是加密函數E的一種變換,具體過程可以看書,這裡主要展示的它的大至過程:
CFB 密碼回報模式
與上面的OFB類似,也是對OFB模式的一種加強,E’函數與OFB一樣
CTR 記數模式
這種模式用IV加密,再與明文異或得到密文塊,且下次加密塊用到的IV是先前的IV加1,過程如圖:
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,這裡也不想添足了!
完