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);
}
} }
AES实现财务数据的加密解密存储的更多相关文章
- php中签名公钥、私钥(SHA1withRSA签名)以及AES(AES/ECB/PKCS5Padding)加密解密详解
由于http请求是无状态,所以我们不知道请求方到底是谁.于是就诞生了签名,接收方和请求方协商一种签名方式进行验证,来取得互相信任,进行下一步业务逻辑交流. 其中签名用得很多的就是公钥私钥,用私钥签名, ...
- 通过Jni实现AES的CBC模式加密解密
AES加密方式基本实现,出现一个问题就是代码的安全性.我们知道java层代码很容易被反编译,很有可能泄漏我们加密方式与密钥 内容,那我们该怎么办呢?我们可以使用c/c++实现加密,编译成So库的形式, ...
- JAVA和PYTHON同时实现AES的加密解密操作---且生成的BASE62编码一致
终于有机会生产JAVA的东东了. 有点兴奋. 花了一天搞完.. java(关键key及算法有缩减): package com.security; import javax.crypto.Cipher; ...
- php实现AES/CBC/PKCS5Padding加密解密(又叫:对称加密)
今天在做一个和java程序接口的架接,java那边需要我这边(PHP)对传过去的值进行AES对称加密,接口返回的结果也是加密过的(就要用到解密),然后试了很多办法,也一一对应了AES的key密钥值,偏 ...
- python中常用的base64 md5 aes des crc32等的加密解密
1.base64 Python内置的base64模块可以实现base64.base32.base16.base85.urlsafe_base64的编码解码,python 3.x通常输入输出都是二进制形 ...
- AES加密解密的例子小结
话不多说,先放上代码,一共有两个文件:AES.php(aes算法类文件)和aesDemo.php(应用实例文件),这里只贴出aesDemo.php,其他的看附件吧!aesDemo.php: 例子, ...
- DES加密解密与AES加密解密
随着开发时间的变长,当初认为比较难的东西,现在渐渐也就变的不那么难了!特别对于一些经常很少使用的类,时间长了之后渐渐就陌生了.所以在这里写一些日后可能会用到的加密与解密. 一.AES加密算法和DES加 ...
- Java 关于密码处理的工具类[MD5编码][AES加密/解密]
项目中又遇到了加密问题,又去翻了半天,然后做测试,干脆就把常用的两类小结一下. 1.第一种所谓的MD5加密 其实也不算加密,只是基于Hash算法的不可逆编码而已,等于说,一旦经过MD5处理,是不可能从 ...
- 你真的了解字典(Dictionary)吗? C# Memory Cache 踩坑记录 .net 泛型 结构化CSS设计思维 WinForm POST上传与后台接收 高效实用的.NET开源项目 .net 笔试面试总结(3) .net 笔试面试总结(2) 依赖注入 C# RSA 加密 C#与Java AES 加密解密
你真的了解字典(Dictionary)吗? 从一道亲身经历的面试题说起 半年前,我参加我现在所在公司的面试,面试官给了一道题,说有一个Y形的链表,知道起始节点,找出交叉节点.为了便于描述,我把上面 ...
随机推荐
- 从入门到精通(分布式文件系统架构)-FastDFS,FastDFS-Nginx整合,合并存储,存储缩略图,图片压缩,Java客户端
导读 互联网环境中的文件如何存储? 不能存本地应用服务器 NFS(采用mount挂载) HDFS(适合大文件) FastDFS(强力推荐
- 绕WAF文章收集
在看了bypassword的<在HTTP协议层面绕过WAF>之后,想起了之前做过的一些研究,所以写个简单的短文来补充一下文章里“分块传输”部分没提到的两个技巧. 技巧1 使用注释扰乱分块数 ...
- keepalived高可用服务配置管理
实验环境: 主机 ipaddress 服务 备注 k8s-master1 10.0.0.63 nginx k8s-master2 10.0.0.64 nginx k8s-node1 10.0.0.65 ...
- XSS检测总结
XSS漏洞介绍 跨站脚本XSS是一种针对网站应用程序的安全漏洞攻击技术.恶意攻击者往web页面插入恶意的Script代码,当用于浏览该页时,嵌入web中的恶意代码就会被执行,从而达到恶意攻击用 ...
- 【csu oj 1542】线段树
题目大意:给定一个合法的括号序列(只包含'(',')'),有q次操作,对每次操作改变一个位置的括号,求最左端的位置,使得改变这个位置上的括号以后,新序列合法(完全配对). 思路:对于合法的括号序列,如 ...
- vue mock 模拟接口数据
日常总结 希望能帮到大家 1 mock/sever.js //创建服务 let http=require('http') let fs=require('fs') let url=require(' ...
- 宽字节XSS跨站攻击
简介 宽字节跨站漏洞多发生在GB系统编码. 对于GBK编码,字符是由两个字节构成,在%df遇到%5c时,由于%df的ascii大于128,所以会自动拼接%5c,吃掉反斜线.而%27 %20小于asci ...
- Xshell 与 Xftp 的安装与使用
我们在日常工作中,不管是系统管理员.程序员.还是技术工程师,如果想登陆到 Linux 服务器,不可能总是跑到机房去工作,通常我们需要一个工具帮我们去做远程连接,这样我们只需要用笔记本电脑就可以连接到服 ...
- 浅谈产品模型(Profile)在程序设计中的作用
引言:物联网平台的一个重要功能就是资产管理,产品或者设备都可以看成是资产中组成部分,所以有时候说物联网平台可以进行产品管理和设备管理.通常应用物联网平台开发一套具有产品或者设备管理功能的系统的时候,必 ...
- Codeforces1141E(E题)Superhero Battle
A superhero fights with a monster. The battle consists of rounds, each of which lasts exactly nn min ...