詳解DES&3DES算法的原理以及C#和JS的實(shí)現(xiàn)
一、簡(jiǎn)介
1、DES 簡(jiǎn)介
DES 全稱為 Data Encryption Standard,即數(shù)據(jù)加密標(biāo)準(zhǔn),是一種使用密鑰加密的塊算法,1977 年被美國(guó)聯(lián)邦政府的國(guó)家標(biāo)準(zhǔn)局確定為聯(lián)邦資料處理標(biāo)準(zhǔn)(FIPS),并授權(quán)在非密級(jí)政府通信中使用,隨后該算法在國(guó)際上廣泛流傳開來。
在很長(zhǎng)時(shí)間內(nèi),許多人心目中“密碼生成”與 DES 一直是個(gè)同義詞。直到 1997 年 NIST(美國(guó)國(guó)家標(biāo)準(zhǔn)與技術(shù)研究院)開始公開征集更安全的加密算法以替代 DES,并在 2001 年推出了更加安全的 AES(Advanced Encryption Standard)高級(jí)加密標(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 簡(jiǎn)介
其實(shí)并不是直接由 DES 過渡到 AES,還有一個(gè) 3DES 統(tǒng)治時(shí)期。3DES 也稱 Triple DES,它使用 3 條 56 位的密鑰對(duì)數(shù)據(jù)進(jìn)行三次加密。
3DES 算法通過對(duì) DES 算法進(jìn)行改進(jìn),增加 DES 的密鑰長(zhǎng)度來避免類似的攻擊,針對(duì)每個(gè)數(shù)據(jù)塊進(jìn)行三次 DES 加密;因此,3DES 加密算法并非什么新的加密算法,是 DES 的一個(gè)更安全的變形,它以 DES 為基本模塊,通過組合分組方法設(shè)計(jì)出分組加密算法。
相比 DES,3DES 因密鑰長(zhǎng)度變長(zhǎng),安全性有所提高,但其處理速度不高。因此又出現(xiàn)了 AES 加密算法,AES 較于 3DES 速度更快、安全性也更高。
加密:
為了兼容普通的 DES,3DES 并沒有直接使用 加密->加密->加密 的方式,而是采用了 加密->解密->加密 的方式。
當(dāng)三重密鑰均相同時(shí),前兩步相互抵消,相當(dāng)于僅實(shí)現(xiàn)了一次加密,因此可實(shí)現(xiàn)對(duì)普通 DES 加密算法的兼容。
解密:
3DES 解密過程,與加密過程相反,即逆序使用密鑰。是以密鑰 3、密鑰 2、密鑰 1的順序執(zhí)行 解密->加密->解密。
二、C# 代碼實(shí)現(xiàn)
1、DES
// 測(cè)試(密鑰需要是八位字符)
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 格式輸出。
疑問解答:三次加解密操作會(huì)運(yùn)用三個(gè)不同的 Key,但是我們只傳入了一個(gè)密鑰,怎么回事?
3DES 密鑰必須為 24 位,為 DES 的 3 倍,經(jīng)測(cè)試得出結(jié)論:
TripleDESCryptoServiceProvider 內(nèi)部將密鑰分成 3 份,進(jìn)行了加密解密三重操作。
我們把 24 位字符串分成三部分,如果三部分均相等,或前兩部分相等,就會(huì)報(bào)錯(cuò):"Specified key is a known weak key for 'TripleDES' and cannot be used."--指定的密鑰是'TripleDES'的已知弱密鑰,不能使用。
// 測(cè)試
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 位以后的對(duì)加密結(jié)果無影響,且不會(huì)報(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() 查看測(cè)試結(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() 查看測(cè)試結(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)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
做一個(gè)優(yōu)秀程序員應(yīng)該知道的15件事
這篇文章主要介紹了做一個(gè)優(yōu)秀程序員應(yīng)該知道的15件事,寫的很好,需要的朋友可以參考下2014-07-07
flask+layui+echarts實(shí)現(xiàn)前端動(dòng)態(tài)圖展示數(shù)據(jù)效果
這篇文章主要介紹了flask+layui+echarts實(shí)現(xiàn)前端動(dòng)態(tài)圖展示數(shù)據(jù)效果,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-09-09
Source?Insight?4.0.093?安裝破解詳細(xì)圖文教程
這篇文章主要介紹了Source?Insight?4.0.093?安裝破解詳細(xì)圖文教程,source?insight?4是一款非常強(qiáng)大的程序編輯器,如果你沒有一款合適的代碼編輯器,那么這款軟件不妨試試,可能你會(huì)喜歡2022-08-08
EventStore文件存儲(chǔ)設(shè)計(jì)詳解
ENode是一個(gè)CQRS+Event Sourcing架構(gòu)的開發(fā)框架,這篇文章主要介紹了EventStore文件存儲(chǔ)設(shè)計(jì) ,需要的朋友可以參考下2019-05-05

