package com.ruoyi.common.utils; import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import java.nio.charset.StandardCharsets; /** * AES 加解密工具类 * 算法:AES/CBC/PKCS5Padding(等效 PKCS7,128 位数据块) * 输出:HEX 大写字符串 * 字符集:UTF-8 */ public class AesUtils { /** 算法/模式/填充 */ private static final String ALGORITHM = "AES/CBC/PKCS5Padding"; /** 默认 Key(HEX,32字节→256位密钥) */ private static final String DEFAULT_KEY = "0F471C56362408AF8DB929C38EDFD23C"; /** 默认 IV(HEX,16字节→128位偏移量) */ private static final String DEFAULT_IV = "11BEE6E35B881A33CF1649607295D1A7"; private AesUtils() { } // ------------------------------------------------------------------------- // 公共 API // ------------------------------------------------------------------------- /** * 使用默认 Key / IV 加密 * * @param plainText 明文 * @return HEX 大写密文 */ public static String encrypt(String plainText) { return encrypt(plainText, DEFAULT_KEY, DEFAULT_IV); } /** * 使用默认 Key / IV 解密 * * @param hexCipherText HEX 大写密文 * @return 明文 */ public static String decrypt(String hexCipherText) { return decrypt(hexCipherText, DEFAULT_KEY, DEFAULT_IV); } /** * AES-CBC 加密 * * @param plainText 明文 * @param hexKey HEX 格式的密钥(16/24/32字节对应128/192/256位) * @param hexIv HEX 格式的偏移量(16字节) * @return HEX 大写密文 */ public static String encrypt(String plainText, String hexKey, String hexIv) { try { byte[] keyBytes = hexToBytes(hexKey); byte[] ivBytes = hexToBytes(hexIv); SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "AES"); IvParameterSpec ivSpec = new IvParameterSpec(ivBytes); Cipher cipher = Cipher.getInstance(ALGORITHM); cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec); byte[] encrypted = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8)); return bytesToHex(encrypted).toUpperCase(); } catch (Exception e) { throw new RuntimeException("AES 加密失败", e); } } /** * AES-CBC 解密 * * @param hexCipherText HEX 大写密文 * @param hexKey HEX 格式的密钥 * @param hexIv HEX 格式的偏移量 * @return 明文 */ public static String decrypt(String hexCipherText, String hexKey, String hexIv) { try { byte[] keyBytes = hexToBytes(hexKey); byte[] ivBytes = hexToBytes(hexIv); byte[] cipherBytes = hexToBytes(hexCipherText); SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "AES"); IvParameterSpec ivSpec = new IvParameterSpec(ivBytes); Cipher cipher = Cipher.getInstance(ALGORITHM); cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec); byte[] decrypted = cipher.doFinal(cipherBytes); return new String(decrypted, StandardCharsets.UTF_8); } catch (Exception e) { throw new RuntimeException("AES 解密失败", e); } } // ------------------------------------------------------------------------- // 私有辅助方法 // ------------------------------------------------------------------------- /** * HEX 字符串转字节数组(大小写均可) */ private static byte[] hexToBytes(String hex) { if (hex == null || hex.length() % 2 != 0) { throw new IllegalArgumentException("非法 HEX 字符串:" + hex); } int len = hex.length(); byte[] data = new byte[len / 2]; for (int i = 0; i < len; i += 2) { data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4) + Character.digit(hex.charAt(i + 1), 16)); } return data; } /** * 字节数组转 HEX 字符串(小写,调用方统一转大写) */ private static String bytesToHex(byte[] bytes) { StringBuilder sb = new StringBuilder(bytes.length * 2); for (byte b : bytes) { sb.append(String.format("%02x", b)); } return sb.toString(); } }