package com.xiaopeng.common.core.utils; import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import javax.crypto.spec.GCMParameterSpec; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import java.nio.charset.StandardCharsets; import java.security.SecureRandom; import java.util.Base64; /** * AES 加密解密工具类 *

* 支持功能: * 1. AES 加密、解密(支持多种模式和填充方式) * 2. 密钥生成(支持 128/192/256 位) * 3. 初始化向量(IV)生成 * 4. Base64 编码/解码 *

* 支持的模式: * - AES/ECB/PKCS5Padding:简单模式,不需要IV * - AES/CBC/PKCS5Padding:需要IV,更安全 * - AES/GCM/NoPadding:需要IV和Tag,最适合现代应用 *

* 注意事项: * - ECB 模式不安全,不建议使用 * - 密钥长度必须是 16/24/32 字节(对应 128/192/256 位) * - IV 长度:AES 块大小为 16 字节 * - GCM 模式 Tag 长度为 16 字节 * - 使用 ThreadLocal 缓存 Cipher 实例,提升高并发性能 */ public class AESUtil { private static final String AES_ALGORITHM = "AES"; private static final String TRANSFORMATION_ECB = "AES/ECB/PKCS5Padding"; private static final String TRANSFORMATION_CBC = "AES/CBC/PKCS5Padding"; private static final String TRANSFORMATION_GCM = "AES/GCM/NoPadding"; private static final int GCM_TAG_LENGTH = 128; private static final int IV_LENGTH = 16; public static final int KEY_LENGTH_128 = 128; public static final int KEY_LENGTH_192 = 192; public static final int KEY_LENGTH_256 = 256; /** * 缓存 Cipher 实例,提高高并发性能 * Cipher 不是线程安全的,每个线程使用自己的实例 */ private static final ThreadLocal ECB_ENCRYPT_CIPHER = ThreadLocal.withInitial(() -> { try { return Cipher.getInstance(TRANSFORMATION_ECB); } catch (Exception e) { throw new RuntimeException("初始化 ECB 加密 Cipher 失败", e); } }); private static final ThreadLocal ECB_DECRYPT_CIPHER = ThreadLocal.withInitial(() -> { try { return Cipher.getInstance(TRANSFORMATION_ECB); } catch (Exception e) { throw new RuntimeException("初始化 ECB 解密 Cipher 失败", e); } }); private static final ThreadLocal CBC_ENCRYPT_CIPHER = ThreadLocal.withInitial(() -> { try { return Cipher.getInstance(TRANSFORMATION_CBC); } catch (Exception e) { throw new RuntimeException("初始化 CBC 加密 Cipher 失败", e); } }); private static final ThreadLocal CBC_DECRYPT_CIPHER = ThreadLocal.withInitial(() -> { try { return Cipher.getInstance(TRANSFORMATION_CBC); } catch (Exception e) { throw new RuntimeException("初始化 CBC 解密 Cipher 失败", e); } }); private static final ThreadLocal GCM_ENCRYPT_CIPHER = ThreadLocal.withInitial(() -> { try { return Cipher.getInstance(TRANSFORMATION_GCM); } catch (Exception e) { throw new RuntimeException("初始化 GCM 加密 Cipher 失败", e); } }); private static final ThreadLocal GCM_DECRYPT_CIPHER = ThreadLocal.withInitial(() -> { try { return Cipher.getInstance(TRANSFORMATION_GCM); } catch (Exception e) { throw new RuntimeException("初始化 GCM 解密 Cipher 失败", e); } }); /** * 生成 AES 密钥(默认 128 位) * * @return Base64 编码的密钥 */ public static String generateKey() { return generateKey(KEY_LENGTH_128); } /** * 生成指定长度的 AES 密钥 * * @param keySize 密钥长度(128/192/256) * @return Base64 编码的密钥 */ public static String generateKey(int keySize) { try { KeyGenerator keyGenerator = KeyGenerator.getInstance(AES_ALGORITHM); keyGenerator.init(keySize, new SecureRandom()); SecretKey secretKey = keyGenerator.generateKey(); return Base64.getEncoder().encodeToString(secretKey.getEncoded()); } catch (Exception e) { throw new RuntimeException("生成密钥失败", e); } } /** * 从字符串生成 AES 密钥 * * @param password 密码字符串 * @param keySize 密钥长度(128/192/256) * @return Base64 编码的密钥 */ public static String generateKeyFromPassword(String password, int keySize) { try { byte[] passwordBytes = password.getBytes(StandardCharsets.UTF_8); byte[] keyBytes = new byte[keySize / 8]; System.arraycopy(passwordBytes, 0, keyBytes, 0, Math.min(passwordBytes.length, keyBytes.length)); SecretKeySpec keySpec = new SecretKeySpec(keyBytes, AES_ALGORITHM); return Base64.getEncoder().encodeToString(keySpec.getEncoded()); } catch (Exception e) { throw new RuntimeException("从密码生成密钥失败", e); } } /** * 生成初始化向量(IV) * * @return Base64 编码的 IV */ public static String generateIV() { try { byte[] iv = new byte[IV_LENGTH]; new SecureRandom().nextBytes(iv); return Base64.getEncoder().encodeToString(iv); } catch (Exception e) { throw new RuntimeException("生成 IV 失败", e); } } /** * ECB 模式加密 * * @param data 待加密数据 * @param key Base64 编码的密钥 * @return Base64 编码的密文 */ public static String encryptByECB(String data, String key) { try { byte[] keyBytes = Base64.getDecoder().decode(key); SecretKeySpec keySpec = new SecretKeySpec(keyBytes, AES_ALGORITHM); Cipher cipher = ECB_ENCRYPT_CIPHER.get(); cipher.init(Cipher.ENCRYPT_MODE, keySpec); byte[] encrypted = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8)); return Base64.getEncoder().encodeToString(encrypted); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("ECB 加密失败", e); } } /** * ECB 模式解密 * * @param data Base64 编码的密文 * @param key Base64 编码的密钥 * @return 明文 */ public static String decryptByECB(String data, String key) { try { byte[] keyBytes = Base64.getDecoder().decode(key); SecretKeySpec keySpec = new SecretKeySpec(keyBytes, AES_ALGORITHM); Cipher cipher = ECB_DECRYPT_CIPHER.get(); cipher.init(Cipher.DECRYPT_MODE, keySpec); byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(data)); return new String(decrypted, StandardCharsets.UTF_8); } catch (Exception e) { throw new RuntimeException("ECB 解密失败", e); } } /** * CBC 模式加密 * * @param data 待加密数据 * @param key Base64 编码的密钥 * @param iv Base64 编码的 IV * @return Base64 编码的密文 */ public static String encryptByCBC(String data, String key, String iv) { try { byte[] keyBytes = Base64.getDecoder().decode(key); byte[] ivBytes = Base64.getDecoder().decode(iv); SecretKeySpec keySpec = new SecretKeySpec(keyBytes, AES_ALGORITHM); IvParameterSpec ivSpec = new IvParameterSpec(ivBytes); Cipher cipher = CBC_ENCRYPT_CIPHER.get(); cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec); byte[] encrypted = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8)); return Base64.getEncoder().encodeToString(encrypted); } catch (Exception e) { throw new RuntimeException("CBC 加密失败", e); } } /** * CBC 模式解密 * * @param data Base64 编码的密文 * @param key Base64 编码的密钥 * @param iv Base64 编码的 IV * @return 明文 */ public static String decryptByCBC(String data, String key, String iv) { try { byte[] keyBytes = Base64.getDecoder().decode(key); byte[] ivBytes = Base64.getDecoder().decode(iv); SecretKeySpec keySpec = new SecretKeySpec(keyBytes, AES_ALGORITHM); IvParameterSpec ivSpec = new IvParameterSpec(ivBytes); Cipher cipher = CBC_DECRYPT_CIPHER.get(); cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec); byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(data)); return new String(decrypted, StandardCharsets.UTF_8); } catch (Exception e) { throw new RuntimeException("CBC 解密失败", e); } } /** * GCM 模式加密(推荐) * * @param data 待加密数据 * @param key Base64 编码的密钥 * @param iv Base64 编码的 IV * @return Base64 编码的密文 */ public static String encryptByGCM(String data, String key, String iv) { try { byte[] keyBytes = Base64.getDecoder().decode(key); byte[] ivBytes = Base64.getDecoder().decode(iv); SecretKeySpec keySpec = new SecretKeySpec(keyBytes, AES_ALGORITHM); GCMParameterSpec gcmSpec = new GCMParameterSpec(GCM_TAG_LENGTH, ivBytes); Cipher cipher = GCM_ENCRYPT_CIPHER.get(); cipher.init(Cipher.ENCRYPT_MODE, keySpec, gcmSpec); byte[] encrypted = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8)); return Base64.getEncoder().encodeToString(encrypted); } catch (Exception e) { throw new RuntimeException("GCM 加密失败", e); } } /** * GCM 模式解密(推荐) * * @param data Base64 编码的密文 * @param key Base64 编码的密钥 * @param iv Base64 编码的 IV * @return 明文 */ public static String decryptByGCM(String data, String key, String iv) { try { byte[] keyBytes = Base64.getDecoder().decode(key); byte[] ivBytes = Base64.getDecoder().decode(iv); SecretKeySpec keySpec = new SecretKeySpec(keyBytes, AES_ALGORITHM); GCMParameterSpec gcmSpec = new GCMParameterSpec(GCM_TAG_LENGTH, ivBytes); Cipher cipher = GCM_DECRYPT_CIPHER.get(); cipher.init(Cipher.DECRYPT_MODE, keySpec, gcmSpec); byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(data)); return new String(decrypted, StandardCharsets.UTF_8); } catch (Exception e) { throw new RuntimeException("GCM 解密失败", e); } } /** * 默认加密(使用 CBC 模式) * * @param data 待加密数据 * @param key Base64 编码的密钥 * @return Base64 编码的密文(包含 IV) */ public static String encrypt(String data, String key) { String iv = generateIV(); String encrypted = encryptByCBC(data, key, iv); return iv + ":" + encrypted; } /** * 默认解密(使用 CBC 模式) * * @param data Base64 编码的密文(格式:iv:encrypted) * @param key Base64 编码的密钥 * @return 明文 */ public static String decrypt(String data, String key) { try { String[] parts = data.split(":"); if (parts.length != 2) { throw new IllegalArgumentException("密文格式错误,应为 iv:encrypted"); } return decryptByCBC(parts[1], key, parts[0]); } catch (Exception e) { throw new RuntimeException("解密失败", e); } } /** * 获取密钥字节数组 * * @param key Base64 编码的密钥 * @return 密钥字节数组 */ public static byte[] getKeyBytes(String key) { return Base64.getDecoder().decode(key); } /** * 获取 IV 字节数组 * * @param iv Base64 编码的 IV * @return IV 字节数组 */ public static byte[] getIVBytes(String iv) { return Base64.getDecoder().decode(iv); } /** * 测试示例 */ public static void main(String[] args) { // 1. 生成密钥 String key = generateKey(KEY_LENGTH_256); System.out.println("密钥: " + key); System.out.println(); // 2. 测试 ECB 模式 String originalData = "Hello AES 加密测试!123456789"; System.out.println("原始数据: " + originalData); String ecbEncrypted = encryptByECB(originalData, key); System.out.println("ECB 加密: " + ecbEncrypted); String ecbDecrypted = decryptByECB(ecbEncrypted, key); System.out.println("ECB 解密: " + ecbDecrypted); System.out.println(); // 3. 测试 CBC 模式 String iv = generateIV(); System.out.println("IV: " + iv); String cbcEncrypted = encryptByCBC(originalData, key, iv); System.out.println("CBC 加密: " + cbcEncrypted); String cbcDecrypted = decryptByCBC(cbcEncrypted, key, iv); System.out.println("CBC 解密: " + cbcDecrypted); System.out.println(); // 4. 测试 GCM 模式(推荐) String gcmEncrypted = encryptByGCM(originalData, key, iv); System.out.println("GCM 加密: " + gcmEncrypted); String gcmDecrypted = decryptByGCM(gcmEncrypted, key, iv); System.out.println("GCM 解密: " + gcmDecrypted); System.out.println(); // 5. 测试默认加密(包含 IV) String encrypted = encrypt(originalData, key); System.out.println("默认加密(含IV): " + encrypted); String decrypted = decrypt(encrypted, key); System.out.println("默认解密: " + decrypted); System.out.println(); // 6. 从密码生成密钥 String passwordKey = generateKeyFromPassword("MySecretPassword123", KEY_LENGTH_256); System.out.println("从密码生成的密钥: " + passwordKey); String passEncrypted = encrypt(originalData, passwordKey); String passDecrypted = decrypt(passEncrypted, passwordKey); System.out.println("使用密码密钥解密: " + passDecrypted); } }