33 changed files with 438 additions and 827 deletions
@ -1,78 +0,0 @@ |
|||
package com.zdxt.enforcementcode.domain.bo; |
|||
|
|||
import com.zdxt.enforcementcode.domain.bean.CryptoIntegrityData; |
|||
import org.dromara.common.mybatis.core.domain.BaseEntity; |
|||
import org.dromara.common.core.validate.AddGroup; |
|||
import org.dromara.common.core.validate.EditGroup; |
|||
import io.github.linpeilie.annotations.AutoMapper; |
|||
import lombok.Data; |
|||
import lombok.EqualsAndHashCode; |
|||
import jakarta.validation.constraints.*; |
|||
import java.util.Date; |
|||
|
|||
/** |
|||
* 数据完整性校验业务对象 crypto_integrity_data |
|||
* |
|||
* @author vincent |
|||
* @date 2026-09-28 |
|||
*/ |
|||
@Data |
|||
@EqualsAndHashCode(callSuper = true) |
|||
@AutoMapper(target = CryptoIntegrityData.class, reverseConvertGenerate = false) |
|||
public class CryptoIntegrityDataBo extends BaseEntity { |
|||
|
|||
/** |
|||
* 主键ID |
|||
*/ |
|||
@NotNull(message = "主键ID不能为空", groups = { EditGroup.class }) |
|||
private Long id; |
|||
|
|||
/** |
|||
* 业务表名,如 sys_user |
|||
*/ |
|||
@NotBlank(message = "业务表名不能为空", groups = { AddGroup.class, EditGroup.class }) |
|||
private String tableName; |
|||
|
|||
/** |
|||
* 业务记录主键,字符串兼容数字/UUID |
|||
*/ |
|||
@NotBlank(message = "业务记录主键不能为空", groups = { AddGroup.class, EditGroup.class }) |
|||
private String bizId; |
|||
|
|||
/** |
|||
* 参与完整性摘要的字段列表,逗号分隔:username,id_card,phone |
|||
*/ |
|||
@NotBlank(message = "参与完整性摘要的字段列表不能为空", groups = { AddGroup.class, EditGroup.class }) |
|||
private String fieldList; |
|||
|
|||
/** |
|||
* 业务字段拼接明文的SM3摘要值,用于完整性校验 |
|||
*/ |
|||
@NotBlank(message = "SM3摘要值不能为空", groups = { AddGroup.class, EditGroup.class }) |
|||
private String sm3Hash; |
|||
|
|||
/** |
|||
* 完整性哈希算法:SM3 |
|||
*/ |
|||
private String hashAlg; |
|||
|
|||
/** |
|||
* 摘要生成时间 |
|||
*/ |
|||
private Date generateTime; |
|||
|
|||
/** |
|||
* 最近一次完整性校验时间 |
|||
*/ |
|||
private Date lastVerifyTime; |
|||
|
|||
/** |
|||
* 校验结果:0未校验 1校验通过 2校验失败(篡改) |
|||
*/ |
|||
private Integer verifyResult; |
|||
|
|||
/** |
|||
* 逻辑删除 |
|||
*/ |
|||
private Integer isDeleted; |
|||
} |
|||
@ -1,83 +0,0 @@ |
|||
package com.zdxt.enforcementcode.domain.bo; |
|||
|
|||
import com.zdxt.enforcementcode.domain.bean.CryptoOperationAudit; |
|||
import org.dromara.common.mybatis.core.domain.BaseEntity; |
|||
import org.dromara.common.core.validate.AddGroup; |
|||
import org.dromara.common.core.validate.EditGroup; |
|||
import io.github.linpeilie.annotations.AutoMapper; |
|||
import lombok.Data; |
|||
import lombok.EqualsAndHashCode; |
|||
import jakarta.validation.constraints.*; |
|||
import java.util.Date; |
|||
|
|||
/** |
|||
* 密评敏感字段操作审计业务对象 crypto_operation_audit |
|||
* |
|||
* @author vincent |
|||
* @date 2026-09-28 |
|||
*/ |
|||
@Data |
|||
@EqualsAndHashCode(callSuper = true) |
|||
@AutoMapper(target = CryptoOperationAudit.class, reverseConvertGenerate = false) |
|||
public class CryptoOperationAuditBo extends BaseEntity { |
|||
|
|||
/** |
|||
* 主键ID |
|||
*/ |
|||
@NotNull(message = "主键ID不能为空", groups = { EditGroup.class }) |
|||
private Long id; |
|||
|
|||
/** |
|||
* 关联 crypto_sensitive_data 主键ID |
|||
*/ |
|||
private Long sensitiveDataId; |
|||
|
|||
/** |
|||
* 业务表名 |
|||
*/ |
|||
@NotBlank(message = "业务表名不能为空", groups = { AddGroup.class, EditGroup.class }) |
|||
private String tableName; |
|||
|
|||
/** |
|||
* 业务记录主键 |
|||
*/ |
|||
@NotBlank(message = "业务记录主键不能为空", groups = { AddGroup.class, EditGroup.class }) |
|||
private String bizId; |
|||
|
|||
/** |
|||
* 敏感字段编码 |
|||
*/ |
|||
@NotBlank(message = "敏感字段编码不能为空", groups = { AddGroup.class, EditGroup.class }) |
|||
private String fieldCode; |
|||
|
|||
/** |
|||
* 操作类型:1新增密文 2解密查看 3修改密文 4密钥轮换 |
|||
*/ |
|||
@NotNull(message = "操作类型不能为空", groups = { AddGroup.class, EditGroup.class }) |
|||
private Integer operateType; |
|||
|
|||
/** |
|||
* 操作人ID(系统用户ID) |
|||
*/ |
|||
private Long operatorId; |
|||
|
|||
/** |
|||
* 操作客户端IP地址 |
|||
*/ |
|||
private String operatorIp; |
|||
|
|||
/** |
|||
* 操作发生时间 |
|||
*/ |
|||
private Date operateTime; |
|||
|
|||
/** |
|||
* 操作备注信息 |
|||
*/ |
|||
private String remark; |
|||
|
|||
/** |
|||
* 逻辑删除 |
|||
*/ |
|||
private Integer isDeleted; |
|||
} |
|||
@ -1,92 +0,0 @@ |
|||
package com.zdxt.enforcementcode.domain.bo; |
|||
|
|||
import com.zdxt.enforcementcode.domain.bean.CryptoSensitiveData; |
|||
import org.dromara.common.mybatis.core.domain.BaseEntity; |
|||
import org.dromara.common.core.validate.AddGroup; |
|||
import org.dromara.common.core.validate.EditGroup; |
|||
import io.github.linpeilie.annotations.AutoMapper; |
|||
import lombok.Data; |
|||
import lombok.EqualsAndHashCode; |
|||
import jakarta.validation.constraints.*; |
|||
|
|||
/** |
|||
* 密评敏感字段密文存储业务对象 crypto_sensitive_data |
|||
* |
|||
* @author vincent |
|||
* @date 2026-09-28 |
|||
*/ |
|||
@Data |
|||
@EqualsAndHashCode(callSuper = true) |
|||
@AutoMapper(target = CryptoSensitiveData.class, reverseConvertGenerate = false) |
|||
public class CryptoSensitiveDataBo extends BaseEntity { |
|||
|
|||
/** |
|||
* 主键ID |
|||
*/ |
|||
@NotNull(message = "主键ID不能为空", groups = { EditGroup.class }) |
|||
private Long id; |
|||
|
|||
/** |
|||
* 业务表名,如 sys_user |
|||
*/ |
|||
@NotBlank(message = "业务表名不能为空", groups = { AddGroup.class, EditGroup.class }) |
|||
private String tableName; |
|||
|
|||
/** |
|||
* 业务表主键ID,字符串兼容数字/UUID主键 |
|||
*/ |
|||
@NotBlank(message = "业务表主键ID不能为空", groups = { AddGroup.class, EditGroup.class }) |
|||
private String bizId; |
|||
|
|||
/** |
|||
* 业务字段编码,username/id_card/phone/password |
|||
*/ |
|||
@NotBlank(message = "业务字段编码不能为空", groups = { AddGroup.class, EditGroup.class }) |
|||
private String fieldCode; |
|||
|
|||
/** |
|||
* 字段原始值 |
|||
*/ |
|||
private String fieldValue; |
|||
|
|||
/** |
|||
* SM4-CBC密文Base64;password单向哈希场景此字段为空 |
|||
*/ |
|||
private String cipherText; |
|||
|
|||
/** |
|||
* SM4-CBC初始化向量,16字节随机值Base64;password此字段为空 |
|||
*/ |
|||
private String fieldIv; |
|||
|
|||
/** |
|||
* 明文SM3哈希,仅用于等值查询,不可逆 |
|||
*/ |
|||
private String plainHash; |
|||
|
|||
/** |
|||
* 哈希盐值,仅password单向哈希字段使用 |
|||
*/ |
|||
private String fieldSalt; |
|||
|
|||
/** |
|||
* 加密算法:SM4-CBC / SM3 |
|||
*/ |
|||
private String encryptAlg; |
|||
|
|||
/** |
|||
* 密钥版本号,用于密钥轮换,密评必查 |
|||
*/ |
|||
@NotBlank(message = "密钥版本号不能为空", groups = { AddGroup.class, EditGroup.class }) |
|||
private String keyVersion; |
|||
|
|||
/** |
|||
* 是否为当前有效密文:1有效,0历史旧密文(密钥轮换保留) |
|||
*/ |
|||
private Integer isActive; |
|||
|
|||
/** |
|||
* 逻辑删除:0未删除,1已删除 |
|||
*/ |
|||
private Integer isDeleted; |
|||
} |
|||
@ -1,24 +0,0 @@ |
|||
package com.zdxt.enforcementcode.service; |
|||
|
|||
import com.zdxt.enforcementcode.domain.vo.CryptoIntegrityDataVo; |
|||
import com.zdxt.enforcementcode.domain.bo.CryptoIntegrityDataBo; |
|||
import org.dromara.common.mybatis.core.page.TableDataInfo; |
|||
import org.dromara.common.mybatis.core.page.PageQuery; |
|||
|
|||
import java.util.Collection; |
|||
import java.util.List; |
|||
|
|||
public interface ICryptoIntegrityDataService { |
|||
|
|||
CryptoIntegrityDataVo queryById(Long id); |
|||
|
|||
TableDataInfo<CryptoIntegrityDataVo> queryPageList(CryptoIntegrityDataBo bo, PageQuery pageQuery); |
|||
|
|||
List<CryptoIntegrityDataVo> queryList(CryptoIntegrityDataBo bo); |
|||
|
|||
Boolean insertByBo(CryptoIntegrityDataBo bo); |
|||
|
|||
Boolean updateByBo(CryptoIntegrityDataBo bo); |
|||
|
|||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid); |
|||
} |
|||
@ -1,24 +0,0 @@ |
|||
package com.zdxt.enforcementcode.service; |
|||
|
|||
import com.zdxt.enforcementcode.domain.vo.CryptoOperationAuditVo; |
|||
import com.zdxt.enforcementcode.domain.bo.CryptoOperationAuditBo; |
|||
import org.dromara.common.mybatis.core.page.TableDataInfo; |
|||
import org.dromara.common.mybatis.core.page.PageQuery; |
|||
|
|||
import java.util.Collection; |
|||
import java.util.List; |
|||
|
|||
public interface ICryptoOperationAuditService { |
|||
|
|||
CryptoOperationAuditVo queryById(Long id); |
|||
|
|||
TableDataInfo<CryptoOperationAuditVo> queryPageList(CryptoOperationAuditBo bo, PageQuery pageQuery); |
|||
|
|||
List<CryptoOperationAuditVo> queryList(CryptoOperationAuditBo bo); |
|||
|
|||
Boolean insertByBo(CryptoOperationAuditBo bo); |
|||
|
|||
Boolean updateByBo(CryptoOperationAuditBo bo); |
|||
|
|||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid); |
|||
} |
|||
@ -1,24 +0,0 @@ |
|||
package com.zdxt.enforcementcode.service; |
|||
|
|||
import com.zdxt.enforcementcode.domain.vo.CryptoSensitiveDataVo; |
|||
import com.zdxt.enforcementcode.domain.bo.CryptoSensitiveDataBo; |
|||
import org.dromara.common.mybatis.core.page.TableDataInfo; |
|||
import org.dromara.common.mybatis.core.page.PageQuery; |
|||
|
|||
import java.util.Collection; |
|||
import java.util.List; |
|||
|
|||
public interface ICryptoSensitiveDataService { |
|||
|
|||
CryptoSensitiveDataVo queryById(Long id); |
|||
|
|||
TableDataInfo<CryptoSensitiveDataVo> queryPageList(CryptoSensitiveDataBo bo, PageQuery pageQuery); |
|||
|
|||
List<CryptoSensitiveDataVo> queryList(CryptoSensitiveDataBo bo); |
|||
|
|||
Boolean insertByBo(CryptoSensitiveDataBo bo); |
|||
|
|||
Boolean updateByBo(CryptoSensitiveDataBo bo); |
|||
|
|||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid); |
|||
} |
|||
@ -1,89 +0,0 @@ |
|||
package com.zdxt.enforcementcode.service.impl; |
|||
|
|||
import com.zdxt.enforcementcode.domain.bean.CryptoIntegrityData; |
|||
import org.dromara.common.core.utils.MapstructUtils; |
|||
import org.dromara.common.core.utils.StringUtils; |
|||
import org.dromara.common.mybatis.core.page.TableDataInfo; |
|||
import org.dromara.common.mybatis.core.page.PageQuery; |
|||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
|||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
|||
import com.baomidou.mybatisplus.core.toolkit.Wrappers; |
|||
import lombok.RequiredArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.stereotype.Service; |
|||
import com.zdxt.enforcementcode.domain.bo.CryptoIntegrityDataBo; |
|||
import com.zdxt.enforcementcode.domain.vo.CryptoIntegrityDataVo; |
|||
import com.zdxt.enforcementcode.mapper.CryptoIntegrityDataMapper; |
|||
import com.zdxt.enforcementcode.service.ICryptoIntegrityDataService; |
|||
|
|||
import java.util.List; |
|||
import java.util.Map; |
|||
import java.util.Collection; |
|||
|
|||
@Slf4j |
|||
@RequiredArgsConstructor |
|||
@Service |
|||
public class CryptoIntegrityDataServiceImpl implements ICryptoIntegrityDataService { |
|||
|
|||
private final CryptoIntegrityDataMapper baseMapper; |
|||
|
|||
@Override |
|||
public CryptoIntegrityDataVo queryById(Long id) { |
|||
return baseMapper.selectVoById(id); |
|||
} |
|||
|
|||
@Override |
|||
public TableDataInfo<CryptoIntegrityDataVo> queryPageList(CryptoIntegrityDataBo bo, PageQuery pageQuery) { |
|||
LambdaQueryWrapper<CryptoIntegrityData> lqw = buildQueryWrapper(bo); |
|||
Page<CryptoIntegrityDataVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw); |
|||
return TableDataInfo.build(result); |
|||
} |
|||
|
|||
@Override |
|||
public List<CryptoIntegrityDataVo> queryList(CryptoIntegrityDataBo bo) { |
|||
LambdaQueryWrapper<CryptoIntegrityData> lqw = buildQueryWrapper(bo); |
|||
return baseMapper.selectVoList(lqw); |
|||
} |
|||
|
|||
private LambdaQueryWrapper<CryptoIntegrityData> buildQueryWrapper(CryptoIntegrityDataBo bo) { |
|||
Map<String, Object> params = bo.getParams(); |
|||
LambdaQueryWrapper<CryptoIntegrityData> lqw = Wrappers.lambdaQuery(); |
|||
lqw.orderByAsc(CryptoIntegrityData::getId); |
|||
lqw.eq(StringUtils.isNotBlank(bo.getTableName()), CryptoIntegrityData::getTableName, bo.getTableName()); |
|||
lqw.eq(StringUtils.isNotBlank(bo.getBizId()), CryptoIntegrityData::getBizId, bo.getBizId()); |
|||
lqw.eq(StringUtils.isNotBlank(bo.getHashAlg()), CryptoIntegrityData::getHashAlg, bo.getHashAlg()); |
|||
lqw.eq(bo.getVerifyResult() != null, CryptoIntegrityData::getVerifyResult, bo.getVerifyResult()); |
|||
lqw.eq(bo.getIsDeleted() != null, CryptoIntegrityData::getIsDeleted, bo.getIsDeleted()); |
|||
return lqw; |
|||
} |
|||
|
|||
@Override |
|||
public Boolean insertByBo(CryptoIntegrityDataBo bo) { |
|||
CryptoIntegrityData add = MapstructUtils.convert(bo, CryptoIntegrityData.class); |
|||
validEntityBeforeSave(add); |
|||
boolean flag = baseMapper.insert(add) > 0; |
|||
if (flag) { |
|||
bo.setId(add.getId()); |
|||
} |
|||
return flag; |
|||
} |
|||
|
|||
@Override |
|||
public Boolean updateByBo(CryptoIntegrityDataBo bo) { |
|||
CryptoIntegrityData update = MapstructUtils.convert(bo, CryptoIntegrityData.class); |
|||
validEntityBeforeSave(update); |
|||
return baseMapper.updateById(update) > 0; |
|||
} |
|||
|
|||
private void validEntityBeforeSave(CryptoIntegrityData entity) { |
|||
//TODO 做一些数据校验,如唯一约束
|
|||
} |
|||
|
|||
@Override |
|||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) { |
|||
if (isValid) { |
|||
//TODO 做一些业务上的校验,判断是否需要校验
|
|||
} |
|||
return baseMapper.deleteByIds(ids) > 0; |
|||
} |
|||
} |
|||
@ -1,91 +0,0 @@ |
|||
package com.zdxt.enforcementcode.service.impl; |
|||
|
|||
import com.zdxt.enforcementcode.domain.bean.CryptoOperationAudit; |
|||
import org.dromara.common.core.utils.MapstructUtils; |
|||
import org.dromara.common.core.utils.StringUtils; |
|||
import org.dromara.common.mybatis.core.page.TableDataInfo; |
|||
import org.dromara.common.mybatis.core.page.PageQuery; |
|||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
|||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
|||
import com.baomidou.mybatisplus.core.toolkit.Wrappers; |
|||
import lombok.RequiredArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.stereotype.Service; |
|||
import com.zdxt.enforcementcode.domain.bo.CryptoOperationAuditBo; |
|||
import com.zdxt.enforcementcode.domain.vo.CryptoOperationAuditVo; |
|||
import com.zdxt.enforcementcode.mapper.CryptoOperationAuditMapper; |
|||
import com.zdxt.enforcementcode.service.ICryptoOperationAuditService; |
|||
|
|||
import java.util.List; |
|||
import java.util.Map; |
|||
import java.util.Collection; |
|||
|
|||
@Slf4j |
|||
@RequiredArgsConstructor |
|||
@Service |
|||
public class CryptoOperationAuditServiceImpl implements ICryptoOperationAuditService { |
|||
|
|||
private final CryptoOperationAuditMapper baseMapper; |
|||
|
|||
@Override |
|||
public CryptoOperationAuditVo queryById(Long id) { |
|||
return baseMapper.selectVoById(id); |
|||
} |
|||
|
|||
@Override |
|||
public TableDataInfo<CryptoOperationAuditVo> queryPageList(CryptoOperationAuditBo bo, PageQuery pageQuery) { |
|||
LambdaQueryWrapper<CryptoOperationAudit> lqw = buildQueryWrapper(bo); |
|||
Page<CryptoOperationAuditVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw); |
|||
return TableDataInfo.build(result); |
|||
} |
|||
|
|||
@Override |
|||
public List<CryptoOperationAuditVo> queryList(CryptoOperationAuditBo bo) { |
|||
LambdaQueryWrapper<CryptoOperationAudit> lqw = buildQueryWrapper(bo); |
|||
return baseMapper.selectVoList(lqw); |
|||
} |
|||
|
|||
private LambdaQueryWrapper<CryptoOperationAudit> buildQueryWrapper(CryptoOperationAuditBo bo) { |
|||
Map<String, Object> params = bo.getParams(); |
|||
LambdaQueryWrapper<CryptoOperationAudit> lqw = Wrappers.lambdaQuery(); |
|||
lqw.orderByAsc(CryptoOperationAudit::getId); |
|||
lqw.eq(bo.getSensitiveDataId() != null, CryptoOperationAudit::getSensitiveDataId, bo.getSensitiveDataId()); |
|||
lqw.eq(StringUtils.isNotBlank(bo.getTableName()), CryptoOperationAudit::getTableName, bo.getTableName()); |
|||
lqw.eq(StringUtils.isNotBlank(bo.getBizId()), CryptoOperationAudit::getBizId, bo.getBizId()); |
|||
lqw.eq(StringUtils.isNotBlank(bo.getFieldCode()), CryptoOperationAudit::getFieldCode, bo.getFieldCode()); |
|||
lqw.eq(bo.getOperateType() != null, CryptoOperationAudit::getOperateType, bo.getOperateType()); |
|||
lqw.eq(bo.getOperatorId() != null, CryptoOperationAudit::getOperatorId, bo.getOperatorId()); |
|||
lqw.eq(bo.getIsDeleted() != null, CryptoOperationAudit::getIsDeleted, bo.getIsDeleted()); |
|||
return lqw; |
|||
} |
|||
|
|||
@Override |
|||
public Boolean insertByBo(CryptoOperationAuditBo bo) { |
|||
CryptoOperationAudit add = MapstructUtils.convert(bo, CryptoOperationAudit.class); |
|||
validEntityBeforeSave(add); |
|||
boolean flag = baseMapper.insert(add) > 0; |
|||
if (flag) { |
|||
bo.setId(add.getId()); |
|||
} |
|||
return flag; |
|||
} |
|||
|
|||
@Override |
|||
public Boolean updateByBo(CryptoOperationAuditBo bo) { |
|||
CryptoOperationAudit update = MapstructUtils.convert(bo, CryptoOperationAudit.class); |
|||
validEntityBeforeSave(update); |
|||
return baseMapper.updateById(update) > 0; |
|||
} |
|||
|
|||
private void validEntityBeforeSave(CryptoOperationAudit entity) { |
|||
//TODO 做一些数据校验,如唯一约束
|
|||
} |
|||
|
|||
@Override |
|||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) { |
|||
if (isValid) { |
|||
//TODO 做一些业务上的校验,判断是否需要校验
|
|||
} |
|||
return baseMapper.deleteByIds(ids) > 0; |
|||
} |
|||
} |
|||
@ -1,91 +0,0 @@ |
|||
package com.zdxt.enforcementcode.service.impl; |
|||
|
|||
import com.zdxt.enforcementcode.domain.bean.CryptoSensitiveData; |
|||
import org.dromara.common.core.utils.MapstructUtils; |
|||
import org.dromara.common.core.utils.StringUtils; |
|||
import org.dromara.common.mybatis.core.page.TableDataInfo; |
|||
import org.dromara.common.mybatis.core.page.PageQuery; |
|||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
|||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
|||
import com.baomidou.mybatisplus.core.toolkit.Wrappers; |
|||
import lombok.RequiredArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.stereotype.Service; |
|||
import com.zdxt.enforcementcode.domain.bo.CryptoSensitiveDataBo; |
|||
import com.zdxt.enforcementcode.domain.vo.CryptoSensitiveDataVo; |
|||
import com.zdxt.enforcementcode.mapper.CryptoSensitiveDataMapper; |
|||
import com.zdxt.enforcementcode.service.ICryptoSensitiveDataService; |
|||
|
|||
import java.util.List; |
|||
import java.util.Map; |
|||
import java.util.Collection; |
|||
|
|||
@Slf4j |
|||
@RequiredArgsConstructor |
|||
@Service |
|||
public class CryptoSensitiveDataServiceImpl implements ICryptoSensitiveDataService { |
|||
|
|||
private final CryptoSensitiveDataMapper baseMapper; |
|||
|
|||
@Override |
|||
public CryptoSensitiveDataVo queryById(Long id) { |
|||
return baseMapper.selectVoById(id); |
|||
} |
|||
|
|||
@Override |
|||
public TableDataInfo<CryptoSensitiveDataVo> queryPageList(CryptoSensitiveDataBo bo, PageQuery pageQuery) { |
|||
LambdaQueryWrapper<CryptoSensitiveData> lqw = buildQueryWrapper(bo); |
|||
Page<CryptoSensitiveDataVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw); |
|||
return TableDataInfo.build(result); |
|||
} |
|||
|
|||
@Override |
|||
public List<CryptoSensitiveDataVo> queryList(CryptoSensitiveDataBo bo) { |
|||
LambdaQueryWrapper<CryptoSensitiveData> lqw = buildQueryWrapper(bo); |
|||
return baseMapper.selectVoList(lqw); |
|||
} |
|||
|
|||
private LambdaQueryWrapper<CryptoSensitiveData> buildQueryWrapper(CryptoSensitiveDataBo bo) { |
|||
Map<String, Object> params = bo.getParams(); |
|||
LambdaQueryWrapper<CryptoSensitiveData> lqw = Wrappers.lambdaQuery(); |
|||
lqw.orderByAsc(CryptoSensitiveData::getId); |
|||
lqw.eq(StringUtils.isNotBlank(bo.getTableName()), CryptoSensitiveData::getTableName, bo.getTableName()); |
|||
lqw.eq(StringUtils.isNotBlank(bo.getBizId()), CryptoSensitiveData::getBizId, bo.getBizId()); |
|||
lqw.eq(StringUtils.isNotBlank(bo.getFieldCode()), CryptoSensitiveData::getFieldCode, bo.getFieldCode()); |
|||
lqw.eq(StringUtils.isNotBlank(bo.getEncryptAlg()), CryptoSensitiveData::getEncryptAlg, bo.getEncryptAlg()); |
|||
lqw.eq(StringUtils.isNotBlank(bo.getKeyVersion()), CryptoSensitiveData::getKeyVersion, bo.getKeyVersion()); |
|||
lqw.eq(bo.getIsActive() != null, CryptoSensitiveData::getIsActive, bo.getIsActive()); |
|||
lqw.eq(bo.getIsDeleted() != null, CryptoSensitiveData::getIsDeleted, bo.getIsDeleted()); |
|||
return lqw; |
|||
} |
|||
|
|||
@Override |
|||
public Boolean insertByBo(CryptoSensitiveDataBo bo) { |
|||
CryptoSensitiveData add = MapstructUtils.convert(bo, CryptoSensitiveData.class); |
|||
validEntityBeforeSave(add); |
|||
boolean flag = baseMapper.insert(add) > 0; |
|||
if (flag) { |
|||
bo.setId(add.getId()); |
|||
} |
|||
return flag; |
|||
} |
|||
|
|||
@Override |
|||
public Boolean updateByBo(CryptoSensitiveDataBo bo) { |
|||
CryptoSensitiveData update = MapstructUtils.convert(bo, CryptoSensitiveData.class); |
|||
validEntityBeforeSave(update); |
|||
return baseMapper.updateById(update) > 0; |
|||
} |
|||
|
|||
private void validEntityBeforeSave(CryptoSensitiveData entity) { |
|||
//TODO 做一些数据校验,如唯一约束
|
|||
} |
|||
|
|||
@Override |
|||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) { |
|||
if (isValid) { |
|||
//TODO 做一些业务上的校验,判断是否需要校验
|
|||
} |
|||
return baseMapper.deleteByIds(ids) > 0; |
|||
} |
|||
} |
|||
@ -1,166 +0,0 @@ |
|||
package com.zdxt.enforcementcode.service.thirdparty; |
|||
|
|||
import com.zdxt.enforcementcode.domain.vo.passwordparty.SymmetryEncryptVo; |
|||
import com.zdxt.enforcementcode.service.thirdparty.impl.PasswordPartyServiceImpl; |
|||
|
|||
/** |
|||
* IPasswordPartyService 接口方法正向流程演示 |
|||
* <p> |
|||
* 运行前请确保: |
|||
* 1. HSM 密码服务平台已启动且网络可达 |
|||
* 2. 下方 BASE_URL 配置为正确的 HSM 服务地址 |
|||
* 3. HSM 中已配置好所需的密钥(密钥索引、算法类型等) |
|||
* </p> |
|||
* |
|||
* @author vincent |
|||
* @date 2026-09-22 |
|||
*/ |
|||
public class PasswordPartyDemo { |
|||
|
|||
/** HSM 密码服务平台地址,按实际环境修改 */ |
|||
private static final String BASE_URL = "http://localhost:8080"; |
|||
|
|||
private static IPasswordPartyService service; |
|||
|
|||
/** |
|||
* 主入口:手动构造 PasswordPartyServiceImpl 实例,依次调用各接口方法验证正向流程 |
|||
* <p> |
|||
* 执行顺序: |
|||
* 1. 生成随机数 |
|||
* 2. 对称加密 → 对称解密(验证互为逆操作) |
|||
* 3. SM2签名 |
|||
* 4. 非对称加密 → 非对称解密(验证互为逆操作) |
|||
* 5. HMAC摘要 |
|||
* </p> |
|||
*/ |
|||
public static void main(String[] args) { |
|||
// 构造配置并初始化 Service 实例(不依赖 Spring 容器)
|
|||
PasswordPartyConfig config = new PasswordPartyConfig(); |
|||
config.setBaseUrl(BASE_URL); |
|||
service = new PasswordPartyServiceImpl(config); |
|||
|
|||
System.out.println("========== IPasswordPartyService 正向流程演示 ==========\n"); |
|||
|
|||
// 1. 生成随机数:验证 HSM 基础连通性
|
|||
testGenerateRandom(); |
|||
// 2. 对称加密 + 对称解密:使用 SM4 算法,验证加解密互为逆操作
|
|||
testSymmetryEncryptAndDecrypt(); |
|||
// 3. SM2签名:对摘要数据进行签名,验证签名值非空
|
|||
testSM2SignAndVerify(); |
|||
// 4. 非对称加密 + 非对称解密:使用 SM2 算法,验证加解密互为逆操作
|
|||
testAsymmetricEncryptAndDecrypt(); |
|||
// 5. HMAC摘要:使用 SM3 算法计算消息认证码
|
|||
testHmacWithIndex(); |
|||
|
|||
System.out.println("\n========== 全部演示完成 =========="); |
|||
} |
|||
|
|||
/** |
|||
* 1. 生成随机数 |
|||
*/ |
|||
private static void testGenerateRandom() { |
|||
System.out.println("----- 1. 生成随机数 -----"); |
|||
String random = service.generateRandom(10); |
|||
System.out.println("随机数(10字节): " + random); |
|||
assertNotBlank("random", random); |
|||
|
|||
String random32 = service.generateRandom(32); |
|||
System.out.println("随机数(32字节): " + random32); |
|||
assertNotBlank("random32", random32); |
|||
System.out.println(); |
|||
} |
|||
|
|||
/** |
|||
* 2. 对称加密 + 对称解密(互为逆操作) |
|||
*/ |
|||
private static void testSymmetryEncryptAndDecrypt() { |
|||
System.out.println("----- 2. 对称加密 + 对称解密 -----"); |
|||
String plainHex = "31323334353637383132333435363738"; |
|||
|
|||
SymmetryEncryptVo encryptResult = service.symmetryEncrypt(plainHex); |
|||
System.out.println("对称加密原文: " + plainHex); |
|||
System.out.println("对称加密密文: " + encryptResult.getOutData()); |
|||
assertNotBlank("encryptOutData", encryptResult.getOutData()); |
|||
|
|||
SymmetryEncryptVo decryptResult = service.symmetryDecrypt(null, encryptResult.getOutData()); |
|||
System.out.println("对称解密结果: " + decryptResult.getOutData()); |
|||
assertNotBlank("decryptOutData", decryptResult.getOutData()); |
|||
|
|||
if (plainHex.equalsIgnoreCase(decryptResult.getOutData())) { |
|||
System.out.println("[PASS] 对称加密/解密互为逆操作,解密结果与原文一致"); |
|||
} else { |
|||
System.out.println("[WARN] 解密结果与原文不一致,请检查密钥配置"); |
|||
} |
|||
System.out.println(); |
|||
} |
|||
|
|||
/** |
|||
* 3. SM2签名 + SM2验签 |
|||
*/ |
|||
private static void testSM2SignAndVerify() { |
|||
System.out.println("----- 3. SM2签名 + SM2验签 -----"); |
|||
String plainDataHex = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"; |
|||
|
|||
String signValue = service.sm2SignData(plainDataHex); |
|||
System.out.println("SM2签名原文(摘要): " + plainDataHex); |
|||
System.out.println("SM2签名值: " + signValue); |
|||
assertNotBlank("signData", signValue); |
|||
|
|||
System.out.println("[PASS] SM2签名成功,签名值非空"); |
|||
System.out.println(); |
|||
} |
|||
|
|||
/** |
|||
* 4. 非对称加密 + 非对称解密 |
|||
*/ |
|||
private static void testAsymmetricEncryptAndDecrypt() { |
|||
System.out.println("----- 4. 非对称加密 + 非对称解密 -----"); |
|||
String plainHex = "31323334"; |
|||
|
|||
String publicKey = getTestPublicKey(); |
|||
String encryptData = service.externalEncrypt(publicKey, plainHex); |
|||
System.out.println("非对称加密原文: " + plainHex); |
|||
System.out.println("非对称加密密文: " + encryptData); |
|||
assertNotBlank("encryptData", encryptData); |
|||
|
|||
String decrypted = service.internalDecrypt(encryptData); |
|||
System.out.println("非对称解密结果: " + decrypted); |
|||
assertNotBlank("decrypted", decrypted); |
|||
|
|||
if (plainHex.equalsIgnoreCase(decrypted)) { |
|||
System.out.println("[PASS] 非对称加密/解密互为逆操作,解密结果与原文一致"); |
|||
} else { |
|||
System.out.println("[WARN] 解密结果与原文不一致,请检查密钥配置"); |
|||
} |
|||
System.out.println(); |
|||
} |
|||
|
|||
/** |
|||
* 5. HMAC摘要 |
|||
*/ |
|||
private static void testHmacWithIndex() { |
|||
System.out.println("----- 5. HMAC摘要 -----"); |
|||
String inputDataHex = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"; |
|||
|
|||
String hmac = service.hmacWithIndex(inputDataHex); |
|||
System.out.println("HMAC输入摘要: " + inputDataHex); |
|||
System.out.println("HMAC输出值: " + hmac); |
|||
assertNotBlank("hmac", hmac); |
|||
System.out.println("[PASS] HMAC摘要成功,结果非空"); |
|||
System.out.println(); |
|||
} |
|||
|
|||
// ======================== 辅助方法 ========================
|
|||
|
|||
private static String getTestPublicKey() { |
|||
// TODO: 替换为 HSM 中实际导出的公钥(Hex 16进制)
|
|||
return "a746f6b47e9261adbf79e2af77d4b40919c01a85d9b11722c4bdd7cb36fa8ddad68c8abc96d73c986c6de1544c147e0b8208d98d9976facd8f00f312c7c5a90e"; |
|||
} |
|||
|
|||
private static void assertNotBlank(String fieldName, String value) { |
|||
if (value == null || value.isBlank()) { |
|||
throw new AssertionError("[FAIL] " + fieldName + " 返回值为空"); |
|||
} |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
package org.dromara.system.config; |
|||
|
|||
import org.springframework.boot.context.properties.ConfigurationProperties; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
@Component |
|||
@ConfigurationProperties(prefix = "password-party") |
|||
public class PasswordPartyConfig { |
|||
|
|||
private String baseUrl; |
|||
|
|||
public String getBaseUrl() { |
|||
return baseUrl; |
|||
} |
|||
|
|||
public void setBaseUrl(String baseUrl) { |
|||
this.baseUrl = baseUrl; |
|||
} |
|||
} |
|||
@ -1,9 +1,8 @@ |
|||
package com.zdxt.enforcementcode.domain.bean; |
|||
package org.dromara.system.domain.bean; |
|||
|
|||
import org.dromara.common.mybatis.core.domain.BaseEntity; |
|||
import com.baomidou.mybatisplus.annotation.*; |
|||
import com.baomidou.mybatisplus.annotation.TableId; |
|||
import com.baomidou.mybatisplus.annotation.TableName; |
|||
import lombok.Data; |
|||
import lombok.EqualsAndHashCode; |
|||
|
|||
import java.io.Serial; |
|||
import java.util.Date; |
|||
@ -1,9 +1,8 @@ |
|||
package com.zdxt.enforcementcode.domain.bean; |
|||
package org.dromara.system.domain.bean; |
|||
|
|||
import org.dromara.common.mybatis.core.domain.BaseEntity; |
|||
import com.baomidou.mybatisplus.annotation.*; |
|||
import com.baomidou.mybatisplus.annotation.TableId; |
|||
import com.baomidou.mybatisplus.annotation.TableName; |
|||
import lombok.Data; |
|||
import lombok.EqualsAndHashCode; |
|||
|
|||
import java.io.Serial; |
|||
import java.util.Date; |
|||
@ -1,9 +1,8 @@ |
|||
package com.zdxt.enforcementcode.domain.bean; |
|||
package org.dromara.system.domain.bean; |
|||
|
|||
import org.dromara.common.mybatis.core.domain.BaseEntity; |
|||
import com.baomidou.mybatisplus.annotation.*; |
|||
import com.baomidou.mybatisplus.annotation.TableId; |
|||
import com.baomidou.mybatisplus.annotation.TableName; |
|||
import lombok.Data; |
|||
import lombok.EqualsAndHashCode; |
|||
|
|||
import java.io.Serial; |
|||
|
|||
@ -1,10 +1,10 @@ |
|||
package com.zdxt.enforcementcode.domain.vo; |
|||
package org.dromara.system.domain.vo; |
|||
|
|||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated; |
|||
import cn.idev.excel.annotation.ExcelProperty; |
|||
import com.zdxt.enforcementcode.domain.bean.CryptoIntegrityData; |
|||
import io.github.linpeilie.annotations.AutoMapper; |
|||
import lombok.Data; |
|||
import org.dromara.system.domain.bean.CryptoIntegrityData; |
|||
|
|||
import java.io.Serial; |
|||
import java.io.Serializable; |
|||
@ -1,10 +1,11 @@ |
|||
package com.zdxt.enforcementcode.domain.vo; |
|||
package org.dromara.system.domain.vo; |
|||
|
|||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated; |
|||
import cn.idev.excel.annotation.ExcelProperty; |
|||
import com.zdxt.enforcementcode.domain.bean.CryptoOperationAudit; |
|||
|
|||
import io.github.linpeilie.annotations.AutoMapper; |
|||
import lombok.Data; |
|||
import org.dromara.system.domain.bean.CryptoOperationAudit; |
|||
|
|||
import java.io.Serial; |
|||
import java.io.Serializable; |
|||
@ -1,11 +1,11 @@ |
|||
package com.zdxt.enforcementcode.domain.vo; |
|||
package org.dromara.system.domain.vo; |
|||
|
|||
|
|||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated; |
|||
import cn.idev.excel.annotation.ExcelProperty; |
|||
import com.zdxt.enforcementcode.domain.bean.CryptoSensitiveData; |
|||
import io.github.linpeilie.annotations.AutoMapper; |
|||
import lombok.Data; |
|||
import org.dromara.system.domain.bean.CryptoSensitiveData; |
|||
|
|||
import java.io.Serial; |
|||
import java.io.Serializable; |
|||
@ -1,4 +1,4 @@ |
|||
package com.zdxt.enforcementcode.domain.vo.passwordparty; |
|||
package org.dromara.system.domain.vo; |
|||
|
|||
import lombok.Data; |
|||
|
|||
@ -1,9 +1,8 @@ |
|||
package com.zdxt.enforcementcode.mapper; |
|||
package org.dromara.system.mapper; |
|||
|
|||
|
|||
import com.zdxt.enforcementcode.domain.bean.CryptoIntegrityData; |
|||
import com.zdxt.enforcementcode.domain.vo.CryptoIntegrityDataVo; |
|||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; |
|||
import org.dromara.system.domain.bean.CryptoIntegrityData; |
|||
import org.dromara.system.domain.vo.CryptoIntegrityDataVo; |
|||
|
|||
public interface CryptoIntegrityDataMapper extends BaseMapperPlus<CryptoIntegrityData, CryptoIntegrityDataVo> { |
|||
|
|||
@ -1,9 +1,9 @@ |
|||
package com.zdxt.enforcementcode.mapper; |
|||
package org.dromara.system.mapper; |
|||
|
|||
|
|||
import com.zdxt.enforcementcode.domain.bean.CryptoOperationAudit; |
|||
import com.zdxt.enforcementcode.domain.vo.CryptoOperationAuditVo; |
|||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; |
|||
import org.dromara.system.domain.bean.CryptoOperationAudit; |
|||
import org.dromara.system.domain.vo.CryptoOperationAuditVo; |
|||
|
|||
public interface CryptoOperationAuditMapper extends BaseMapperPlus<CryptoOperationAudit, CryptoOperationAuditVo> { |
|||
|
|||
@ -1,8 +1,9 @@ |
|||
package com.zdxt.enforcementcode.mapper; |
|||
package org.dromara.system.mapper; |
|||
|
|||
|
|||
import com.zdxt.enforcementcode.domain.bean.CryptoSensitiveData; |
|||
import com.zdxt.enforcementcode.domain.vo.CryptoSensitiveDataVo; |
|||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; |
|||
import org.dromara.system.domain.bean.CryptoSensitiveData; |
|||
import org.dromara.system.domain.vo.CryptoSensitiveDataVo; |
|||
|
|||
public interface CryptoSensitiveDataMapper extends BaseMapperPlus<CryptoSensitiveData, CryptoSensitiveDataVo> { |
|||
|
|||
@ -0,0 +1,67 @@ |
|||
package org.dromara.system.service; |
|||
|
|||
/** |
|||
* 密评敏感字段 HSM 加密服务 |
|||
* <p> |
|||
* 通过 HSM 密码服务平台对敏感字段进行加密存储,满足密评合规要求。 |
|||
* 手机号/身份证号使用 SM4-CBC 对称加密,密码使用 HMAC-SM3 单向哈希。 |
|||
*/ |
|||
public interface ICryptoSensitiveHsmService { |
|||
|
|||
/** |
|||
* 加密并存储敏感字段(SM4-CBC 对称加密) |
|||
* |
|||
* @param tableName 业务表名,如 sys_user |
|||
* @param bizId 业务记录主键 |
|||
* @param fieldCode 字段编码,如 phone / id_card |
|||
* @param plainText 明文值 |
|||
* @return HSM 加密后的密文(cipherText),加密失败或明文为空时返回 null |
|||
*/ |
|||
String encryptAndSave(String tableName, String bizId, String fieldCode, String plainText); |
|||
|
|||
/** |
|||
* 哈希并存储密码(HMAC-SM3 单向哈希) |
|||
* <p> |
|||
* 生成随机 salt,调用 HSM /hsm/api/HmacWithIndex 接口计算哈希, |
|||
* 哈希值存入 plain_hash,salt 存入 field_salt,cipher_text 为空。 |
|||
* |
|||
* @param tableName 业务表名 |
|||
* @param bizId 业务记录主键 |
|||
* @param plainPassword 明文密码 |
|||
* @return 生成的盐值(Hex),供登录校验时使用 |
|||
*/ |
|||
String hashAndSavePassword(String tableName, String bizId, String plainPassword); |
|||
|
|||
/** |
|||
* 验证密码是否匹配 |
|||
* |
|||
* @param tableName 业务表名 |
|||
* @param bizId 业务记录主键 |
|||
* @param plainPassword 明文密码 |
|||
* @return true=匹配 |
|||
*/ |
|||
boolean verifyPassword(String tableName, String bizId, String plainPassword); |
|||
|
|||
/** |
|||
* 解密获取明文(SM4-CBC 对称解密) |
|||
* |
|||
* @param tableName 业务表名 |
|||
* @param bizId 业务记录主键 |
|||
* @param fieldCode 字段编码 |
|||
* @return 明文值,不存在则返回 null |
|||
*/ |
|||
String decryptField(String tableName, String bizId, String fieldCode); |
|||
|
|||
/** |
|||
* 计算并存储数据完整性摘要(HMAC-SM3) |
|||
* <p> |
|||
* 将多个业务字段明文拼接后,调用 HSM HMAC-SM3 计算摘要, |
|||
* 结果存入 crypto_integrity_data 表,用于后续完整性校验。 |
|||
* |
|||
* @param tableName 业务表名,如 sys_user |
|||
* @param bizId 业务记录主键 |
|||
* @param fieldList 参与摘要的字段列表,逗号分隔,如 password,phonenumber,certificateNumber |
|||
* @param plainValues 与 fieldList 顺序一致的明文值 |
|||
*/ |
|||
void saveIntegrityHash(String tableName, String bizId, String fieldList, String... plainValues); |
|||
} |
|||
@ -0,0 +1,195 @@ |
|||
package org.dromara.system.service.impl; |
|||
|
|||
import cn.hutool.core.util.HexUtil; |
|||
import cn.hutool.core.util.StrUtil; |
|||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
|||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; |
|||
import lombok.RequiredArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.dromara.common.satoken.utils.LoginHelper; |
|||
import org.dromara.system.domain.bean.CryptoIntegrityData; |
|||
import org.dromara.system.domain.bean.CryptoOperationAudit; |
|||
import org.dromara.system.domain.bean.CryptoSensitiveData; |
|||
import org.dromara.system.domain.vo.SymmetryEncryptVo; |
|||
import org.dromara.system.mapper.CryptoIntegrityDataMapper; |
|||
import org.dromara.system.mapper.CryptoOperationAuditMapper; |
|||
import org.dromara.system.mapper.CryptoSensitiveDataMapper; |
|||
import org.dromara.system.service.ICryptoSensitiveHsmService; |
|||
import org.dromara.system.service.IPasswordPartyService; |
|||
import org.springframework.stereotype.Service; |
|||
import org.springframework.transaction.annotation.Transactional; |
|||
|
|||
import java.nio.charset.StandardCharsets; |
|||
import java.util.Date; |
|||
|
|||
@Slf4j |
|||
@RequiredArgsConstructor |
|||
@Service |
|||
public class CryptoSensitiveHsmServiceImpl implements ICryptoSensitiveHsmService { |
|||
|
|||
private final IPasswordPartyService passwordPartyService; |
|||
private final CryptoSensitiveDataMapper cryptoSensitiveDataMapper; |
|||
private final CryptoOperationAuditMapper cryptoOperationAuditMapper; |
|||
private final CryptoIntegrityDataMapper cryptoIntegrityDataMapper; |
|||
|
|||
private static final String KEY_VERSION = "V1"; |
|||
private static final String TABLE_SYS_USER = "sys_user"; |
|||
|
|||
@Override |
|||
@Transactional(rollbackFor = Exception.class) |
|||
public String encryptAndSave(String tableName, String bizId, String fieldCode, String plainText) { |
|||
if (StrUtil.isBlank(plainText)) { |
|||
return null; |
|||
} |
|||
String inputHex = HexUtil.encodeHexStr(plainText.getBytes(StandardCharsets.UTF_8)); |
|||
SymmetryEncryptVo encryptResult = passwordPartyService.symmetryEncrypt(inputHex); |
|||
|
|||
CryptoSensitiveData existing = queryActiveRecord(tableName, bizId, fieldCode); |
|||
if (existing != null) { |
|||
existing.setCipherText(encryptResult.getOutData()); |
|||
existing.setFieldIv(encryptResult.getIvData()); |
|||
existing.setFieldValue(plainText); |
|||
existing.setEncryptAlg("SM4-CBC"); |
|||
existing.setKeyVersion(KEY_VERSION); |
|||
cryptoSensitiveDataMapper.updateById(existing); |
|||
saveAuditRecord(tableName, bizId, fieldCode, existing.getId(), 3, "HSM SM4-CBC 加密更新"); |
|||
} else { |
|||
CryptoSensitiveData record = new CryptoSensitiveData(); |
|||
record.setTableName(tableName); |
|||
record.setBizId(bizId); |
|||
record.setFieldCode(fieldCode); |
|||
record.setFieldValue(plainText); |
|||
record.setCipherText(encryptResult.getOutData()); |
|||
record.setFieldIv(encryptResult.getIvData()); |
|||
record.setEncryptAlg("SM4-CBC"); |
|||
record.setKeyVersion(KEY_VERSION); |
|||
record.setIsActive(1); |
|||
record.setIsDeleted(0); |
|||
cryptoSensitiveDataMapper.insert(record); |
|||
saveAuditRecord(tableName, bizId, fieldCode, record.getId(), 1, "HSM SM4-CBC 加密存储"); |
|||
} |
|||
return encryptResult.getOutData(); |
|||
} |
|||
|
|||
@Override |
|||
@Transactional(rollbackFor = Exception.class) |
|||
public String hashAndSavePassword(String tableName, String bizId, String plainPassword) { |
|||
if (StrUtil.isBlank(plainPassword)) { |
|||
return null; |
|||
} |
|||
return encryptAndSave(tableName, bizId, "password", plainPassword); |
|||
} |
|||
|
|||
@Override |
|||
public boolean verifyPassword(String tableName, String bizId, String plainPassword) { |
|||
CryptoSensitiveData record = queryActiveRecord(tableName, bizId, "password"); |
|||
if (record == null || StrUtil.isBlank(record.getCipherText()) || StrUtil.isBlank(record.getFieldIv())) { |
|||
return false; |
|||
} |
|||
try { |
|||
SymmetryEncryptVo decryptResult = passwordPartyService.symmetryDecrypt(record.getFieldIv(), record.getCipherText()); |
|||
byte[] plainBytes = hexToBytes(decryptResult.getOutData()); |
|||
String decryptedPassword = new String(plainBytes, StandardCharsets.UTF_8); |
|||
return decryptedPassword.equals(plainPassword); |
|||
} catch (Exception e) { |
|||
log.error("HSM解密密码验证失败, tableName={}, bizId={}", tableName, bizId, e); |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public String decryptField(String tableName, String bizId, String fieldCode) { |
|||
CryptoSensitiveData record = queryActiveRecord(tableName, bizId, fieldCode); |
|||
if (record == null || StrUtil.isBlank(record.getCipherText())) { |
|||
return null; |
|||
} |
|||
SymmetryEncryptVo decryptResult = passwordPartyService.symmetryDecrypt(record.getFieldIv(), record.getCipherText()); |
|||
byte[] plainBytes = hexToBytes(decryptResult.getOutData()); |
|||
return new String(plainBytes, StandardCharsets.UTF_8); |
|||
} |
|||
|
|||
@Override |
|||
@Transactional(rollbackFor = Exception.class) |
|||
public void saveIntegrityHash(String tableName, String bizId, String fieldList, String... plainValues) { |
|||
StringBuilder sb = new StringBuilder(); |
|||
for (int i = 0; i < plainValues.length; i++) { |
|||
if (i > 0) sb.append(","); |
|||
sb.append(plainValues[i] != null ? plainValues[i] : ""); |
|||
} |
|||
String concatPlain = sb.toString(); |
|||
String inputHex = HexUtil.encodeHexStr(concatPlain.getBytes(StandardCharsets.UTF_8)); |
|||
String hmacHash = passwordPartyService.hmacWithIndex(inputHex); |
|||
|
|||
LambdaQueryWrapper<CryptoIntegrityData> lqw = new LambdaQueryWrapper<>(); |
|||
lqw.eq(CryptoIntegrityData::getTableName, tableName) |
|||
.eq(CryptoIntegrityData::getBizId, bizId) |
|||
.eq(CryptoIntegrityData::getIsDeleted, 0); |
|||
CryptoIntegrityData existing = cryptoIntegrityDataMapper.selectOne(lqw); |
|||
|
|||
if (existing != null) { |
|||
existing.setFieldList(fieldList); |
|||
existing.setSm3Hash(hmacHash); |
|||
existing.setHashAlg("SM3"); |
|||
existing.setGenerateTime(new Date()); |
|||
existing.setVerifyResult(0); |
|||
cryptoIntegrityDataMapper.updateById(existing); |
|||
} else { |
|||
CryptoIntegrityData record = new CryptoIntegrityData(); |
|||
record.setTableName(tableName); |
|||
record.setBizId(bizId); |
|||
record.setFieldList(fieldList); |
|||
record.setSm3Hash(hmacHash); |
|||
record.setHashAlg("SM3"); |
|||
record.setGenerateTime(new Date()); |
|||
record.setVerifyResult(0); |
|||
record.setIsDeleted(0); |
|||
cryptoIntegrityDataMapper.insert(record); |
|||
} |
|||
} |
|||
|
|||
private CryptoSensitiveData queryActiveRecord(String tableName, String bizId, String fieldCode) { |
|||
LambdaQueryWrapper<CryptoSensitiveData> lqw = new LambdaQueryWrapper<>(); |
|||
lqw.eq(CryptoSensitiveData::getTableName, tableName) |
|||
.eq(CryptoSensitiveData::getBizId, bizId) |
|||
.eq(CryptoSensitiveData::getFieldCode, fieldCode) |
|||
.eq(CryptoSensitiveData::getIsActive, 1) |
|||
.eq(CryptoSensitiveData::getIsDeleted, 0); |
|||
return cryptoSensitiveDataMapper.selectOne(lqw); |
|||
} |
|||
|
|||
private void deactivateExisting(String tableName, String bizId, String fieldCode) { |
|||
LambdaUpdateWrapper<CryptoSensitiveData> uw = new LambdaUpdateWrapper<>(); |
|||
uw.eq(CryptoSensitiveData::getTableName, tableName) |
|||
.eq(CryptoSensitiveData::getBizId, bizId) |
|||
.eq(CryptoSensitiveData::getFieldCode, fieldCode) |
|||
.eq(CryptoSensitiveData::getIsActive, 1) |
|||
.set(CryptoSensitiveData::getIsActive, 0); |
|||
cryptoSensitiveDataMapper.update(null, uw); |
|||
} |
|||
|
|||
private void saveAuditRecord(String tableName, String bizId, String fieldCode, |
|||
Long sensitiveDataId, int operateType, String remark) { |
|||
CryptoOperationAudit audit = new CryptoOperationAudit(); |
|||
audit.setSensitiveDataId(sensitiveDataId); |
|||
audit.setTableName(tableName); |
|||
audit.setBizId(bizId); |
|||
audit.setFieldCode(fieldCode); |
|||
audit.setOperateType(operateType); |
|||
audit.setRemark(remark); |
|||
try { |
|||
audit.setOperatorId(LoginHelper.getUserId()); |
|||
} catch (Exception ignored) { |
|||
} |
|||
cryptoOperationAuditMapper.insert(audit); |
|||
} |
|||
|
|||
private static byte[] hexToBytes(String 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; |
|||
} |
|||
} |
|||
@ -1,13 +1,14 @@ |
|||
package com.zdxt.enforcementcode.service.thirdparty.impl; |
|||
package org.dromara.system.service.impl; |
|||
|
|||
import cn.hutool.http.HttpRequest; |
|||
import cn.hutool.http.HttpResponse; |
|||
import com.alibaba.fastjson.JSONObject; |
|||
import com.zdxt.enforcementcode.domain.vo.passwordparty.SymmetryEncryptVo; |
|||
import com.zdxt.enforcementcode.service.thirdparty.IPasswordPartyService; |
|||
import lombok.RequiredArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.dromara.common.core.exception.base.BaseException; |
|||
import org.dromara.system.config.PasswordPartyConfig; |
|||
import org.dromara.system.domain.vo.SymmetryEncryptVo; |
|||
import org.dromara.system.service.IPasswordPartyService; |
|||
import org.springframework.stereotype.Service; |
|||
|
|||
/** |
|||
Loading…
Reference in new issue