• AES实现财务数据的加密解密存储


    • 需求背景

    众所周知,金融行业有各种各样的财务报表,有些报表涉及到公司财务或经营相关的敏感数据,需要进行加密存储,只有掌握密钥的用户才能看到解密后的数据。注意,这里所说的加密并不是针对整个数据库或者表全局加密,而是针对表的某些字段进行加密。

    • 实现思路

    1、针对某一张报表创建相对应的一张落地表,相关需要加密的字段统一定义为VARCHAR2(1000)。

    2、实现Hibernate监听器接口,在实体保存之前进行加密,数据Load出来之后进行解密,这样可以实现加密解密逻辑的统一处理。

    3、对是否需要加密的实体和字段标注对应的注解,将加密解密的实现逻辑转化为对注解的解析处理。

    4、统一采用AES加密解密算法,放在工具类中实现,加密解密流程(原图摘自:https://blog.csdn.net/gulang03/article/details/81175854)如下:

     5、其他需要处理的场景

         a、数据的保存和查询采用的是JDBC的处理方式,需要在SQL中统一处理(建议用JdbcTemplate底层统一封装下),mysql有内置函数,oracle需要自定义函数实现

         b、数据修改时也需要考虑加密的场景

         c、oracle正常情况,用户不能访问sys.dbms_crypto,需要DBA授权

    •  核心代码

     1、注册监听器事件

    public class HibernateEvent {
    
        @Autowired
        private SessionFactory sessionFactory;
        @Autowired
        private AesListener aesListener;
    
        @PostConstruct
        public void registerListeners() {
            EventListenerRegistry registry = ((SessionFactoryImpl) sessionFactory).getServiceRegistry().getService(
                    EventListenerRegistry.class);
            registry.getEventListenerGroup(EventType.PRE_INSERT).appendListener(aesListener);
            registry.getEventListenerGroup(EventType.POST_LOAD).appendListener(aesListener);
        }
    
    }

    2、监听器实现

    @Component
    public class AesListener implements PreInsertEventListener, PostLoadEventListener {
        @Override
        public boolean onPreInsert(PreInsertEvent event) {
    
            Class clazz = event.getPersister().getMappedClass();
    
            String[] propertyNames = event.getPersister().getPropertyNames();
    
            EnableEncrypted enableEncrypted = (EnableEncrypted)clazz.getAnnotation(EnableEncrypted.class);
    
            if(enableEncrypted != null){
                Field[] fields = clazz.getDeclaredFields();
                if(fields != null){
                    for(Field field : fields){
                        boolean isAccessible = field.isAccessible();
                        if(!isAccessible){
                            field.setAccessible(true);
                        }
                        Encrypted encrypted = field.getAnnotation(Encrypted.class);
                        if(encrypted != null){
                            try {
                                Object value = field.get(event.getEntity());
    
                                Class<?> type = field.getType();
                                String enStr = null;
                                if(type == String.class){
                                    enStr = AesUtils.aesEncrypt(value.toString());
                                }else if(type == Double.class){
                                    Double val = (Double)value;
                                    enStr = AesUtils.aesDecrypt(String.valueOf(val));
                                }
    
                                if(enStr != null){
                                    field.set(event.getEntity(), enStr);
                                    field.setAccessible(isAccessible);
    
                                    for(int i = 0; i < propertyNames.length; i++){
                                        if(field.getName().equals(propertyNames[i])){
                                            event.getState()[i] = enStr;
                                            break;
                                        }
                                    }
                                }
                            } catch (IllegalAccessException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }
            return false;
        }
    }

    3、加密解密工具类

    public class AesUtils {
    
        public static String selectSql(String columnName){
            if(StringUtils.isNotEmpty(columnName)){
                String alias = columnName.contains(".")?columnName.substring(columnName.lastIndexOf(".")+1):columnName;
                return whereSql(columnName) + " AS "+alias;
            }
            return null;
        }
    
        public static String whereSql(String columnName){
            if(StringUtils.isNotEmpty(columnName)){
                return "CAST(AES_DECRYPT(UNHEX("+columnName+"), '"+ AesConstants.AES_KEY +"') AS CHAR)";
            }
            return null;
        }
    
        public static String writeSql(String columnValue){
            if(StringUtils.isNotEmpty(columnValue)){
                return "HEX(AES_ENCRYPT('"+columnValue+"', '"+AesConstants.AES_KEY+"'))";
            }
            return null;
        }
    
        private static String parseByte2HexStr(byte buf[]) {
            StringBuffer sb = new StringBuffer();
            for (int i = 0; i < buf.length; i++) {
                String hex = Integer.toHexString(buf[i] & 0xFF);
                if (hex.length() == 1) {
                    hex = '0' + hex;
                }
                sb.append(hex.toUpperCase());
            }
            return sb.toString();
        }
    
        private static byte[] parseHexStr2Byte(String hexStr) {
            if (hexStr.length() < 1)
                return null;
            byte[] result = new byte[hexStr.length()/2];
            for (int i = 0;i< hexStr.length()/2; i++) {
                int high = Integer.parseInt(hexStr.substring(i*2, i*2+1), 16);
                int low = Integer.parseInt(hexStr.substring(i*2+1, i*2+2), 16);
                result[i] = (byte) (high * 16 + low);
            }
            return result;
        }
    
        public static String aesEncrypt(String content) {
            try {
                SecretKey key = generateMySQLAESKey("ASCII");
                Cipher cipher = Cipher.getInstance("AES");
                cipher.init(Cipher.ENCRYPT_MODE, key);
                byte[] cleartext = content.getBytes("UTF-8");
                byte[] ciphertextBytes = cipher.doFinal(cleartext);
                return new String(Hex.encodeHex(ciphertextBytes));
    
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            } catch (NoSuchPaddingException e) {
                e.printStackTrace();
            } catch (InvalidKeyException e) {
                e.printStackTrace();
            } catch (IllegalBlockSizeException e) {
                e.printStackTrace();
            } catch (BadPaddingException e) {
                e.printStackTrace();
            }
            return null;
        }
    
        public static String aesDecrypt(String content){
            try {
                SecretKey key = generateMySQLAESKey("ASCII");
                Cipher cipher = Cipher.getInstance("AES");
                cipher.init(Cipher.DECRYPT_MODE, key);
                byte[] cleartext = new byte[0];
                try {
                    cleartext = Hex.decodeHex(content.toCharArray());
                } catch (DecoderException e) {
                    log.error("非法的16进制字符串:" + content, e);
                }
                byte[] ciphertextBytes = cipher.doFinal(cleartext);
                return new String(ciphertextBytes, "UTF-8");
    
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            } catch (NoSuchPaddingException e) {
                e.printStackTrace();
            } catch (InvalidKeyException e) {
                e.printStackTrace();
            } catch (IllegalBlockSizeException e) {
                e.printStackTrace();
            } catch (BadPaddingException e) {
                e.printStackTrace();
            }
            return null;
        }
    
        public static SecretKeySpec generateMySQLAESKey(final String encoding) {
            try {
                final byte[] finalKey = new byte[16];
                int i = 0;
                for(byte b : AesConstants.AES_KEY.getBytes(encoding))
                    finalKey[i++%16] ^= b;
                return new SecretKeySpec(finalKey, "AES");
            } catch(UnsupportedEncodingException e) {
                throw new RuntimeException(e);
            }
        }
    
    }
  • 相关阅读:
    我的2015年ccf的解答
    VS中出现“链接器工具错误,XXX工具模块对于SAFESEH映像是不安全的”的解决方法
    记录每次运行的时刻的小程序
    c语言中strcpy与strlen函数对字符串最后的''的处理
    windows8.1的启动目录的路径
    使用feof()判断文件结束时会多输出内容的原因
    [转]android sqlite db-journal文件产生原因及说明
    安卓备份 To Do(待办事项)的数据库
    下载YouTube视频的方法
    Firefox及我使用的firefox扩展
  • 原文地址:https://www.cnblogs.com/abingtech/p/13027821.html
Copyright © 2020-2023  润新知