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.security.Security;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Arrays;
|
||||
import java.util.Base64;
|
||||
|
||||
@Slf4j
|
||||
|
|
@ -102,4 +103,58 @@ public class EncryptionService {
|
|||
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 {
|
||||
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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import com.kakarote.core.common.Const;
|
|||
import com.kakarote.core.common.FieldEnum;
|
||||
import com.kakarote.core.security.EncryptionService;
|
||||
import com.kakarote.core.servlet.ApplicationContextHolder;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.*;
|
||||
|
|
@ -13,6 +14,7 @@ import java.util.*;
|
|||
/**
|
||||
* Elasticsearch数据加密解密工具类
|
||||
*/
|
||||
@Slf4j
|
||||
public class EsDataEncryptUtil {
|
||||
|
||||
private static EncryptionService encryptionService;
|
||||
|
|
@ -110,7 +112,7 @@ public class EsDataEncryptUtil {
|
|||
String strValue = (String) value;
|
||||
// 已经加密的不再重复加密
|
||||
if (!strValue.isEmpty() && !strValue.startsWith(Const.ENCRYPTED_PREFIX)) {
|
||||
return Const.ENCRYPTED_PREFIX + getEncryptionService().encryptAes(strValue);
|
||||
return Const.ENCRYPTED_PREFIX + getEncryptionService().deterministicEncryptAes(strValue);
|
||||
}
|
||||
return strValue;
|
||||
} else if (value instanceof Map) {
|
||||
|
|
@ -132,7 +134,7 @@ public class EsDataEncryptUtil {
|
|||
* 根据值类型进行解密
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private static Object decryptValue(String key,Object value) {
|
||||
private static Object decryptValue(String key, Object value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
|
|
@ -141,8 +143,17 @@ public class EsDataEncryptUtil {
|
|||
String strValue = (String) value;
|
||||
// 对已加密的数据进行解密
|
||||
if (strValue.startsWith(Const.ENCRYPTED_PREFIX)) {
|
||||
String newValue = getEncryptionService().decryptAes(strValue.substring(Const.ENCRYPTED_PREFIX.length()));
|
||||
return desensitization(key,newValue);
|
||||
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) {
|
||||
|
|
@ -152,13 +163,13 @@ public class EsDataEncryptUtil {
|
|||
// 递归处理List中的每个元素
|
||||
List<Object> decryptedList = new ArrayList<>();
|
||||
for (Object item : (List<Object>) value) {
|
||||
decryptedList.add(decryptValue(key,item));
|
||||
decryptedList.add(decryptValue(key, item));
|
||||
}
|
||||
return decryptedList;
|
||||
}
|
||||
// 其他类型保持不变
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
// 数据脱敏
|
||||
private static String desensitization(String key,String value){
|
||||
|
|
|
|||
|
|
@ -255,7 +255,7 @@ public class ElasticUtil {
|
|||
if (value instanceof String) {
|
||||
String strValue = (String) value;
|
||||
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 {
|
||||
map.put(fieldName, value);
|
||||
}
|
||||
|
|
@ -303,10 +303,23 @@ public class ElasticUtil {
|
|||
if (search.getValues().size() == 0 && !Arrays.asList(5, 6).contains(search.getSearchEnum().getType())) {
|
||||
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()) {
|
||||
case IS:
|
||||
queryBuilder.filter(QueryBuilders.termsQuery(search.getName(), search.getValues()));
|
||||
break;
|
||||
// 其他搜索条件处理保持不变
|
||||
case IS_NOT:
|
||||
queryBuilder.mustNot(QueryBuilders.termsQuery(search.getName(), search.getValues()));
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@ public class CrmQueryGsdjxxDTO implements Serializable {
|
|||
// 登记序号
|
||||
private String yf;
|
||||
|
||||
private String rq;
|
||||
|
||||
// 评价年度
|
||||
private String xzqhDm;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue