init
This commit is contained in:
30
common/common-decrypt/pom.xml
Normal file
30
common/common-decrypt/pom.xml
Normal file
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>cn.fateverse</groupId>
|
||||
<artifactId>common</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>common-decrypt</artifactId>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.fateverse</groupId>
|
||||
<artifactId>common-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-aop</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,36 @@
|
||||
package cn.fateverse.common.decrypt;
|
||||
|
||||
import cn.fateverse.common.decrypt.aspect.EncryptAspect;
|
||||
import cn.fateverse.common.decrypt.config.EncryptProperties;
|
||||
import cn.fateverse.common.decrypt.service.DefaultEncryptService;
|
||||
import cn.fateverse.common.decrypt.service.EncryptService;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* @author Clay
|
||||
* @date 2023-07-04
|
||||
*/
|
||||
@EnableConfigurationProperties({EncryptProperties.class})
|
||||
public class DecryptConfiguration {
|
||||
|
||||
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean({EncryptService.class})
|
||||
public EncryptService encryptService(EncryptProperties encryptProperties) {
|
||||
return new DefaultEncryptService(encryptProperties);
|
||||
}
|
||||
|
||||
|
||||
@Bean
|
||||
@ConditionalOnBean(EncryptService.class)
|
||||
public EncryptAspect encryptAspect(EncryptService encryptService) {
|
||||
return new EncryptAspect(encryptService);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package cn.fateverse.common.decrypt.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* @author Clay
|
||||
* @date 2023-07-03
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Encrypt {
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package cn.fateverse.common.decrypt.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* 定义注解 标记需要加密的字段
|
||||
*/
|
||||
@Target({ElementType.PARAMETER, ElementType.METHOD, ElementType.FIELD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface EncryptField {
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
package cn.fateverse.common.decrypt.aspect;
|
||||
|
||||
import cn.fateverse.common.core.exception.CustomException;
|
||||
import cn.fateverse.common.core.result.Result;
|
||||
import cn.fateverse.common.decrypt.annotation.EncryptField;
|
||||
import cn.fateverse.common.decrypt.service.EncryptService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Parameter;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@Aspect
|
||||
public class EncryptAspect {
|
||||
|
||||
protected static String BASE_PACKAGE;
|
||||
|
||||
|
||||
static {
|
||||
String typeName = EncryptAspect.class.getTypeName();
|
||||
int fastIndex = typeName.indexOf(".");
|
||||
BASE_PACKAGE = typeName.substring(0, typeName.indexOf(".", fastIndex + 1));
|
||||
}
|
||||
|
||||
private final EncryptService encryptService;
|
||||
|
||||
public EncryptAspect(EncryptService encryptService) {
|
||||
this.encryptService = encryptService;
|
||||
}
|
||||
|
||||
|
||||
@Around("@annotation(cn.fateverse.common.decrypt.annotation.Encrypt)")
|
||||
public Object decryptField(ProceedingJoinPoint point) throws Throwable {
|
||||
MethodSignature signature = (MethodSignature) point.getSignature();
|
||||
//获取请求参数
|
||||
Object[] args = point.getArgs();
|
||||
//获取方法
|
||||
Method method = signature.getMethod();
|
||||
//获取方法参数 Parameter对象集 参数修饰符、参数名、注解及注解类型
|
||||
Parameter[] parameters = method.getParameters();
|
||||
for (int i = 0; i < parameters.length; i++) {
|
||||
Parameter parameter = parameters[i];
|
||||
//获取参数注解
|
||||
EncryptField encryptField = parameter.getAnnotation(EncryptField.class);
|
||||
Object arg = args[i];
|
||||
if (null != encryptField) {
|
||||
if (arg instanceof String) {
|
||||
String decrypt = encryptService.decrypt((String) arg);
|
||||
args[i] = decrypt;
|
||||
} else if (arg instanceof List) {
|
||||
try {
|
||||
List<String> list = (List<String>) arg;
|
||||
for (int j = 0; j < list.size(); j++) {
|
||||
String ciphertext = list.get(j);
|
||||
String decrypt = encryptService.decrypt(ciphertext);
|
||||
list.set(j, decrypt);
|
||||
}
|
||||
args[i] = list;
|
||||
} catch (Exception e) {
|
||||
throw new CustomException("接受参数类型错误,请使用String类型的泛型参数");
|
||||
}
|
||||
}
|
||||
} else if (parameter.getType().getName().startsWith(BASE_PACKAGE)) { //返回一个类对象,该类对象标识此参数对象表示的参数的声明类型
|
||||
decrypt(arg);
|
||||
}
|
||||
}
|
||||
//正常执行业务,最后返回的返回值为Result
|
||||
Object proceed = point.proceed(args);
|
||||
if (proceed instanceof Result) {
|
||||
Result<Object> result = (Result<Object>) proceed;
|
||||
Object data = result.getData();
|
||||
if (null != data) {
|
||||
try {
|
||||
encrypt(data);
|
||||
} catch (Exception e) {
|
||||
log.error("加密异常", e);
|
||||
return Result.error("加密异常!");
|
||||
}
|
||||
}
|
||||
result.setData(data);
|
||||
} else {
|
||||
try {
|
||||
encrypt(proceed);
|
||||
} catch (Exception e) {
|
||||
log.error("加密异常", e);
|
||||
return Result.error("加密异常!");
|
||||
}
|
||||
}
|
||||
return proceed;
|
||||
}
|
||||
|
||||
|
||||
private void encrypt(Object data) throws Exception {
|
||||
if (data == null) {
|
||||
return;
|
||||
}
|
||||
Class<?> argClass = data.getClass();
|
||||
if (argClass.getTypeName().startsWith(BASE_PACKAGE)) {
|
||||
Field[] fields = argClass.getDeclaredFields();
|
||||
for (Field field : fields) {
|
||||
EncryptField encryptField = field.getAnnotation(EncryptField.class);
|
||||
field.setAccessible(true);
|
||||
Object value = ReflectionUtils.getField(field, data);
|
||||
if (null == value) {
|
||||
continue;
|
||||
}
|
||||
if (null != encryptField && value instanceof String) {
|
||||
String decrypt = encryptService.encrypt((String) value);
|
||||
ReflectionUtils.setField(field, data, decrypt);
|
||||
} else if (field.getType().getName().startsWith(BASE_PACKAGE)) {
|
||||
encrypt(value);
|
||||
} else if (value instanceof Collection) {
|
||||
Collection<Object> collection = (Collection<Object>) value;
|
||||
for (Object item : collection) {
|
||||
encrypt(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (data instanceof Collection) {
|
||||
Collection<Object> collection = (Collection<Object>) data;
|
||||
for (Object item : collection) {
|
||||
encrypt(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void decrypt(Object arg) throws Exception {
|
||||
Class<?> argClass = arg.getClass();
|
||||
Field[] fields = argClass.getDeclaredFields();
|
||||
for (Field field : fields) {
|
||||
EncryptField encryptField = field.getAnnotation(EncryptField.class);
|
||||
field.setAccessible(true);
|
||||
Object value = ReflectionUtils.getField(field, arg);
|
||||
if (null == value) {
|
||||
continue;
|
||||
}
|
||||
if (null != encryptField && value instanceof String) {
|
||||
String decrypt = encryptService.decrypt((String) value);
|
||||
ReflectionUtils.setField(field, arg, decrypt);
|
||||
} else if (field.getType().getName().startsWith(BASE_PACKAGE)) {
|
||||
decrypt(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package cn.fateverse.common.decrypt.config;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* @author Clay
|
||||
* @date 2023-07-04
|
||||
*/
|
||||
@ConfigurationProperties(prefix = "encrypt")
|
||||
public class EncryptProperties {
|
||||
|
||||
private String secretKey = "1234567890abcdef";
|
||||
|
||||
public String getSecretKey() {
|
||||
return secretKey;
|
||||
}
|
||||
|
||||
public void setSecretKey(String secretKey) {
|
||||
this.secretKey = secretKey;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package cn.fateverse.common.decrypt.service;
|
||||
|
||||
import cn.fateverse.common.core.exception.CustomException;
|
||||
import cn.fateverse.common.decrypt.config.EncryptProperties;
|
||||
import cn.fateverse.common.decrypt.utils.SM4Util;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* @author Clay
|
||||
* @date 2023-08-07
|
||||
*/
|
||||
|
||||
public class DefaultEncryptService implements EncryptService {
|
||||
|
||||
private final EncryptProperties properties;
|
||||
|
||||
public DefaultEncryptService(EncryptProperties properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String encrypt(String plainText) {
|
||||
try {
|
||||
return SM4Util.encrypt(plainText, properties.getSecretKey());
|
||||
} catch (Exception e) {
|
||||
throw new CustomException("加密失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String decrypt(String cipherText) {
|
||||
try {
|
||||
return SM4Util.decrypt(cipherText, properties.getSecretKey());
|
||||
} catch (Exception e) {
|
||||
throw new CustomException("解密失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package cn.fateverse.common.decrypt.service;
|
||||
|
||||
/**
|
||||
* @author Clay
|
||||
* @date 2024/2/19 16:19
|
||||
*/
|
||||
public interface EncryptService {
|
||||
|
||||
/**
|
||||
* 加密方法
|
||||
*
|
||||
* @param plainText 需要加密的文档
|
||||
* @return 加密之后的数据
|
||||
*/
|
||||
String encrypt(String plainText);
|
||||
|
||||
/**
|
||||
* 解密方法
|
||||
*
|
||||
* @param cipherText 需要解密的文档
|
||||
* @return 解密之后的文档
|
||||
*/
|
||||
String decrypt(String cipherText);
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
package cn.fateverse.common.decrypt.utils;
|
||||
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
import org.bouncycastle.util.encoders.Hex;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.security.Security;
|
||||
|
||||
public class SM4Util {
|
||||
|
||||
private static final String ALGORITHM_NAME = "SM4";
|
||||
private static final String ALGORITHM_NAME_ECB_PADDING = "SM4/ECB/PKCS7Padding";
|
||||
private static final String ALGORITHM_NAME_CBC_PADDING = "SM4/CBC/PKCS7Padding";
|
||||
private static final String CHARSET_NAME = "UTF-8";
|
||||
private static final String IV_PARAMETER = "0000000000000000";
|
||||
|
||||
static {
|
||||
Security.addProvider(new BouncyCastleProvider());
|
||||
}
|
||||
|
||||
/**
|
||||
* SM4 加密
|
||||
*
|
||||
* @param plainText 明文
|
||||
* @param secretKey 密钥
|
||||
* @return 密文
|
||||
* @throws Exception 异常
|
||||
*/
|
||||
public static String encrypt(String plainText, String secretKey) throws Exception {
|
||||
byte[] keyBytes = secretKey.getBytes(CHARSET_NAME);
|
||||
byte[] plainBytes = plainText.getBytes(CHARSET_NAME);
|
||||
byte[] cipherBytes = encrypt_ECB_Padding(keyBytes, plainBytes);
|
||||
return new String(Hex.encode(cipherBytes));
|
||||
}
|
||||
|
||||
/**
|
||||
* SM4 解密
|
||||
*
|
||||
* @param cipherText 密文
|
||||
* @param secretKey 密钥
|
||||
* @return 明文
|
||||
* @throws Exception 异常
|
||||
*/
|
||||
public static String decrypt(String cipherText, String secretKey) throws Exception {
|
||||
byte[] keyBytes = secretKey.getBytes(CHARSET_NAME);
|
||||
byte[] cipherBytes = Hex.decode(cipherText);
|
||||
byte[] plainBytes = decrypt_ECB_Padding(keyBytes, cipherBytes);
|
||||
return new String(plainBytes, CHARSET_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* ECB 模式加密
|
||||
*
|
||||
* @param keyBytes 密钥
|
||||
* @param plainBytes 明文
|
||||
* @return 密文
|
||||
* @throws Exception 异常
|
||||
*/
|
||||
private static byte[] encrypt_ECB_Padding(byte[] keyBytes, byte[] plainBytes) throws Exception {
|
||||
Cipher cipher = Cipher.getInstance(ALGORITHM_NAME_ECB_PADDING, BouncyCastleProvider.PROVIDER_NAME);
|
||||
SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, ALGORITHM_NAME);
|
||||
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
|
||||
return cipher.doFinal(plainBytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* ECB 模式解密
|
||||
*
|
||||
* @param keyBytes 密钥
|
||||
* @param cipherBytes 密文
|
||||
* @return 明文
|
||||
* @throws Exception 异常
|
||||
*/
|
||||
private static byte[] decrypt_ECB_Padding(byte[] keyBytes, byte[] cipherBytes) throws Exception {
|
||||
Cipher cipher = Cipher.getInstance(ALGORITHM_NAME_ECB_PADDING, BouncyCastleProvider.PROVIDER_NAME);
|
||||
SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, ALGORITHM_NAME);
|
||||
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
|
||||
return cipher.doFinal(cipherBytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* CBC 模式加密
|
||||
*
|
||||
* @param keyBytes 密钥
|
||||
* @param plainBytes 明文
|
||||
* @param ivBytes 向量
|
||||
* @return 密文
|
||||
* @throws Exception 异常
|
||||
*/
|
||||
private static byte[] encrypt_CBC_Padding(byte[] keyBytes, byte[] plainBytes, byte[] ivBytes) throws Exception {
|
||||
Cipher cipher = Cipher.getInstance(ALGORITHM_NAME_CBC_PADDING, BouncyCastleProvider.PROVIDER_NAME);
|
||||
SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, ALGORITHM_NAME);
|
||||
IvParameterSpec ivParameterSpec = new IvParameterSpec(ivBytes);
|
||||
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
|
||||
return cipher.doFinal(plainBytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* CBC 模式解密
|
||||
*
|
||||
* @param keyBytes 密钥
|
||||
* @param cipherBytes 密文
|
||||
* @param ivBytes 向量
|
||||
* @return 明文
|
||||
* @throws Exception 异常
|
||||
*/
|
||||
private static byte[] decrypt_CBC_Padding(byte[] keyBytes, byte[] cipherBytes, byte[] ivBytes) throws Exception {
|
||||
Cipher cipher = Cipher.getInstance(ALGORITHM_NAME_CBC_PADDING, BouncyCastleProvider.PROVIDER_NAME);
|
||||
SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, ALGORITHM_NAME); IvParameterSpec ivParameterSpec = new IvParameterSpec(ivBytes);
|
||||
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec); return cipher.doFinal(cipherBytes);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
cn.fateverse.common.decrypt.DecryptConfiguration
|
||||
Reference in New Issue
Block a user