AES (Advanced Encryption Standard),高級加密標準,是對稱分組加密算法標準。核心特性:
| 類/接口 | 作用 |
|---|---|
Cipher | 加密/解密核心引擎,無狀態,需 init 初始化 |
KeyGenerator | 對稱密鑰生成器 |
SecretKey | 對稱密鑰接口 |
IvParameterSpec | 初始化向量 (IV) 參數規範 |
SecretKeySpec | 從字節數組構建密鑰 |
public static void ecbPkcs5(String plaintext) throws Exception {
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
SecretKey key = KeyGenerator.getInstance("AES").generateKey(); // 隨機密鑰
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] encrypted = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));
System.out.println("加密: " + Base64.getEncoder().encodeToString(encrypted));
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] decrypted = cipher.doFinal(encrypted);
System.out.println("解密: " + new String(decrypted, StandardCharsets.UTF_8));
}
缺點:相同明文產生相同密文,模式可見性差,不安全。
public static void cbcPkcs5(String plaintext) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKey key = KeyGenerator.getInstance("AES").generateKey();
byte[] iv = generateSecureIV(); // 16 字節安全隨機 IV
cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));
byte[] encrypted = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));
System.out.println("IV: " + Base64.getEncoder().encodeToString(iv));
System.out.println("加密: " + Base64.getEncoder().encodeToString(encrypted));
cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
byte[] decrypted = cipher.doFinal(encrypted);
System.out.println("解密: " + new String(decrypted, StandardCharsets.UTF_8));
}
private static byte[] generateSecureIV() {
byte[] iv = new byte[16];
new SecureRandom().nextBytes(iv);
return iv;
}
關鍵點:
public static void cbcNoPadding(String plaintext) throws Exception {
// 前提:明文長度必須是 16 字節倍數
if (plaintext.getBytes(StandardCharsets.UTF_8).length % 16 != 0) {
throw new IllegalArgumentException("NoPadding 要求數據長度為 16 倍數");
}
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
SecretKey key = KeyGenerator.getInstance("AES").generateKey();
byte[] iv = "1234567812345678".getBytes(StandardCharsets.UTF_8); // 固定 IV 僅演示
cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));
byte[] encrypted = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));
cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
byte[] decrypted = cipher.doFinal(encrypted);
System.out.println("解密: " + new String(decrypted, StandardCharsets.UTF_8));
}
public static void encryptWithFixedKey(String plaintext, String base64Key, String base64Iv) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
// 從 Base64 還原密鑰和 IV
byte[] keyBytes = Base64.getDecoder().decode(base64Key);
byte[] ivBytes = Base64.getDecoder().decode(base64Iv);
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
byte[] encrypted = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(encrypted);
}
| 填充模式 | 填充規則 | 適用場景 | 數據長度要求 |
|---|---|---|---|
| PKCS5Padding | 缺幾字節填幾個該數值字節 | 通用推薦,Java 默認 | 任意長度 |
| PKCS7Padding | 同 PKCS5,支持更大分組 | BouncyCastle 提供 | 任意長度 |
| NoPadding | 不填充 | 數據已對齊、流式加密、自定義填充 | 必須是 16 倍數 |
| ISO10126Padding | 隨機填充,最後字節標示長度 | 舊系統兼容 | 任意長度 |
KeyGenerator 或 PBKDF2 從密碼派生(SecretKeyFactory)SecureRandom 生成 16 字節,每次加密唯一public static String encryptGCM(String plaintext, SecretKey key) throws Exception {
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
byte[] iv = new byte[12]; // GCM 推薦 96 位 IV
new SecureRandom().nextBytes(iv);
GCMParameterSpec spec = new GCMParameterSpec(128, iv); // 128 位認證標籤
cipher.init(Cipher.ENCRYPT_MODE, key, spec);
byte[] encrypted = cipher.doFinal(plaintext.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.getEncoder().encodeToString(combined);
}
| 異常 | 原因 | 解決 |
|---|---|---|
| IllegalBlockSizeException | NoPadding 模式下數據非 16 倍數 | 使用 PKCS5Padding 或手動填充 |
| InvalidKeyException: Illegal key size | 密鑰長度超過默認限制 (128 位) | 安裝 JCE Unlimited Strength Jurisdiction Policy |
| InvalidAlgorithmParameterException: Wrong IV length | IV 長度不等於 16 (CBC) 或 12 (GCM) | 嚴格按模式要求生成 IV |
| BadPaddingException | 解密密鑰/IV 錯誤、數據損壞 | 核對密鑰、IV、確保數據完整傳輸 |
Java AES 加密核心在於:選對模式(生產首選 CBC+PKCS5Padding 或 GCM)、管好密鑰(隨機生成、安全存儲、定期輪換)、用好 IV(CBC 每次隨機 16 字節、GCM 12 字節)、編碼規範(Base64 存储/傳輸二進制數據)。避免使用 ECB 模式、硬編碼密鑰/IV、自定義填充邏輯。現代應用強烈建議升級到 AES-GCM 獲得認證加密保護。