diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/encrypt/EncryptUtil.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/encrypt/EncryptUtil.java new file mode 100644 index 0000000..875b68e --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/encrypt/EncryptUtil.java @@ -0,0 +1,134 @@ +package com.ruoyi.common.utils.encrypt; + +import cn.hutool.json.JSON; +import cn.hutool.json.JSONUtil; +import com.ruoyi.common.utils.StringUtils; +import org.apache.commons.codec.binary.Base64; + +import javax.crypto.Cipher; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; + +public class EncryptUtil { + + private static final String ALGORITHM = "AES"; + private static final String TRANSFORMATION = "AES/CBC/PKCS5Padding"; + + public static void main(String[] args) { + String appId = "cloud-9793ee8a8c3d47b8871007ffc4128502"; + String appSecret = "Yi+NACK70UPg8rFvsnnfBUq1wcLD4nm6ilC4II/4C4k="; + String generatedIv = generateAppIV(appId); + String generatedKey = generateAppKey(appId, appSecret); + + String data = "n+Rq0Y+quYHa9uL+EpWbuw=="; + String str = decrypt(data, generatedIv, generatedKey); + System.err.println(str); + } + + + private static String generateAppIV(String appId) { + try { + MessageDigest md = MessageDigest.getInstance("MD5"); + byte[] hashBytes = md.digest(appId.getBytes("UTF-8")); + // 直接使用字节数组转换,确保精确的16字节 + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < 16; i++) { + String hex = Integer.toHexString(0xff & hashBytes[i]); + if (hex.length() == 1) { + sb.append('0'); + } + sb.append(hex); + } + return sb.toString().substring(0, 16); // 确保正好16个字符 + } catch (Exception e) { + throw new RuntimeException("IV生成失败", e); + } + } + + private static String generateAppKey(String appId, String appSecret) { + try { + String combinedKey = appId + appSecret; + MessageDigest md = MessageDigest.getInstance("SHA-256"); + byte[] hashBytes = md.digest(combinedKey.getBytes("UTF-8")); + // 取前16字节作为AES密钥 + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < 16; i++) { + sb.append(Integer.toHexString((hashBytes[i] & 0xFF) | 0x100).substring(1, 3)); + } + return sb.toString().substring(0, 16); // AES-128需要16字符密钥 + } catch (Exception e) { + throw new RuntimeException("密钥生成失败", e); + } + } + + public static String decrypt(String content, String iv, String key) {if(StringUtils.isEmpty(content)) {return "";} + iv = getIv( iv); + try { + byte[] decoded = Base64.decodeBase64(content); + byte[] decrypted = AES_CBC_Decrypt(decoded, iv, AES_normalizeKey(key)); + String result = new String(decrypted, StandardCharsets.UTF_8); + + // 清理可能的填充字符 + result = result.trim(); + if (result.endsWith("\0")) { + result = result.replaceAll("\\\\0+$", ""); + } + + // 处理JSON格式 + String cleanResult = result.replaceAll("\"", ""); + if (cleanResult.startsWith("{") && cleanResult.endsWith("}")) { + JSON parse = JSONUtil.parse(cleanResult); + return String.valueOf(parse); + } else { + return result; + } + } catch (Exception e) { + return ""; + } + } + + private static String getIv(String iv) { + return generateIV(iv); + } + + private static String generateIV(String iv) { + try { + MessageDigest md = MessageDigest.getInstance("MD5"); + byte[] hashBytes = md.digest(iv.getBytes("UTF-8")); + // 直接使用字节数组转换,确保精确的16字节 + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < 16; i++) { + String hex = Integer.toHexString(0xff & hashBytes[i]); + if (hex.length() == 1) { + sb.append('0'); + } + sb.append(hex); + } + return sb.toString().substring(0, 16); // 确保正好16个字符 + } catch (Exception e) { + throw new RuntimeException("IV生成失败", e); + } + } + + /** + * AES CBC 解密 + */ + private static byte[] AES_CBC_Decrypt(byte[] content, String iv, String key) throws Exception { + SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), ALGORITHM); + Cipher cipher = Cipher.getInstance(TRANSFORMATION); + IvParameterSpec ivSpec = new IvParameterSpec(iv.getBytes(StandardCharsets.UTF_8)); + cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec); + return cipher.doFinal(content); + } + + + /** + * 规范化密钥长度为16位(AES-128) + */ + private static String AES_normalizeKey(String key) { + return key; + } + +}