詳解DES&3DES算法的原理以及C#和JS的實(shí)現(xiàn)
一、簡介
1、DES 簡介
DES 全稱為 Data Encryption Standard,即數(shù)據(jù)加密標(biāo)準(zhǔn),是一種使用密鑰加密的塊算法,1977 年被美國聯(lián)邦政府的國家標(biāo)準(zhǔn)局確定為聯(lián)邦資料處理標(biāo)準(zhǔn)(FIPS),并授權(quán)在非密級政府通信中使用,隨后該算法在國際上廣泛流傳開來。
在很長時(shí)間內(nèi),許多人心目中“密碼生成”與 DES 一直是個(gè)同義詞。直到 1997 年 NIST(美國國家標(biāo)準(zhǔn)與技術(shù)研究院)開始公開征集更安全的加密算法以替代 DES,并在 2001 年推出了更加安全的 AES(Advanced Encryption Standard)高級加密標(biāo)準(zhǔn)。
優(yōu)點(diǎn):
- Feistel 網(wǎng)絡(luò)的輪數(shù)可以任意增加;
- 解密與輪函數(shù) f 無關(guān),輪函數(shù)f也不需要有逆函數(shù);
- 輪函數(shù)可以設(shè)計(jì)得足夠復(fù)雜;
- 加密和解密可以使用完全相同的結(jié)構(gòu)來實(shí)現(xiàn)。
缺點(diǎn):
- 分組比較短;
- 密鑰太短;
- 密碼生命周期短;
- 運(yùn)算速度較慢。
2、3DES 簡介
其實(shí)并不是直接由 DES 過渡到 AES,還有一個(gè) 3DES 統(tǒng)治時(shí)期。3DES 也稱 Triple DES,它使用 3 條 56 位的密鑰對數(shù)據(jù)進(jìn)行三次加密。
3DES 算法通過對 DES 算法進(jìn)行改進(jìn),增加 DES 的密鑰長度來避免類似的攻擊,針對每個(gè)數(shù)據(jù)塊進(jìn)行三次 DES 加密;因此,3DES 加密算法并非什么新的加密算法,是 DES 的一個(gè)更安全的變形,它以 DES 為基本模塊,通過組合分組方法設(shè)計(jì)出分組加密算法。
相比 DES,3DES 因密鑰長度變長,安全性有所提高,但其處理速度不高。因此又出現(xiàn)了 AES 加密算法,AES 較于 3DES 速度更快、安全性也更高。
加密:
為了兼容普通的 DES,3DES 并沒有直接使用 加密->加密->加密 的方式,而是采用了 加密->解密->加密 的方式。
當(dāng)三重密鑰均相同時(shí),前兩步相互抵消,相當(dāng)于僅實(shí)現(xiàn)了一次加密,因此可實(shí)現(xiàn)對普通 DES 加密算法的兼容。
解密:
3DES 解密過程,與加密過程相反,即逆序使用密鑰。是以密鑰 3、密鑰 2、密鑰 1的順序執(zhí)行 解密->加密->解密。
二、C# 代碼實(shí)現(xiàn)
1、DES
// 測試(密鑰需要是八位字符) string jiamihou = DesEncrypt("TestString", "11111222", false); // 57fe567eaa866373f851a526f07d9e26 string jiamiqian = DesDecrypt(jiamihou32, "11111222"); /// <summary> /// DES加密字符串 /// </summary> /// <param name="deseninstr">待加密的字符串</param> /// <param name="deskey">加密密鑰,要求為8位</param> /// <param name="isupper">返回大寫密文,false:小寫</param> /// <returns>加密成功返回加密后的字符串,失敗返回源串</returns> public static string DesEncrypt(string deseninstr, string deskey, bool isupper = true) { StringBuilder stringBuilder = new StringBuilder(); try { DESCryptoServiceProvider des = new DESCryptoServiceProvider(); byte[] inputByteArray = Encoding.UTF8.GetBytes(deseninstr); des.Key = Encoding.UTF8.GetBytes(deskey); des.IV = Encoding.UTF8.GetBytes(deskey); // 當(dāng) mode 為 CBC 時(shí),偏移量必傳 des.Mode=CipherMode.ECB; // 為空默認(rèn) CBC MemoryStream memoryStream = new MemoryStream(); CryptoStream cryptoStream = new CryptoStream(memoryStream, des.CreateEncryptor(), CryptoStreamMode.Write); cryptoStream.Write(inputByteArray, 0, inputByteArray.Length); cryptoStream.FlushFinalBlock(); foreach (byte bb in memoryStream.ToArray()) { stringBuilder.AppendFormat(isupper ? "{0:X2}" : "{0:x2}", bb); } return stringBuilder.ToString(); } catch (Exception ex) { return deseninstr; } } /// <summary> /// DES解密字符串 /// </summary> /// <param name="desdeinstr">待解密的字符串</param> /// <param name="deskey">解密密鑰,要求為8位</param> /// <returns>解密成功返回解密后的字符串,失敗返源串</returns> public static string DesDecrypt(string desdeinstr, string deskey) { MemoryStream memoryStream = new MemoryStream(); try { DESCryptoServiceProvider des = new DESCryptoServiceProvider(); byte[] inputByteArray = new byte[desdeinstr.Length / 2]; for (int ii = 0; ii < desdeinstr.Length / 2; ii++) { int intt = (Convert.ToInt32(desdeinstr.Substring(ii * 2, 2), 16)); inputByteArray[ii] = (byte)intt; } des.Key = Encoding.UTF8.GetBytes(deskey); des.IV = Encoding.UTF8.GetBytes(deskey); // 當(dāng) mode 為 CBC 時(shí),偏移量必傳 des.Mode = CipherMode.ECB; // 為空默認(rèn) CBC CryptoStream cs = new CryptoStream(memoryStream, des.CreateDecryptor(), CryptoStreamMode.Write); cs.Write(inputByteArray, 0, inputByteArray.Length); cs.FlushFinalBlock(); return Encoding.UTF8.GetString(memoryStream.ToArray()); } catch { return desdeinstr; } }
2、3DES
密文采用 Base64 格式輸出。
疑問解答:三次加解密操作會運(yùn)用三個(gè)不同的 Key,但是我們只傳入了一個(gè)密鑰,怎么回事?
3DES 密鑰必須為 24 位,為 DES 的 3 倍,經(jīng)測試得出結(jié)論:
TripleDESCryptoServiceProvider 內(nèi)部將密鑰分成 3 份,進(jìn)行了加密解密三重操作。
我們把 24 位字符串分成三部分,如果三部分均相等,或前兩部分相等,就會報(bào)錯(cuò):"Specified key is a known weak key for 'TripleDES' and cannot be used."--指定的密鑰是'TripleDES'的已知弱密鑰,不能使用。
// 測試 string jiamihou16 = SecurityDES.Des3Encrypt("TestString", "111112222233333444445555", "12345678"); // yJGf3qgWyoAQeaPY2S5Etg== string jiamihou32 = SecurityDES.Des3Decrypt(jiamihou16, "111112222233333444445555", "12345678"); /// <summary> /// 3DES 加密 /// </summary> /// <param name="des3eninstr"></param> /// <param name="des3key">24 位</param> /// <param name="des3iv">8 位</param> /// <returns></returns> public static string Des3Encrypt(string des3eninstr, string des3key, string des3iv) { string encryptPassword = string.Empty; SymmetricAlgorithm algorithm = new TripleDESCryptoServiceProvider(); algorithm.Key = Encoding.UTF8.GetBytes(des3key);// Convert.FromBase64String(des3key); algorithm.IV = Encoding.UTF8.GetBytes(des3iv); algorithm.Mode = CipherMode.ECB; algorithm.Padding = PaddingMode.PKCS7; ICryptoTransform transform = algorithm.CreateEncryptor(); byte[] data = Encoding.UTF8.GetBytes(des3eninstr); MemoryStream memoryStream = new MemoryStream(); CryptoStream cryptoStream = new CryptoStream(memoryStream, transform, CryptoStreamMode.Write); cryptoStream.Write(data, 0, data.Length); cryptoStream.FlushFinalBlock(); encryptPassword = Convert.ToBase64String(memoryStream.ToArray()); memoryStream.Close(); cryptoStream.Close(); return encryptPassword; } /// <summary> /// 3DES 解密 /// </summary> /// <param name="des3deinstr">密文 Base64</param> /// <param name="des3key">24 位</param> /// <param name="des3iv">8 位</param> /// <returns></returns> public static string Des3Decrypt(string des3deinstr, string des3key, string des3iv) { string decryptPassword = string.Empty; SymmetricAlgorithm algorithm = new TripleDESCryptoServiceProvider(); algorithm.Key = Encoding.UTF8.GetBytes(des3key); algorithm.IV = Encoding.UTF8.GetBytes(des3iv); algorithm.Mode = CipherMode.ECB; algorithm.Padding = PaddingMode.PKCS7; ICryptoTransform transform = algorithm.CreateDecryptor(algorithm.Key, algorithm.IV); byte[] buffer = Convert.FromBase64String(des3deinstr); MemoryStream memoryStream = new MemoryStream(buffer); CryptoStream cryptoStream = new CryptoStream(memoryStream, transform, CryptoStreamMode.Read); StreamReader reader = new StreamReader(cryptoStream, System.Text.Encoding.ASCII); decryptPassword = reader.ReadToEnd(); reader.Close(); cryptoStream.Close(); memoryStream.Close(); return decryptPassword; }
三、js 語言實(shí)現(xiàn)
以下是通過 crypto-js.js 實(shí)現(xiàn)。
1、DES
注意:mode 為空默認(rèn) CBC,此時(shí)偏移量 iv 不可為空。
注意:密鑰可用位數(shù)為 8,如果超過 8 位以后的對加密結(jié)果無影響,且不會報(bào)錯(cuò)。
// 先引入 js 文件 <script src="http://cdn.bootcdn.net/ajax/libs/crypto-js/4.0.0/crypto-js.js"></script> // npm(Node.js package manager)方式 > npm install crypto-js // 調(diào)用方法 message() 查看測試結(jié)果 function message(){ var outdata_value = encryptByDES("TestString", "11111222"); alert(outdata_value) // 57fe567eaa866373f851a526f07d9e26 console.log("outdata_value-aes_encrypt:", outdata_value); outdata_value = decryptByDES(outdata_value, "11111222"); alert(outdata_value) console.log("outdata_value-aes_decrypt:", outdata_value); } //DES 加密 function encryptByDES(deseninstr, keystr, ivstr = keystr) { var keybyte = CryptoJS.enc.Utf8.parse(keystr); var ivbyte = CryptoJS.enc.Utf8.parse(ivstr); let afterEncrypt = CryptoJS.DES.encrypt(deseninstr, keybyte, { iv: ivbyte, // 當(dāng) mode 為 CBC 時(shí),偏移量必傳 mode: CryptoJS.mode.ECB, // 為空默認(rèn) CBC padding: CryptoJS.pad.Pkcs7 }).ciphertext.toString() console.log(afterEncrypt) return afterEncrypt } //DES 解密 function decryptByDES(desdeinstr, keystr, ivstr = keystr) { var keybyte = CryptoJS.enc.Utf8.parse(keystr); var ivbyte = CryptoJS.enc.Utf8.parse(ivstr); var decrypted = CryptoJS.DES.decrypt( { ciphertext: CryptoJS.enc.Hex.parse(desdeinstr) }, keybyte, { iv: ivbyte, // 當(dāng) mode 為 CBC 時(shí),偏移量必傳 mode: CryptoJS.mode.ECB, // 為空默認(rèn) CBC padding: CryptoJS.pad.Pkcs7 } ); console.log(decrypted); var result_value = decrypted.toString(CryptoJS.enc.Utf8); return result_value; }
2、3DES
// 調(diào)用方法 message() 查看測試結(jié)果 function message() { var outdata_value = encryptByDES("TestString", "111112222233333444445555"); alert(outdata_value) // yJGf3qgWyoAQeaPY2S5Etg== console.log("outdata_value-3des_encrypt:", outdata_value); outdata_value = decryptByDES(outdata_value, "111112222233333444445555"); alert(outdata_value) console.log("outdata_value-3des_decrypt:", outdata_value); } // 加密 密鑰需為 24 位,偏移量需為 8 位 function encryptByDES(deseninstr, keystr) { var keybyte = CryptoJS.enc.Utf8.parse(keystr); //var ivbyte = CryptoJS.enc.Utf8.parse(ivstr); var encrypted = CryptoJS.TripleDES.encrypt(deseninstr, keybyte, { // iv: ivbyte, // 當(dāng) mode 為 CBC 時(shí),偏移量必傳 mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7 }); return encrypted.toString(); } // 解密 密鑰需為 24 位,偏移量需為 8 位 function decryptByDES(desdeinstr, keystr) { var keybyte = CryptoJS.enc.Utf8.parse(keystr); //var ivbyte = CryptoJS.enc.Utf8.parse(ivstr); var decrypted = CryptoJS.TripleDES.decrypt(desdeinstr, keybyte, { // iv: ivbyte, // 當(dāng) mode 為 CBC 時(shí),偏移量必傳 mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7 }); return decrypted.toString(CryptoJS.enc.Utf8); }
到此這篇關(guān)于詳解DES&3DES算法的原理以及C#和JS的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)DES算法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
淺談vscode中task.json和launch.json的關(guān)系
本文主要介紹了淺談vscode中task.json和launch.json的關(guān)系,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-08-08利用ChatGPT與MindShow制作一個(gè)PPT的方法詳解
PPT制作是商務(wù)、教育和各種場合演講的重要組成部分,然而,很多人會花費(fèi)大量時(shí)間和精力在內(nèi)容生成和視覺設(shè)計(jì)方面,為了解決這個(gè)問題,我們可以利用兩個(gè)強(qiáng)大的工具——ChatGPT和MindShow,來提高制作PPT的效率,感興趣的同學(xué)可以參考閱讀2023-06-06asp php 清空access mysql mssql數(shù)據(jù)庫的代碼
php清空mysql asp情況access或mssql2008-12-12VS2019 自定義項(xiàng)目模板的實(shí)現(xiàn)方法
這篇文章主要介紹了VS2019 自定義項(xiàng)目模板的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04UTC時(shí)間、GMT時(shí)間、本地時(shí)間、Unix時(shí)間戳的具體使用
本文主要介紹了UTC時(shí)間、GMT時(shí)間、本地時(shí)間、Unix時(shí)間戳的具體使用,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09