首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 程式設計入門

Java AES 加密解密實戰:跨平台一致、支援中文、Base64 輸出

     編輯:Java 程式設計入門

AES(Advanced Encryption Standard)是對稱加密標準,廣泛用於敏感數據傳輸與存儲。本文提供生產級工具類,解決「Linux/Windows 结果不一致」「中文亂碼」「密鑰派生不穩定」等常見坑點,採用 AES/ECB/PKCS5Padding 模式,輸出 Base64 字串便於 JSON/URL 傳輸。

核心設計要點

  • 固定密鑰長度 128 位,密鑰由密碼經 SHA1PRNG 派生,確保跨平台一致(需注意:JDK 8+ SHA1PRNG 實現可能差異,生產建議改用 PBKDF2)。
  • 模式:AES/ECB/PKCS5Padding(ECB 模式無 IV,簡單但安全性較低;高安全場景請用 CBC/GCM + 隨機 IV)。
  • 字符集:統一 UTF-8,解決中文亂碼。
  • 輸出:加密結果經 Base64 編碼,解密先 Base64 解碼。

完整工具類

import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.security.*;
import java.util.Base64; // JDK 8+ 內建,舊版用 Apache Commons Codec

public class AesUtil {

    private static final String ALGO = "AES";
    private static final String TRANSFORMATION = "AES/ECB/PKCS5Padding";
    private static final int KEY_SIZE = 128;
    private static final String CHARSET = "UTF-8";

    /** 從密碼派生 128 位 AES 密鑰 */
    private static SecretKeySpec deriveKey(String password) throws NoSuchAlgorithmException, InvalidKeyException {
        // 注意:SecureRandom SHA1PRNG 在不同 JDK 實現可能不同,生產建議用 PBKDF2WithHmacSHA256
        KeyGenerator kgen = KeyGenerator.getInstance(ALGO);
        SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
        sr.setSeed(password.getBytes(StandardCharsets.UTF_8));
        kgen.init(KEY_SIZE, sr);
        SecretKey secretKey = kgen.generateKey();
        return new SecretKeySpec(secretKey.getEncoded(), ALGO);
    }

    /** 加密 → Base64 字串 */
    public static String encrypt(String content, String password) {
        try {
            SecretKeySpec key = deriveKey(password);
            Cipher cipher = Cipher.getInstance(TRANSFORMATION);
            cipher.init(Cipher.ENCRYPT_MODE, key);
            byte[] encrypted = cipher.doFinal(content.getBytes(CHARSET));
            return Base64.getEncoder().encodeToString(encrypted);
        } catch (Exception e) {
            throw new RuntimeException("AES 加密失敗", e);
        }
    }

    /** Base64 字串 → 解密明文 */
    public static String decrypt(String base64Content, String password) {
        try {
            SecretKeySpec key = deriveKey(password);
            Cipher cipher = Cipher.getInstance(TRANSFORMATION);
            cipher.init(Cipher.DECRYPT_MODE, key);
            byte[] decoded = Base64.getDecoder().decode(base64Content);
            byte[] decrypted = cipher.doFinal(decoded);
            return new String(decrypted, CHARSET);
        } catch (Exception e) {
            throw new RuntimeException("AES 解密失敗", e);
        }
    }

    // 測試
    public static void main(String[] args) {
        String plain = "t太陽est地";
        String pwd = "12345678";
        String cipher = encrypt(plain, pwd);
        System.out.println("加密: " + cipher); // 例: Bpf0jyJDj/pVHaRf66+OMA==
        System.out.println("解密: " + decrypt(cipher, pwd)); // t太陽est地
    }
}

關鍵坑點避雷指南

問題原因解決方案
Linux/Windows 加密結果不同SHA1PRNG 實現差異改用 PBKDF2WithHmacSHA256 固定迭代次數、鹽值派生密鑰
中文加密後解密亂碼字符集不一致全鏈路強制 UTF-8(getBytes(CHARSET)/new String(bytes, CHARSET))
密文長度非 16 倍數報錯ECB/PKCS5Padding 自動填充,解密時需完整密文確保 Base64 完整傳輸,無截斷/換行
金鑰長度不足/非法密碼過短導致派生弱建議密碼 ≥ 16 字符,或改用 PBKDF2 + 固定鹽值

進階建議:生產環境請升級

  1. 模式改 CBC/GCM:引入隨機 IV(隨密文輸出),防止相同明文產生相同密文。
  2. 密鑰派生用 PBKDF2:SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"),迭代 ≥ 100,000,鹽值 16 字節隨機生成。
  3. 金鑰管理:勿硬編碼密碼,使用 KMS/環境變數/配置中心注入。
  4. 完整性驗證:GCM 模式自帶認證標籤;CBC 需額外 HMAC。

總結

本文提供的工具類可直接用於測試、內部非核心數據加密。對於高安全要求場景,請務必採用 AES-GCM + PBKDF2 + 安全金鑰管理 方案。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved