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

Java 實現 AES 加密演算法完整範例:CBC 模式、PKCS7Padding、Base64 編碼

     編輯:Java 相關知識

AES 關鍵參數選擇

  • 模式:CBC(Cipher Block Chaining),需初始化向量(IV),比 ECB 安全。
  • 填充:PKCS7Padding(Java 稱 PKCS5Padding),區塊大小 16 位元組。
  • 金鑰長度:128/192/256 位。本例用 SHA-256 摘要種子取前 16 位元組作 128-bit 金鑰。
  • IV:生產環境必須隨機生成並隨密文儲存/傳輸,本例為示範固定全 0。

完整工具類

import javax.crypto.*;
import javax.crypto.spec.*;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

public final class AesCrypt {
    private static final String ALGORITHM = "AES/CBC/PKCS5Padding";
    private static final String SEED = "U1MjU1M0FDOUZ.Qz"; // 16 字元種子,實際應從配置/密碼管理讀取
    private static final byte[] FIXED_IV = new byte[16]; // 僅示範,生產請用 SecureRandom 生成

    private final SecretKeySpec keySpec;
    private final IvParameterSpec ivSpec;

    public AesCrypt() throws NoSuchAlgorithmException {
        // 衍生金鑰:SHA-256(SEED) 取前 16 bytes
        MessageDigest digest = MessageDigest.getInstance("SHA-256");
        byte[] hash = digest.digest(SEED.getBytes(StandardCharsets.UTF_8));
        byte[] keyBytes = new byte[16];
        System.arraycopy(hash, 0, keyBytes, 0, 16);
        this.keySpec = new SecretKeySpec(keyBytes, "AES");
        this.ivSpec = new IvParameterSpec(FIXED_IV);
    }

    public String encrypt(String plainText) {
        try {
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
            byte[] encrypted = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
            return Base64.getEncoder().encodeToString(encrypted);
        } catch (Exception e) {
            throw new RuntimeException("加密失敗", e);
        }
    }

    public String decrypt(String cipherText) {
        try {
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
            byte[] decoded = Base64.getDecoder().decode(cipherText);
            byte[] decrypted = cipher.doFinal(decoded);
            return new String(decrypted, StandardCharsets.UTF_8);
        } catch (Exception e) {
            throw new RuntimeException("解密失敗", e);
        }
    }

    // 測試
    public static void main(String[] args) throws Exception {
        AesCrypt crypt = new AesCrypt();
        String original = "敏感資料:身分證 A123456789";
        String encrypted = crypt.encrypt(original);
        String decrypted = crypt.decrypt(encrypted);
        System.out.println("原文:" + original);
        System.out.println("密文:" + encrypted);
        System.out.println("解密:" + decrypted);
    }
}

生產環境必做的強化

  1. 隨機 IV:每次加密生成新 IV(SecureRandom),將 IV(16 bytes)拼接在密文前端,解密時切割取出。
    // 加密時
    byte[] iv = new byte[16]; new SecureRandom().nextBytes(iv);
    cipher.init(Cipher.ENCRYPT_MODE, keySpec, new IvParameterSpec(iv));
    byte[] cipherBytes = cipher.doFinal(plainBytes);
    byte[] output = new byte[iv.length + cipherBytes.length];
    System.arraycopy(iv, 0, output, 0, iv.length);
    System.arraycopy(cipherBytes, 0, output, iv.length, cipherBytes.length);
    return Base64.getEncoder().encodeToString(output);
    
    // 解密時
    byte[] input = Base64.getDecoder().decode(cipherText);
    byte[] iv = Arrays.copyOfRange(input, 0, 16);
    byte[] cipherBytes = Arrays.copyOfRange(input, 16, input.length);
    // ... 用 iv 初始化 IvParameterSpec 解密
    
  2. 金鑰管理:勿硬編碼,使用 Vault、AWS KMS、環境變數、JCEKS keystore。
  3. 完整性驗證:AES-CBC 無完整性保護,建議改用 AES-GCM(Authenticated Encryption)或額外加 HMAC-SHA256。
  4. 例外處理:區分 BadPaddingException(密文/金鑰錯誤)、IllegalBlockSizeException 資料損壞,避免洩露細節。

常見坑點

  • PKCS5Padding 在 Java 中實際支援 16 位元組區塊(AES),名稱歷史原因。
  • Base64 編碼/解碼需指定 StandardCharsets.UTF_8,避免平台預設編碼差異。
  • Android 使用 android.util.Base64,JRE 用 java.util.Base64(Java 8+)或 Apache Commons Codec。

線上工具驗證

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