fix
This commit is contained in:
parent
cfce3f4242
commit
f80d75969d
|
|
@ -13,6 +13,7 @@ import javax.crypto.spec.SecretKeySpec;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.security.Security;
|
import java.security.Security;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
|
@ -102,4 +103,58 @@ public class EncryptionService {
|
||||||
throw new SecurityException("数据解密失败", e);
|
throw new SecurityException("数据解密失败", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public String deterministicDecryptAes(String ciphertext) {
|
||||||
|
try {
|
||||||
|
// 使用与加密相同的固定IV
|
||||||
|
byte[] fixedIv = new byte[GCM_IV_LENGTH];
|
||||||
|
Arrays.fill(fixedIv, (byte) 0x01);
|
||||||
|
|
||||||
|
// 初始化密钥
|
||||||
|
SecretKey secretKey = new SecretKeySpec(Base64.getDecoder().decode(systemKey), AES_KEY_ALGORITHM);
|
||||||
|
|
||||||
|
// 初始化解密器
|
||||||
|
Cipher cipher = Cipher.getInstance(AES_ALGORITHM);
|
||||||
|
GCMParameterSpec parameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, fixedIv);
|
||||||
|
cipher.init(Cipher.DECRYPT_MODE, secretKey, parameterSpec);
|
||||||
|
|
||||||
|
// 解码Base64密文(注意:这里不包含IV)
|
||||||
|
byte[] decoded = Base64.getDecoder().decode(ciphertext);
|
||||||
|
|
||||||
|
// 执行解密
|
||||||
|
byte[] plaintext = cipher.doFinal(decoded);
|
||||||
|
return new String(plaintext, StandardCharsets.UTF_8);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("确定性AES解密失败", e);
|
||||||
|
throw new SecurityException("数据解密失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 确定性AES加密(用于查询场景)
|
||||||
|
* 使用固定IV,确保相同明文总是生成相同密文
|
||||||
|
*/
|
||||||
|
public String deterministicEncryptAes(String plaintext) {
|
||||||
|
try {
|
||||||
|
// 使用固定IV(注意:在生产环境中,应考虑使用派生IV而不是固定IV)
|
||||||
|
byte[] fixedIv = new byte[GCM_IV_LENGTH];
|
||||||
|
// 可以使用字段名或其他确定性数据来派生IV
|
||||||
|
Arrays.fill(fixedIv, (byte) 0x01);
|
||||||
|
|
||||||
|
// 初始化密钥
|
||||||
|
SecretKey secretKey = new SecretKeySpec(Base64.getDecoder().decode(systemKey), AES_KEY_ALGORITHM);
|
||||||
|
|
||||||
|
// 初始化加密器
|
||||||
|
Cipher cipher = Cipher.getInstance(AES_ALGORITHM);
|
||||||
|
GCMParameterSpec parameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, fixedIv);
|
||||||
|
cipher.init(Cipher.ENCRYPT_MODE, secretKey, parameterSpec);
|
||||||
|
|
||||||
|
// 执行加密
|
||||||
|
byte[] ciphertext = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));
|
||||||
|
|
||||||
|
// 注意:这里不包含IV,因为IV是固定的
|
||||||
|
return Base64.getEncoder().encodeToString(ciphertext);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("确定性AES加密失败", e);
|
||||||
|
throw new SecurityException("数据加密失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -49,7 +49,7 @@ public class SensitiveDataConverter extends AbstractJsonTypeHandler<String> impl
|
||||||
public void setNonNullParameter(PreparedStatement preparedStatement, int i, String s, JdbcType jdbcType) throws SQLException {
|
public void setNonNullParameter(PreparedStatement preparedStatement, int i, String s, JdbcType jdbcType) throws SQLException {
|
||||||
if (s != null && !s.isEmpty() && !s.startsWith(Const.ENCRYPTED_PREFIX)) {
|
if (s != null && !s.isEmpty() && !s.startsWith(Const.ENCRYPTED_PREFIX)) {
|
||||||
// 加密后添加前缀标识
|
// 加密后添加前缀标识
|
||||||
s = Const.ENCRYPTED_PREFIX + getEncryptionService().encryptAes(s);
|
s = Const.ENCRYPTED_PREFIX + getEncryptionService().deterministicEncryptAes(s);
|
||||||
}
|
}
|
||||||
preparedStatement.setString(i, s);
|
preparedStatement.setString(i, s);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import com.kakarote.core.common.Const;
|
||||||
import com.kakarote.core.common.FieldEnum;
|
import com.kakarote.core.common.FieldEnum;
|
||||||
import com.kakarote.core.security.EncryptionService;
|
import com.kakarote.core.security.EncryptionService;
|
||||||
import com.kakarote.core.servlet.ApplicationContextHolder;
|
import com.kakarote.core.servlet.ApplicationContextHolder;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
@ -13,6 +14,7 @@ import java.util.*;
|
||||||
/**
|
/**
|
||||||
* Elasticsearch数据加密解密工具类
|
* Elasticsearch数据加密解密工具类
|
||||||
*/
|
*/
|
||||||
|
@Slf4j
|
||||||
public class EsDataEncryptUtil {
|
public class EsDataEncryptUtil {
|
||||||
|
|
||||||
private static EncryptionService encryptionService;
|
private static EncryptionService encryptionService;
|
||||||
|
|
@ -110,7 +112,7 @@ public class EsDataEncryptUtil {
|
||||||
String strValue = (String) value;
|
String strValue = (String) value;
|
||||||
// 已经加密的不再重复加密
|
// 已经加密的不再重复加密
|
||||||
if (!strValue.isEmpty() && !strValue.startsWith(Const.ENCRYPTED_PREFIX)) {
|
if (!strValue.isEmpty() && !strValue.startsWith(Const.ENCRYPTED_PREFIX)) {
|
||||||
return Const.ENCRYPTED_PREFIX + getEncryptionService().encryptAes(strValue);
|
return Const.ENCRYPTED_PREFIX + getEncryptionService().deterministicEncryptAes(strValue);
|
||||||
}
|
}
|
||||||
return strValue;
|
return strValue;
|
||||||
} else if (value instanceof Map) {
|
} else if (value instanceof Map) {
|
||||||
|
|
@ -132,34 +134,43 @@ public class EsDataEncryptUtil {
|
||||||
* 根据值类型进行解密
|
* 根据值类型进行解密
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private static Object decryptValue(String key,Object value) {
|
private static Object decryptValue(String key, Object value) {
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
|
||||||
|
|
||||||
if (value instanceof String) {
|
|
||||||
String strValue = (String) value;
|
|
||||||
// 对已加密的数据进行解密
|
|
||||||
if (strValue.startsWith(Const.ENCRYPTED_PREFIX)) {
|
|
||||||
String newValue = getEncryptionService().decryptAes(strValue.substring(Const.ENCRYPTED_PREFIX.length()));
|
|
||||||
return desensitization(key,newValue);
|
|
||||||
}
|
|
||||||
return strValue;
|
|
||||||
} else if (value instanceof Map) {
|
|
||||||
// 递归处理嵌套Map
|
|
||||||
return decryptMap((Map<String, Object>) value);
|
|
||||||
} else if (value instanceof List) {
|
|
||||||
// 递归处理List中的每个元素
|
|
||||||
List<Object> decryptedList = new ArrayList<>();
|
|
||||||
for (Object item : (List<Object>) value) {
|
|
||||||
decryptedList.add(decryptValue(key,item));
|
|
||||||
}
|
|
||||||
return decryptedList;
|
|
||||||
}
|
|
||||||
// 其他类型保持不变
|
|
||||||
return value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (value instanceof String) {
|
||||||
|
String strValue = (String) value;
|
||||||
|
// 对已加密的数据进行解密
|
||||||
|
if (strValue.startsWith(Const.ENCRYPTED_PREFIX)) {
|
||||||
|
String encryptedValue = strValue.substring(Const.ENCRYPTED_PREFIX.length());
|
||||||
|
// 尝试使用确定性解密(用于查询和存储中使用了deterministicEncryptAes的情况)
|
||||||
|
try {
|
||||||
|
String newValue = getEncryptionService().deterministicDecryptAes(encryptedValue);
|
||||||
|
return desensitization(key, newValue);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 如果确定性解密失败,尝试使用普通解密
|
||||||
|
log.debug("确定性解密失败,尝试普通解密", e);
|
||||||
|
String newValue = getEncryptionService().decryptAes(encryptedValue);
|
||||||
|
return desensitization(key, newValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return strValue;
|
||||||
|
} else if (value instanceof Map) {
|
||||||
|
// 递归处理嵌套Map
|
||||||
|
return decryptMap((Map<String, Object>) value);
|
||||||
|
} else if (value instanceof List) {
|
||||||
|
// 递归处理List中的每个元素
|
||||||
|
List<Object> decryptedList = new ArrayList<>();
|
||||||
|
for (Object item : (List<Object>) value) {
|
||||||
|
decryptedList.add(decryptValue(key, item));
|
||||||
|
}
|
||||||
|
return decryptedList;
|
||||||
|
}
|
||||||
|
// 其他类型保持不变
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
// 数据脱敏
|
// 数据脱敏
|
||||||
private static String desensitization(String key,String value){
|
private static String desensitization(String key,String value){
|
||||||
if ("mobile".equals(key)) {
|
if ("mobile".equals(key)) {
|
||||||
|
|
|
||||||
|
|
@ -255,7 +255,7 @@ public class ElasticUtil {
|
||||||
if (value instanceof String) {
|
if (value instanceof String) {
|
||||||
String strValue = (String) value;
|
String strValue = (String) value;
|
||||||
if (!strValue.isEmpty() && !strValue.startsWith(Const.ENCRYPTED_PREFIX)) {
|
if (!strValue.isEmpty() && !strValue.startsWith(Const.ENCRYPTED_PREFIX)) {
|
||||||
map.put(fieldName, Const.ENCRYPTED_PREFIX + ApplicationContextHolder.getBean(EncryptionService.class).encryptAes(strValue));
|
map.put(fieldName, Const.ENCRYPTED_PREFIX + ApplicationContextHolder.getBean(EncryptionService.class).deterministicEncryptAes(strValue));
|
||||||
} else {
|
} else {
|
||||||
map.put(fieldName, value);
|
map.put(fieldName, value);
|
||||||
}
|
}
|
||||||
|
|
@ -303,10 +303,23 @@ public class ElasticUtil {
|
||||||
if (search.getValues().size() == 0 && !Arrays.asList(5, 6).contains(search.getSearchEnum().getType())) {
|
if (search.getValues().size() == 0 && !Arrays.asList(5, 6).contains(search.getSearchEnum().getType())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 对需要加密的字段值进行加密处理
|
||||||
|
List<String> encryptedValues = new ArrayList<>();
|
||||||
|
for (String value : search.getValues()) {
|
||||||
|
if (!value.isEmpty() && !value.startsWith(Const.ENCRYPTED_PREFIX)) {
|
||||||
|
// 添加加密前缀并进行AES加密
|
||||||
|
encryptedValues.add(Const.ENCRYPTED_PREFIX + ApplicationContextHolder.getBean(EncryptionService.class).deterministicEncryptAes(value));
|
||||||
|
} else {
|
||||||
|
encryptedValues.add(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
search.setValues(encryptedValues);
|
||||||
switch (search.getSearchEnum()) {
|
switch (search.getSearchEnum()) {
|
||||||
case IS:
|
case IS:
|
||||||
queryBuilder.filter(QueryBuilders.termsQuery(search.getName(), search.getValues()));
|
queryBuilder.filter(QueryBuilders.termsQuery(search.getName(), search.getValues()));
|
||||||
break;
|
break;
|
||||||
|
// 其他搜索条件处理保持不变
|
||||||
case IS_NOT:
|
case IS_NOT:
|
||||||
queryBuilder.mustNot(QueryBuilders.termsQuery(search.getName(), search.getValues()));
|
queryBuilder.mustNot(QueryBuilders.termsQuery(search.getName(), search.getValues()));
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,8 @@ public class CrmQueryGsdjxxDTO implements Serializable {
|
||||||
// 登记序号
|
// 登记序号
|
||||||
private String yf;
|
private String yf;
|
||||||
|
|
||||||
|
private String rq;
|
||||||
|
|
||||||
// 评价年度
|
// 评价年度
|
||||||
private String xzqhDm;
|
private String xzqhDm;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue