DES 加密演算法是一種對稱加密演算法,但是用來加解密的 Key 及 IV 需要固定長度,DES 的 Key 及 IV 長度大小都是固定 8 bytes,也就是說每次加解密的過程中都需要湊足 8 bytes 的 Key 及 IV,多了或少了都不行。
我參考余小章的文章 - [C#.NET] 字串及檔案 利用 DES / AES 演算法加解密,實作如何使用不固定長度的 Key 及 IV 進行 DES 加解密。
加密
如何使用不固定長度的 Key 及 IV,關鍵就在於把不固定轉成固定就行了,下面我使用 MD5CryptoServiceProvider 及 Rfc2898DeriveBytes 這兩個類別提供的方法來達成這件事情。
private string EncryptByDES(string source, string key, string iv)
{
DESCryptoServiceProvider des = new DESCryptoServiceProvider();
// Rfc2898DeriveBytes 類別可以用來從基底金鑰與其他參數中產生衍生金鑰。
// 使用 MD5 來 Hash 出 Rfc2898 需要的 Salt。
Rfc2898DeriveBytes rfc2898 = new Rfc2898DeriveBytes(key, this.HashByMD5(key));
// 8 bits = 1 byte,將 KeySize 及 BlockSize 個別除以 8,取得 Rfc2898 產生衍生金鑰的長度。
des.Key = rfc2898.GetBytes(des.KeySize / 8);
des.IV = rfc2898.GetBytes(des.BlockSize / 8);
var dataByteArray = Encoding.UTF8.GetBytes(source);
// 加密
using (MemoryStream ms = new MemoryStream())
using (CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(dataByteArray, 0, dataByteArray.Length);
cs.FlushFinalBlock();
return Convert.ToBase64String(ms.ToArray());
}
// 或
var encrypted = des.CreateEncryptor().TransformFinalBlock(dataByteArray, 0, dataByteArray.Length);
return Convert.ToBase64String(encrypted);
}
MD5 Hash 方法
private byte[] HashByMD5(string source)
{
MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
return md5.ComputeHash(Encoding.UTF8.GetBytes(source));
}
解密
解密也一樣,利用 MD5CryptoServiceProvider 及 Rfc2898DeriveBytes 取得 Key 及 IV 後進行解密程序。
private string DecryptByDES(string encrypted, string key, string iv)
{
DESCryptoServiceProvider des = new DESCryptoServiceProvider();
// Rfc2898DeriveBytes 類別可以用來從基底金鑰與其他參數中產生衍生金鑰。
// 使用 MD5 來 Hash 出 Rfc2898 需要的 Salt。
Rfc2898DeriveBytes rfc2898 = new Rfc2898DeriveBytes(key, this.HashByMD5(key));
// 8 bits = 1 byte,將 KeySize 及 BlockSize 個別除以 8,取得 Rfc2898 產生衍生金鑰的長度。
des.Key = rfc2898.GetBytes(des.KeySize / 8);
des.IV = rfc2898.GetBytes(des.BlockSize / 8);
var dataByteArray = Convert.FromBase64String(encrypted);
// 解密
using (MemoryStream ms = new MemoryStream())
using (CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(dataByteArray, 0, dataByteArray.Length);
cs.FlushFinalBlock();
return Encoding.UTF8.GetString(ms.ToArray());
}
// 或
var decryped = des.CreateDecryptor().TransformFinalBlock(dataByteArray, 0, dataByteArray.Length);
return Encoding.UTF8.GetString(decryped);
}
< Source Code >