【数据存储加密】国密算法

基于对称加密国密算法进行数据库存储加密

业务背景

某银行,由于行内要求以及系统安全考虑,现需要对数据库存储的敏感信息进行加密存储。

加密算法

加密算法分对称加密、非对称加密、可逆加密、不可逆加密。

  • 对称加密:即加密和解密用同一个秘钥
  • 非对称加密:秘钥分公钥和私钥,加密用私钥,解密需用公钥;加密用公钥,解密需用私钥。
  • 可逆加密:即加密内容可解密
  • 不仅可逆加密:即加密内容不可揭秘

根据业务背景来选去算法,因为数据在入库的时候需要加密,但在逻辑处理的时候需要解密,所以需要可逆加密算法。同时因为数据使用不存在第三方系统直接调用,所以选用对称加密。我这里选用的是国密SM4-ECB算法。

详细设计

分析

主流程业务节点按照订单号进行流转,订单号由日期+递增序号组成,切量阶段即可根据订单号进行判断是否需要加密或者解密。然后通过自定义注解,用来标识需要加解密的字段。这样就已经可以确认哪些数据哪些字段需要加密。然后新建一张秘钥参数表,用于存储秘钥和订单号的范围,这样就可以实现加密功能的切量。
由于加密后的内容是byte数组,长度为原数据长度向上取16的倍数,如果直接将byte数组存入数据库,会导致栏位长度扩大好几倍,增加数据库存储压力。所以在加密之后,对加密的结果转换为Base64后进行存储。转换后的长度大概为字节数组长度的三分之四。

设计

  1. 获取秘钥
    对秘钥表创建缓存,根据订单号获取秘钥,获取不到即不需要加解密处理。
  2. 加解密
    方法入参为泛型,利用反射,判断字段上是否有加解密的注解,以此来进行加解密,然后置入字段。

加密注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 是否加密
 *
 * @author LGQ
 */
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface IsEncrypt {
}

加密方法

/**
     * 根据字段注解对实体进行加密
     *
     * @param t 实体
     * @return 实体
     */
    public static <T> T encrypt(T t, String secretKey) {
        if (StringUtils.isBlank(secretKey)) {
            return t;
        }
        String currentFiled = null;
        String currentFiledValue = null;
        try {
            T newObject = (T) t.getClass().newInstance();
            BeanUtils.copyProperties(t, newObject, t.getClass());
            Class<?> aClass = t.getClass();
            for (Field declaredField : aClass.getDeclaredFields()) {
                declaredField.setAccessible(true);
                IsEncrypt isEncrypt = declaredField.getDeclaredAnnotation(IsEncrypt.class);
                if (null != isEncrypt) {
                    currentFiled = declaredField.getName();
                    currentFiledValue = (String) declaredField.get(t);
                    declaredField.set(newObject, encrypt(currentFiledValue, secretKey));
                }
            }
            return newObject;
        } catch (Exception e) {
            log.error("SM4国密加密失败,加密秘钥为{},加密字段{},字段数据{}", secretKey, currentFiled, currentFiledValue, e);
            throw new EncryptException("SM4国密加密失败");
        }
    }

	/**
     * 数据加密
     *
     * @param data 明文
     * @return 加密后的byte转Base64
     */
    public static String encrypt(String data, String secretKey) {
        if (StringUtils.isBlank(data)) {
            return data;
        }
        try {
            //2、加密
            SMCryptKY smCryptKY = new SMCryptKY();
            byte[] secretDataBytes = smCryptKY.SM4EncryptWithECB(secretKey.getBytes(StandardCharsets.UTF_8), data.getBytes());
            return Base64.getEncoder().encodeToString(secretDataBytes);
        } catch (SMCryptException e) {
            log.error("SM4国密加密失败,加密内容为{},加密秘钥为{}", data, secretKey, e);
            throw new EncryptException("SM4国密加密失败");
        }
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

宋马尧

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值