数据库敏感字段快速方便地加密解密

数据库敏感字段快速方便地加密解密


业务背景:用户插入数据时,敏感字段要加密入库;展示在前端时是解密后的。
但是加密后字段只能精确筛选了。

加密解密工具类

使用的是SM4国密算法
导入依赖:

<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-ext-jdk15on</artifactId>
    <version>1.58</version>
    <scope>compile</scope>
</dependency>
<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk15on</artifactId>
    <version>1.58</version>
    <scope>compile</scope>
</dependency>
<dependency>
    <groupId>com.jd.blockchain</groupId>
    <artifactId>crypto-sm</artifactId>
    <version>1.1.2.RELEASE</version>
</dependency>

工具类:

public class SMUtil {
    private SMUtil(){
    }
    private static Logger logger = LoggerFactory.getLogger("SMUtil");
    private static final byte[] SECRET_KEY = StringUtils.getBytesUtf8("b#UHHQyQTTkGAe08");//带偏移量的密钥和偏移量似乎是固定16位长度的
    private static final byte[] IV = StringUtils.getBytesUtf8("ivUHMQJQKKkGAei8");
    private static final String SMENCRYPT_PRE = "SMENCRYPT#";
    /**
     * 将明文字符串加密成密文后,用Base64编码,并加上SMENCRYPT#作为前缀
     * @param plainStr 明文字符串
     * @return Base64编码后的密文,并且加上 SMENCRYPT# 前缀
     */
    public static String encrypt(String plainStr){
        if(org.apache.commons.lang3.StringUtils.isEmpty(plainStr) || isEncryptBySMCrypto(plainStr)==true){
            return plainStr;
        }
        String encResult = null;
        try {
            byte[] encBytes = SM4Utils.encrypt(plainStr.getBytes("UTF-8"), SECRET_KEY ,IV);
            encResult = SMENCRYPT_PRE + Base64.encodeBase64String(encBytes);
        } catch (UnsupportedEncodingException e) {
            logger.error("使用国密算法异常:", e);
        }
        return encResult;
    }

    /**
     * 国密算法解密,要有前缀SMENCRYPT#
     * @param encStr 加密字符串,要有前缀SMENCRYPT#,表示是通过国密算法加密的
     * @return
     */
    public static String decrypt(String encStr){
        if(org.apache.commons.lang3.StringUtils.isEmpty(encStr) || isEncryptBySMCrypto(encStr) == false){
            return encStr;
        }
        String decResult = null;
        String removePre = org.apache.commons.lang3.StringUtils.remove(encStr, SMENCRYPT_PRE);
        try {
            byte[] decBytes = SM4Utils.decrypt(Base64.decodeBase64(removePre), SECRET_KEY);
            decResult = new String(decBytes, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            logger.error("使用国密算法异常:", e);
        }
        return decResult;
    }

    /**
     * 判断是否用国密算法加密过,通过判断前缀是否有SMENCRYPT#
     * @return 有SMENCRYPT#为true表示用了国密算法加密了
     */
    public static boolean isEncryptBySMCrypto(String encStr){
        return org.apache.commons.lang3.StringUtils.contains(encStr, SMENCRYPT_PRE);
    }
}

加密解密处理器

public class SMCryptoTypeHandler extends BaseTypeHandler<String> {
    @Override
    public void setNonNullParameter(PreparedStatement preparedStatement, int i, String s, JdbcType jdbcType) throws SQLException {
        preparedStatement.setString(i, SMUtil.encrypt(s));
    }

    @Override
    public String getNullableResult(ResultSet resultSet, String s) throws SQLException {
        return SMUtil.decrypt(resultSet.getString(s));
    }

    @Override
    public String getNullableResult(ResultSet resultSet, int i) throws SQLException {
        return SMUtil.decrypt(resultSet.getString(i));
    }

    @Override
    public String getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
        return SMUtil.decrypt(callableStatement.getString(i));
    }
}

第一步:在Mapper.xml的resultMap标签中使用,使用示例:
需要加密的字段加上typehandler属性

<resultMap id="BaseResultMap1" type="com.thunisoft.dzsjdc.repository.model.TYwSqjbxx">
        <id column="c_id" jdbcType="CHAR" property="cId"/>
        <result column="c_bdcrxm" jdbcType="VARCHAR" property="cBdcrxm" typeHandler="com......SMCryptoTypeHandler"/>
        <result column="c_bdcrsf" jdbcType="VARCHAR" property="cBdcrsf" typeHandler="com......SMCryptoTypeHandler"/>
        <result column="c_bdcrzw" jdbcType="VARCHAR" property="cBdcrzw" typeHandler="com......SMCryptoTypeHandler"/>
        <result column="c_saay" jdbcType="VARCHAR" property="cSaay"/>
        <result column="c_bwtdwid" jdbcType="VARCHAR" property="cBwtdwid"/>
</resultMap>

第二步:实体类的对应敏感字段上加上注解@ColumnType,示例如下:

@Column(name = "c_bdcrxm")
@ApiModelProperty("...")
@ColumnType(typeHandler = SMCryptoTypeHandler.class)
private String cBdcrxm;

第三步:敏感字段作为筛选条件的查询语句、敏感字段插入数据库时,做出如下处理:

<if test="map.bdcrxm != null and map.bdcrxm != ''">
	and c_bdcrxm like 
	concat('%', #{map.bdcrxm,jdbcType=VARCHAR, typeHandler=com...路径...SMCryptoTypeHandler},'%')
</if>
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值