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();
|
}
|
}
|