javax.crypto.IllegalBlockSizeException: Input length must be multiple of 8 when decrypting with padded cipher
解密時拋出塊大小非法異常,且後續出現 NullPointerException。
Cipher.getInstance("DES") 使用預設模式 ECB/NoPadding,要求輸入長度為 8 字節倍數。實際數據長度不固定,解密失敗。KeyGenerator 每次生成隨機密鑰,導致加密解密密鑰不一致。catch 僅打印堆疊,返回 null 或空字串,後續操作觸發 NPE。public class DESUtil {
private static final String ALGORITHM = "DES/CBC/PKCS5Padding";
private static final String KEY = "19491001"; // 8 字節密鑰,生產環境應從配置讀取
private static SecretKeySpec getKeySpec() {
return new SecretKeySpec(KEY.getBytes(StandardCharsets.UTF_8), "DES");
}
private static IvParameterSpec getIvSpec() {
return new IvParameterSpec(KEY.getBytes(StandardCharsets.UTF_8)); // 簡化:密鑰作 IV,實際應隨機生成並隨密文存儲
}
// 加密:返回 Base64 字串,便於傳輸
public static String encrypt(String plainText) throws Exception {
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, getKeySpec(), getIvSpec());
byte[] encrypted = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(encrypted);
}
// 解密:輸入 Base64 字串
public static String decrypt(String encryptedBase64) throws Exception {
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, getKeySpec(), getIvSpec());
byte[] decoded = Base64.getDecoder().decode(encryptedBase64);
byte[] decrypted = cipher.doFinal(decoded);
return new String(decrypted, StandardCharsets.UTF_8);
}
// 測試
public static void main(String[] args) throws Exception {
String original = "product_id=12345";
String encrypted = encrypt(original);
String decrypted = decrypt(encrypted);
System.out.println("加密: " + encrypted);
System.out.println("解密: " + decrypted);
}
}
DES/CBC/PKCS5Padding,自動處理填充,無需手動補齊 8 字節。// JSP 加密傳參
String encId = DESUtil.encrypt(request.getParameter("product_id"));
response.sendRedirect("action.do?encId=" + URLEncoder.encode(encId, "UTF-8"));
// Action 解密
String encId = request.getParameter("encId");
String productId = DESUtil.decrypt(encId);
DES 已不安全(密鑰僅 56 位),生產環境強烈建議升級至 AES-256-GCM,並使用隨機 IV、認證加密防篡改。