DES 概述與現狀
DES (Data Encryption Standard) 為 1977 年美國聯邦標準,56 位有效金鑰,64 位分組。現已不安全(1997 年暴力破解 < 24 小時),實務上已被 AES (128/192/256-bit) 取代。本文僅供維護舊系統、教學理解對稱加密原理參考,新專案嚴禁使用 DES。
核心參數說明
| 參數 | 值 | 說明 |
| 演算法/模式/填充 | DES/CBC/PKCS5Padding | CBC 模式需 IV,PKCS5Padding 自動填充至 8 位元組倍數 |
| 金鑰長度 | 8 位元組 (56 位有效 + 8 位奇偶校驗) | 不足 8 位拋 InvalidKeyException |
| IV (初始向量) | 8 位元組 | CBC 模式必須,建議隨機生成並與密文一同傳輸 |
| 編碼 | Base64 | 二進位密文安全傳輸(JSON、URL、XML) |
完整工具類原始碼
import java.security.Key;
import java.security.SecureRandom;
import java.security.spec.AlgorithmParameterSpec;
import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
import org.apache.commons.codec.binary.Base64; // 需 commons-codec 依賴
public class Des {
public static final String ALGORITHM = "DES/CBC/PKCS5Padding";
// 固定 IV(示範用),生產環境必須隨機生成!
private static final byte[] FIXED_IV = "********".getBytes(StandardCharsets.UTF_8);
/** 加密:String → Base64 String */
public static String encode(String key, String data) throws Exception {
return encode(key, data.getBytes(StandardCharsets.UTF_8));
}
/** 加密:byte[] → Base64 String */
public static String encode(String key, byte[] data) throws Exception {
Key secretKey = generateKey(key);
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(FIXED_IV));
byte[] encrypted = cipher.doFinal(data);
return Base64.encodeBase64String(encrypted);
}
/** 解密:Base64 String → byte[] */
public static byte[] decode(String key, byte[] data) throws Exception {
Key secretKey = generateKey(key);
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(FIXED_IV));
return cipher.doFinal(data);
}
/** 解密:Base64 String → String */
public static String decodeValue(String key, String data) throws Exception {
byte[] decoded = Base64.decodeBase64(data);
byte[] decrypted = decode(key, decoded);
String result = new String(decrypted, StandardCharsets.UTF_8);
if (result.isEmpty()) throw new Exception("解密結果為空");
return result;
}
private static Key generateKey(String key) throws Exception {
if (key == null || key.getBytes(StandardCharsets.UTF_8).length < 8) {
throw new IllegalArgumentException("金鑰長度不得小於 8 位元組");
}
DESKeySpec dks = new DESKeySpec(key.getBytes(StandardCharsets.UTF_8));
SecretKeyFactory factory = SecretKeyFactory.getInstance("DES");
return factory.generateSecret(dks);
}
}
使用範例
public class DesTest {
public static void main(String[] args) throws Exception {
String key = "MySecretKey123"; // 至少 8 字元
String original = "敏感資料:身分證 A123456789";
// 加密
String encrypted = Des.encode(key, original);
System.out.println("密文: " + encrypted); // 如: xYz789...==
// 解密
String decrypted = Des.decodeValue(key, encrypted);
System.out.println("明文: " + decrypted);
// 驗證
assert original.equals(decrypted);
}
}
關鍵安全實踐(若必須用 DES)
- IV 必須隨機:每次加密生成新
SecureRandom 8 位元組 IV,密文格式:IV(8 bytes) + Ciphertext,解密時前 8 位切割作 IV。
- 金鑰管理:勿硬編碼,使用 KMS、環境變數、HashiCorp Vault、AWS KMS 等。
- 金鑰派生:若金鑰來自密碼,必須用
PBKDF2WithHmacSHA256 + 隨機 Salt + 10萬+ 迭代派生 8 位元組 DES 金鑰。
- 完整性驗證:DES 無內建認證,需額外計算 HMAC-SHA256(密文) 並驗證,防止填充神諭攻擊。
- 避免 ECB 模式:
DES/ECB/PKCS5Padding 相同明文塊產生相同密文塊,嚴重洩露模式。
遷移至 AES(推薦)
// AES-256-CBC 範例
public class AesUtil {
static final String ALGO = "AES/CBC/PKCS5Padding";
static final int KEY_SIZE = 256;
public static String encrypt(String key, String data) throws Exception {
byte[] keyBytes = key.getBytes(StandardCharsets.UTF_8);
// 若金鑰非 32 位元組,用 SHA-256 摘要截取
Key secretKey = new SecretKeySpec(
MessageDigest.getInstance("SHA-256").digest(keyBytes), "AES");
Cipher cipher = Cipher.getInstance(ALGO);
byte[] iv = new byte[16];
new SecureRandom().nextBytes(iv);
cipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(iv));
byte[] encrypted = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
// 組合 IV + 密文
byte[] combined = new byte[iv.length + encrypted.length];
System.arraycopy(iv, 0, combined, 0, iv.length);
System.arraycopy(encrypted, 0, combined, iv.length, encrypted.length);
return Base64.encodeBase64String(combined);
}
// 解密對應拆分 IV...
}
常見異常與排查
| 異常 | 原因 | 解決 |
InvalidKeyException: Illegal key size | JCE 限制金鑰長度(舊版 JDK) | 安裝 Unlimited Strength JCE Policy Files 或升級 JDK |
BadPaddingException | 金鑰/IV 錯誤、資料損壞、填充模式不匹配 | 核對金鑰、IV、填充模式、確認 Base64 正確解碼 |
InvalidAlgorithmParameterException | IV 長度不等於 8 (DES) 或 16 (AES) | 確保 IV 正確長度 |
NoSuchAlgorithmException | 提供者不支援 DES(極少見) | 確認 Security.getProviders() 包含 SunJCE |
法律合規提醒
- 中國《商用密碼管理條例》規定:涉及國家秘密、關鍵資訊基礎設施,必須使用國家認證密碼演算法 (SM2/SM3/SM4)。
- 出口管制:舊版美國 EAR 限制強加密軟體出口,現已大幅放寬,但仍需留意目的地國家法規。
- GDPR/個資法:加密是「適當技術措施」之一,但 DES 不再視為充分保護,監管機構可能判定不合規。
總結
- DES 為歷史教學/舊系統維護用途,核心 API:
Cipher.getInstance("DES/CBC/PKCS5Padding") + DESKeySpec + IvParameterSpec + Base64。
- 新專案一律使用 AES-256-GCM 或 ChaCha20-Poly1305(AEAD 模式,同時提供機密性與完整性)。
- 金鑰管理、IV 隨機化、完整性驗證、合規演算法選型,才是加密工程的核心難點。