DES (Data Encryption Standard) 是 56 位密鑰的對稱分組加密算法,雖已被 AES 取代,但在維護舊系統、對接老接口、嵌入式設備通信等場景仍廣泛使用。本文提供生產級 C# 實現,涵蓋 ECB/CBC 模式、PKCS7 填充、Base64 編碼、初始化向量 (IV) 處理、鑰匙派生、異常處理與安全最佳實踐。
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
public static class DesEncryption {
// 默認密鑰與 IV (僅演示,生產環境嚴禁硬編碼!)
private const string DefaultKey = "VavicApp"; // 8 字節 = 64 位 (含 8 位校驗位,實際 56 位有效)
private const string DefaultIV = "VavicApp"; // CBC 模式必須 8 字節 IV
///
/// DES 加密 (CBC 模式 + PKCS7 填充 + Base64 輸出)
///
public static string Encrypt(string plainText, string key = null, string iv = null, CipherMode mode = CipherMode.CBC) {
if (string.IsNullOrEmpty(plainText)) return string.Empty;
key ??= DefaultKey;
iv ??= DefaultIV;
ValidateKeyIV(key, iv);
using var des = DES.Create();
des.Key = Encoding.ASCII.GetBytes(key.PadRight(8).Substring(0, 8)); // 強制 8 字節
des.IV = Encoding.ASCII.GetBytes(iv.PadRight(8).Substring(0, 8));
des.Mode = mode;
des.Padding = PaddingMode.PKCS7;
using var ms = new MemoryStream();
using var cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write);
using var sw = new StreamWriter(cs, Encoding.UTF8);
sw.Write(plainText);
sw.Flush();
cs.FlushFinalBlock();
return Convert.ToBase64String(ms.ToArray());
}
///
/// DES 解密
///
public static string Decrypt(string cipherText, string key = null, string iv = null, CipherMode mode = CipherMode.CBC) {
if (string.IsNullOrEmpty(cipherText)) return string.Empty;
key ??= DefaultKey;
iv ??= DefaultIV;
ValidateKeyIV(key, iv);
byte[] cipherBytes;
try {
cipherBytes = Convert.FromBase64String(cipherText);
} catch (FormatException) {
throw new CryptographicException("無效的 Base64 密文");
}
using var des = DES.Create();
des.Key = Encoding.ASCII.GetBytes(key.PadRight(8).Substring(0, 8));
des.IV = Encoding.ASCII.GetBytes(iv.PadRight(8).Substring(0, 8));
des.Mode = mode;
des.Padding = PaddingMode.PKCS7;
using var ms = new MemoryStream(cipherBytes);
using var cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Read);
using var sr = new StreamReader(cs, Encoding.UTF8);
return sr.ReadToEnd();
}
private static void ValidateKeyIV(string key, string iv) {
if (string.IsNullOrEmpty(key) || key.Length < 8) throw new ArgumentException("密鑰必須至少 8 字符");
if (string.IsNullOrEmpty(iv) || iv.Length < 8) throw new ArgumentException("IV 必須至少 8 字符");
}
}
string original = "敏感數據:身份證 11010119900307893X、銀行卡 6225880123456789";
string encrypted = DesEncryption.Encrypt(original);
string decrypted = DesEncryption.Decrypt(encrypted);
Console.WriteLine($"原文: {original}");
Console.WriteLine($"密文: {encrypted}"); // 輸出 Base64 字符串
Console.WriteLine($"解密: {decrypted}");
Console.WriteLine($"驗證: {original == decrypted}"); // True
| 參數 | 推薦值 | 說明 |
|---|---|---|
| Algorithm | DES | 固定 64 位塊大小,56 位有效密鑰 |
| Mode | CBC (Cipher Block Chaining) | **首選**。引入 IV,相同明文加密出不同密文,抵抗模式分析。ECB 模式不安全,僅用於兼容極老系統 |
| Padding | PKCS7 | 填充至 8 字節倍數。.NET PaddingMode.PKCS7 等同 PKCS#5 |
| Key | 8 字節 (64 位) | 第 8、16、24...56 位為奇偶校驗位,實際熵 56 位。**嚴禁硬編碼**,需從 KMS/環境變量/安全存儲讀取 |
| IV | 8 字節,隨機生成 | **每次加密必須隨機生成新 IV**,與密文一起存儲/傳輸(通常前綴在密文前)。不可重複使用相同 Key+IV |
| Encoding | UTF-8 | 明文轉字節編碼,雙方約定一致 |
| Output Encoding | Base64 | 二進制密文安全傳輸編碼 |
public static class DesEncryptionV2 {
// 密文格式: [IV(8 bytes)][CipherText...] -> Base64
public static string EncryptWithRandomIV(string plainText, string key) {
if (string.IsNullOrEmpty(plainText)) return string.Empty;
ValidateKey(key);
using var des = DES.Create();
des.Key = Encoding.ASCII.GetBytes(key.PadRight(8).Substring(0, 8));
des.Mode = CipherMode.CBC;
des.Padding = PaddingMode.PKCS7;
des.GenerateIV(); // 自動生成隨機 IV
using var ms = new MemoryStream();
ms.Write(des.IV, 0, des.IV.Length); // 寫入 IV 作為密文頭
using var cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write);
using var sw = new StreamWriter(cs, Encoding.UTF8);
sw.Write(plainText);
sw.Flush();
cs.FlushFinalBlock();
return Convert.ToBase64String(ms.ToArray());
}
public static string DecryptWithRandomIV(string cipherText, string key) {
if (string.IsNullOrEmpty(cipherText)) return string.Empty;
ValidateKey(key);
byte[] fullBytes = Convert.FromBase64String(cipherText);
if (fullBytes.Length < 8) throw new CryptographicException("密文過短,不含 IV");
using var des = DES.Create();
des.Key = Encoding.ASCII.GetBytes(key.PadRight(8).Substring(0, 8));
des.Mode = CipherMode.CBC;
des.Padding = PaddingMode.PKCS7;
byte[] iv = new byte[8];
Array.Copy(fullBytes, 0, iv, 0, 8);
des.IV = iv;
byte[] cipherBytes = new byte[fullBytes.Length - 8];
Array.Copy(fullBytes, 8, cipherBytes, 0, cipherBytes.Length);
using var ms = new MemoryStream(cipherBytes);
using var cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Read);
using var sr = new StreamReader(cs, Encoding.UTF8);
return sr.ReadToEnd();
}
private static void ValidateKey(string key) {
if (string.IsNullOrEmpty(key) || key.Length < 8) throw new ArgumentException("密鑰至少 8 字符");
}
}
var pbkdf2 = new Rfc2898DeriveBytes(password, salt, 100000, HashAlgorithmName.SHA256); var key = pbkdf2.GetBytes(8);新系統**強制使用 AES-256-GCM** (或 AES-256-CBC+HMAC-SHA256):
using var aes = Aes.Create();
aes.KeySize = 256;
aes.Mode = CipherMode.GCM; // .NET 6+ 支持 GCM,內置認證加密
aes.GenerateKey();
aes.GenerateIV();
// 加密
using var encryptor = aes.CreateEncryptor();
var cipher = encryptor.TransformFinalBlock(plainBytes, 0, plainBytes.Length);
var tag = aes.GetTag(); // GCM 認證標籤
// 存儲: IV + Cipher + Tag
AES 優勢:128/192/256 位密鑰、128 位塊大小、硬件加速 (AES-NI)、認證加密模式 (GCM/CCM) 防篡改、無已知實用攻擊。
Bad Data / Padding is invalidEncoding.UTF8。CryptoStream),避免全量載入內存。雖然 DES 已退出歷史舞台,但理解其模式、填充、IV、鑰匙管理原理,是掌握現代對稱加密 (AES、ChaCha20-Poly1305) 的基石。維護舊系統時請嚴格遵循「隨機 IV、密鑰外部化、認證加密」原則,將風險降至最低。