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

Java AES 加密算法深度解析:從基礎用法到生產級最佳實踐

     編輯:Java 相關知識

前言:為什麼選擇 AES?

AES(Advanced Encryption Standard)是目前最廣泛採用的對稱加密算法,以其高安全性、高性能、硬件加速友好的特點,成為數據加密的事實標準。Java 通過 JCA(Java Cryptography Architecture)原生支持 AES,無需引入第三方庫。本文將從核心 API 用法、關鍵參數選擇、常見坑點到生產級封裝進行全方位講解。

核心 API 快速上手

1. 密鑰生成

// 生成 256 位 AES 密鑰(需 JCE 無限制強度策略文件)
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(256); // 可選 128/192/256
SecretKey secretKey = keyGen.generateKey();

// 若需從字符串派生密鑰(如用戶輸入密碼),請使用 PBKDF2
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 65536, 256);
SecretKey derivedKey = factory.generateSecret(spec);

2. 加密操作

Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); // 推薦 GCM 模式
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] iv = cipher.getIV(); // GCM 必須獲取隨機生成的 IV
byte[] ciphertext = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));
// 存儲格式:IV + 密文(或 IV + 密文 + AuthTag)

3. 解密操作

Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
GCMParameterSpec spec = new GCMParameterSpec(128, iv); // 128-bit 認證標籤
cipher.init(Cipher.DECRYPT_MODE, secretKey, spec);
byte[] plaintext = cipher.doFinal(ciphertext);
String result = new String(plaintext, StandardCharsets.UTF_8);

關鍵參數選擇指南

參數推薦值說明
密鑰長度256 bits長期機密性需求選 256;性能敏感可用 128
工作模式GCM (Galois/Counter Mode)提供機密性+完整性認證(AEAD),防篡改;避免使用 ECB、CBC(需額外 MAC)
填充方式NoPadding (GCM 內建)GCM/CFB/OFB/CTR 為流模式,無需填充
IV/Nonce96-bit 隨機數GCM 推薦 12 字節,**同一密鑰下絕不重複**;可用 SecureRandom 生成
認證標籤長度128 bitsGCMParameterSpec 指定,越長越安全

⚠️ 生產環境必避的 5 大坑

  1. 使用 ECB 模式:Cipher.getInstance("AES") 默認為 ECB/PKCS5Padding,**極不安全**(相同明文塊產生相同密文塊),圖像加密時輪廓清晰可見。
  2. 硬編碼/固定 IV:IV 必須隨機且唯一,固定 IV 等同於破壞語義安全性。
  3. 密鑰管理混亂:密鑰不應硬編碼在代碼/配置文件中,應使用 KMS(如 HashiCorp Vault、AWS KMS、阿里雲 KMS)托管,運行時動態拉取。
  4. 忽略認證標籤:CBC 模式需額外計算 HMAC(Encrypt-then-MAC),GCM 內建認證,**解密時必須驗證標籤**,否則無法檢測篡改。
  5. 未處理 JCE 限制:Oracle JDK 默認限制密鑰長度 ≤ 128 位,使用 256 位需替換 local_policy.jar/US_export_policy.jar 或升級至 JDK 8u161+(默認解除限制)。

生產級工具類封裝(線程安全、易用)

public final class AesGcmUtil {
    private static final String ALGORITHM = "AES/GCM/NoPadding";
    private static final int IV_LENGTH = 12;  // 96-bit
    private static final int TAG_LENGTH = 128; // 128-bit
    private static final SecureRandom RANDOM = new SecureRandom();

    private final SecretKey key;

    public AesGcmUtil(SecretKey key) { this.key = key; }

    /** 加密,返回 Base64(IV + 密文) */
    public String encrypt(String plaintext) {
        try {
            byte[] iv = new byte[IV_LENGTH];
            RANDOM.nextBytes(iv);
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, key, new GCMParameterSpec(TAG_LENGTH, iv));
            byte[] ciphertext = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));
            // 合併 IV + 密文
            byte[] combined = new byte[iv.length + ciphertext.length];
            System.arraycopy(iv, 0, combined, 0, iv.length);
            System.arraycopy(ciphertext, 0, combined, iv.length, ciphertext.length);
            return Base64.getEncoder().encodeToString(combined);
        } catch (GeneralSecurityException e) {
            throw new IllegalStateException("加密失敗", e);
        }
    }

    /** 解密,輸入 Base64(IV + 密文) */
    public String decrypt(String combinedBase64) {
        try {
            byte[] combined = Base64.getDecoder().decode(combinedBase64);
            if (combined.length < IV_LENGTH) throw new IllegalArgumentException("數據長度非法");
            byte[] iv = Arrays.copyOfRange(combined, 0, IV_LENGTH);
            byte[] ciphertext = Arrays.copyOfRange(combined, IV_LENGTH, combined.length);
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, key, new GCMParameterSpec(TAG_LENGTH, iv));
            byte[] plaintext = cipher.doFinal(ciphertext);
            return new String(plaintext, StandardCharsets.UTF_8);
        } catch (GeneralSecurityException e) {
            throw new IllegalStateException("解密失敗/數據被篡改", e);
        }
    }
}

使用示例

// 初始化(實際從 KMS 獲取)
SecretKey key = ...; 
AesGcmUtil util = new AesGcmUtil(key);

// 業務調用
String encrypted = util.encrypt("敏感數據:身份證號 1234567890");
String decrypted = util.decrypt(encrypted);
assert "敏感數據:身份證號 1234567890".equals(decrypted);

總結

Java 實現 AES 加密雖然 API 簡單,但模式選擇、IV 管理、密鑰托管、認證驗證等工程細節決定了系統的真實安全性。牢記:優先選 GCM、IV 唯一隨機、密鑰上 KMS、標籤必驗證。將上述工具類納入項目公共庫,統一加密規範,才能在合規審計與實戰攻防中立於不敗之地。

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