設計目標
- 採用 **TripleDES (3DES)** 對稱加密,兼容舊系統。
- 金鑰 (Key) 與初始向量 (IV) 從 **設定檔** 讀取,不硬編碼。
- 提供 **靜態輔助類**,封裝 `ICryptoTransform`、`CryptoStream` 細節。
- 正確處理 **資源釋放**、**異常捕獲**、**Base64 編碼** 輸出。
設定檔區段
<configuration>
<appSettings>
<add key="DES_Key" value="KIPSToILGp6fl+3gXJvMsN4IajizYBBT" /> <!-- 24 bytes Base64 = 192 bits -->
<add key="DES_IV" value="SuFjcEmp/TE=" /> <!-- 8 bytes Base64 = 64 bits -->
</appSettings>
</configuration>
生成金鑰腳本 (一次性執行存入設定檔):
using (var tdes = new TripleDESCryptoServiceProvider())
{
tdes.GenerateKey(); tdes.GenerateIV();
Console.WriteLine("Key: " + Convert.ToBase64String(tdes.Key));
Console.WriteLine("IV: " + Convert.ToBase64String(tdes.IV));
}
CryptoHelper 完整實作
using System;
using System.Configuration;
using System.IO;
using System.Security.Cryptography;
using System.Text;
public static class CryptoHelper
{
private static readonly byte[] _key = Convert.FromBase64String(ConfigurationManager.AppSettings["DES_Key"]);
private static readonly byte[] _iv = Convert.FromBase64String(ConfigurationManager.AppSettings["DES_IV"]);
/// 加密字串 → Base64 密文
public static string Encrypt(string plainText)
{
if (string.IsNullOrEmpty(plainText)) return string.Empty;
using (var tdes = new TripleDESCryptoServiceProvider { Key = _key, IV = _iv, Mode = CipherMode.CBC, Padding = PaddingMode.PKCS7 })
using (var ms = new MemoryStream())
using (var cs = new CryptoStream(ms, tdes.CreateEncryptor(), CryptoStreamMode.Write))
using (var sw = new StreamWriter(cs, Encoding.UTF8))
{
sw.Write(plainText);
sw.Flush(); // 關鍵:確保資料寫入 CryptoStream
cs.FlushFinalBlock();
return Convert.ToBase64String(ms.ToArray());
}
}
/// Base64 密文 → 解密明文
public static string Decrypt(string cipherBase64)
{
if (string.IsNullOrEmpty(cipherBase64)) return string.Empty;
try
{
byte[] cipherBytes = Convert.FromBase64String(cipherBase64);
using (var tdes = new TripleDESCryptoServiceProvider { Key = _key, IV = _iv, Mode = CipherMode.CBC, Padding = PaddingMode.PKCS7 })
using (var ms = new MemoryStream(cipherBytes))
using (var cs = new CryptoStream(ms, tdes.CreateDecryptor(), CryptoStreamMode.Read))
using (var sr = new StreamReader(cs, Encoding.UTF8))
{
return sr.ReadToEnd();
}
}
catch (CryptographicException)
{
// 金鑰錯誤、資料竄改、Padding 無效
return null; // 或拋出自訂異常
}
catch (FormatException)
{
// 非合法 Base64
return null;
}
}
}
關鍵實作細節解析
| 細節 | 說明 |
| CipherMode.CBC | 密碼分組鏈接模式,需 IV,比 ECB 安全。 |
| PaddingMode.PKCS7 | 標準填充,跨平台相容 (Java/Python 同規格)。 |
| StreamWriter/StreamReader | 自動處理 UTF-8 編碼轉換,避免手動 GetBytes 錯誤。 |
| sw.Flush() + cs.FlushFinalBlock() | 確保所有緩衝區資料經過加密寫入 MemoryStream。 |
| using 區塊巢狀 | 保證 CryptoStream、MemoryStream、TripleDES 正確 Dispose,釋放非託管資源。 |
| 靜態唯讀金鑰 | 應用程式啟動讀取一次,效能最佳;若需熱更新可改用 Lazy/設定監聽。 |
使用範例
string original = "機敏資料:身分證 A123456789";
string encrypted = CryptoHelper.Encrypt(original); // "N8lAaHMFtSAQgaf3+RUFng=="
string decrypted = CryptoHelper.Decrypt(encrypted); // 還原原文
Console.WriteLine($"加密: {encrypted}");
Console.WriteLine($"解密: {decrypted}");
安全性與現代化建議
| 議題 | 建議 |
| 3DES 已棄用 | NIST 建議遷移至 **AES-256-GCM** (認證加密),提供機密性+完整性。 |
| 金鑰管理 | 生產環境應使用 **Azure Key Vault / HashiCorp Vault / AWS KMS**,勿存於 web.config。 |
| IV 重複使用 | CBC 模式下同一 Key 必須搭配**隨機 IV**,建議每次加密產生新 IV 並前綴於密文。 |
| 完整性驗證 | 3DES-CBC 无認證標籤,易受 Padding Oracle 攻擊。改用 AES-GCM 或額外加 HMAC-SHA256。 |
AES-GCM 現代化實作片段 (.NET Core 3.1+)
public static class AesGcmHelper
{
public static (byte[] cipher, byte[] nonce, byte[] tag) Encrypt(byte[] key, byte[] plain)
{
var nonce = new byte[12]; // GCM 建議 96-bit nonce
RandomNumberGenerator.Fill(nonce);
var tag = new byte[16];
var cipher = new byte[plain.Length];
using (var aes = new AesGcm(key))
aes.Encrypt(nonce, plain, cipher, tag);
return (cipher, nonce, tag);
}
public static byte[] Decrypt(byte[] key, byte[] nonce, byte[] cipher, byte[] tag)
{
var plain = new byte[cipher.Length];
using (var aes = new AesGcm(key))
aes.Decrypt(nonce, cipher, tag, plain);
return plain;
}
}