原問題1:
加密時是直接寫入文件的,解密時是一邊讀加密后的文件,一邊解。對于有的字符串就對,有的就不對,我懷疑那個DES加密的類有問題。
public static void DesEncrypt(Stream inStream,Stream outStream,byte[] desKey,byte[] desIV)
{
DES des=new DESCryptoServiceProvider();
CryptoStream cs=new CryptoStream(outStream,des.CreateEncryptor(desKey,desIV),CryptoStreamMode.Write);
byte[] buf=new byte[1024];
int len=0;
while ((len=inStream.Read(buf,0,buf.Length))>0)
{
cs.Write(buf,0,len);
}
cs.Close();
}
public static void DesDeEncrypt(Stream inStream,Stream outStream,byte[] desKey,byte[] desIV)
{
DES des=new DESCryptoServiceProvider();
CryptoStream cs=new CryptoStream(inStream,des.CreateDecryptor(desKey,desIV),CryptoStreamMode.Read);
byte[] buf=new byte[1024];
int len=0;
while ((len=cs.Read(buf,0,buf.Length))>0)
{
outStream.Write(buf,0,len);
}
}
原問題2:
發現加密類RijndaelManaged的問題,根據MSDN的這個例子發現的問題,例子源碼(VS2003)
ms-help://MS.VSCC.2003/MS.MSDNQTR.2003FEB.2052/cpref/html/frlrfSystemSecurityCryptographyRijndaelManagedClassTopic.htm
問題描述:在最后的Console.WriteLine("Round Trip: {0}", roundtrip );這行代碼后面追加下面的代碼
Console.WriteLine(original.Length == roundtrip.Length);
運行一下看看,按照正常想法應該是解密后的內容應該與原文完全相同,輸出True,但是卻輸出False。
這兩個問題都差不多,都是因為不了解對稱加密(AES/DES等)的加密原理,而誤認為.net framework的加密算法有問題。
AES/DES都是塊式加密的(塊的大小等于密鑰的大小)。對于AES算法,其密鑰大小為128bit(16byte),故每塊16byte,在加密之前要對加密數據進行填充(例如:如果要用AES算法加密100byte的數據,則填充成112byte構成16的倍數,加密之后的數據大小為112byte;如果要加密112byte,則要另外填充16byte,構成128byte,加密之后的數據大小為128byte)。現在回過頭來看看問題2,我們將MSDN中的代碼改成下面這樣則可以返回true了:
fromEncrypt = new byte[toEncrypt.Length];//MSDN中使用的是encrypted.Length;
csDecrypt.Read(fromEncrypt, 0, fromEncrypt.Length);
這是因為按照MSDN的示例執行加密后,由于填充的緣故,encrypted的長度要比toEncrypt大,而MSDN的示例中是以encrypted的長度來設定fromEncrypt的長度,故解密之后fromEncrypt后面有一段是空的,得到的解密后字符串roundtrip中的后面有一截是以'\0'進行填充了,故長度不一樣了。而使用toEncrypt.Length來設定fromEncrypt的長度,則申請的空間剛剛夠用,不用填充。
下面再來看看第一個問題:每次取1024byte進行加密,加密時系統會自動填充8個byte(DES的密鑰長度為64bit),加密后得到1024+8byte的數據,所以你解密的時候要每次取1024+8byte進行解密。而對于加密前文件大小小于或等于1016byte的文件,加密后大小小于或等于1024byte,故循環只執行一次,按照問題中的解密代碼可以解密成功,而對于再大一點或更大的文件,則必然解密失敗,所以才出現問題中的“對于有的字符串就對,有的就不對”。修正后的測試代碼如下:
DESCryptoServiceProvider des = new DESCryptoServiceProvider();
des.GenerateKey();
des.GenerateIV();
FileStream fs1 = new FileStream("自然.mp3", FileMode.Open, FileAccess.Read);
FileStream fs2 = new FileStream("Encrypted.mp3", FileMode.OpenOrCreate, FileAccess.Write);
//加密
CryptoStream csEnCrypt=new CryptoStream(fs2,des.CreateEncryptor(des.Key,des.IV),CryptoStreamMode.Write);
byte[] buf=new byte[1024];
int len = 0;
while ((len=fs1.Read(buf,0,buf.Length))>0)
{
csEnCrypt.Write(buf,0,len);
csEnCrypt.Flush();
Console.WriteLine("Encrypt: " + len.ToString());
}
Console.ReadLine();
Console.WriteLine(" ");
csEnCrypt.Close();
fs1.Close();
fs2.Close();
//解密
FileStream fs4 = new FileStream("Encrypted.mp3", FileMode.OpenOrCreate, FileAccess.Read);
FileStream fs3 = new FileStream("Decrypted.mp3", FileMode.OpenOrCreate, FileAccess.Write);
CryptoStream csDecrypt = new CryptoStream(fs4, des.CreateDecryptor(des.Key, des.IV), CryptoStreamMode.Read);
byte[] buf2 = new byte[1024+8];
while ((len = csDecrypt.Read(buf2, 0, buf2.Length)) > 0)
{
Console.WriteLine("Decrypt: " + len.ToString());
fs3.Write(buf2, 0,len);
fs3.Flush();
}
csDecrypt.Close();
fs3.Close();//可以正常播放了
fs4.Close();
補充 :.Net數據安全
1.填充模式(Padding Mode): None,PKCS7,Zeros.
2.加密模式(Cipher Mode):CBC,CFB,CTS,ECB,OFB.
3.對稱加密:
DESCryptoServiceProvider: Key- 64bit IV- 64bit
RC2CryptoServiceProvider: Key-128bit IV- 64bit
DijndaeManaged(AES) : Key-256/128/192bit IV-128bit
TripDESCryptoServiceProvider: key-192bit IV- 64bit
CreateDecryptor()構造解密器,CreateEncryptor()構造加密器。
4.非對稱加密:
DSA:KeySize=1024bit
DSASignatrueFommatter類:創建數字簽名;
DSASignatrueDefommatter類:驗證數字簽名;
RSA:KeySize=1024bit
加密:RSA.Encrypt(byte[] DataEncrypt,bool Padding)
解密:RSA.Decrypt(byte[] DataEncrypt,bool Padding)
導出/導入密鑰:RSA.ToXmlString(bool)/RSA.FromXml(string)
簽名/驗證:RSA.SignData()/RSA.VerifyData()
5.消息摘要:
HMACSHA1
MACTripleDES
MD5CryptoServiceProvider(128bit)
SHA1Managed(160bit)
SHA256Managed(256bit)
SHA384Managed(384bit)
SHA512Managed(512bit)
參考文獻:
[1] MSDN
[2] 《應用密碼學》Bruce Schneier[著],吳世忠等[譯]

浙公網安備 33010602011771號