Java 敏感信息加密处理
一、敏感信息加密处理我们要实现什么
系统往往需要将用户敏感信息进行加密,不同的敏感信息加密要求不同。
比如,密码的加密,我们往往不需要是可逆的。用户输入密码后,通过系统的加密规则,编码后直接比对加密存储的密码,获得比对结果即可证明用户登录信息合法性。
然后,有时我们为了防止被脱库导致的数据泄漏,不得不对一些敏感信息(比如:身份证号、手机号)进行加密。这样的数据不仅要求加密,还需要在展示及其他业务场景下完全显示,或者掩码显示,这就需要我们对加密的内容进行解密。
二、敏感信息加密处理我做了些什么
近来,项目中为了实现这个需求,做了些简单的设计:
注:考虑到在维护生产数据时方便查询,这里使用aes加密方式,该加密方式同mysql的aes加密结果相同,故可在sql中直接使用hex及aes_encrypt函数进行查询;密盐可保存在配置文件中。
1.使用自定义注解,po的每个类中需要加密及解密的字段可添加该注解
2.声明base类,并实现encrypt和decrypt方法,方法实现利用java反射及自定义注解
3.所有需要用到加密及解密的实体对象,必须继承自base类
4.实体类加密时调用encrypt方法,解密时调用decrypt方法,如此可实现对该对象中敏感数据的加密解密
三、敏感信息加密实现
1.先看效果
注释很清楚,先给对象设置身份证号,然后执行自加密方法,返回自己的引用,打印出来加密后该对象的json字符串;执行自解密方法,返回自己的引用,打印出来解密后该对象的json字符串。
2.设计实现结构
crypt | |--annotation | |--decryptfiled | |--encryptfiled |--crypt | |--encryptdecryptinterface |--domain | |--baseinfo | |--simpledomain |--utils | |--mysqlutils
2.1先看看注解的实现
/** * created by bright on 2017/2/22. * * @author : */ @target(elementtype.field) @retention(retentionpolicy.runtime) public @interface encryptfiled { string value() default ""; } 自定义注解
两个注解的实现一致,注解名称不同而已,不再贴另外一个注解的代码。
2.2定义自加密、自解密接口
base类实现该接口中的自加密自解密方法
/** * created by bright on 2017/2/22. * * @author : */ public interface encryptdecryptinterface { public <t> t encryptself(); public <t> t decryptself(); } 自定义接口
2.3mysqlutils的实现
/** * created by bright on 2017/2/22. * * @author : */ @component public class mysqlutils { private static final string encrypttype= "aes";//加密方式 private static final string encoding = "utf-8";//加密时编码 private static string mysqlutilskey = "aaa";//加密密盐 private static mysqlutils mysqlutils;//单例 private static cipher encryptcipher ;//加密cipher private static cipher decryptchipher;//解密chipher /** * 该方法可用在spring项目中使用配置文件设置密盐,默认值为123 * @param key */ @value("${mysql.column.crypt.key:123}") public void setmysqlutilskey(string key){ mysqlutils.mysqlutilskey = key; } /** * encryptcipher、decryptchipher初始化 */ public static void init(){ try { encryptcipher = cipher.getinstance(encrypttype); decryptchipher = cipher.getinstance(encrypttype); encryptcipher.init(cipher.encrypt_mode, generatemysqlaeskey(mysqlutilskey, encoding)); decryptchipher.init(cipher.decrypt_mode, generatemysqlaeskey(mysqlutilskey, encoding)); } catch (invalidkeyexception e) { throw new runtimeexception(e); } catch (nosuchalgorithmexception e) { throw new runtimeexception(e); } catch (nosuchpaddingexception e) { throw new runtimeexception(e); } } /** * 单例获取方法实现 * @return */ public synchronized static mysqlutils getinstance(){ if(mysqlutils == null){ mysqlutils = new mysqlutils(); init(); } return mysqlutils; } /** * 加密算法 * @param encryptstring * @return */ public string mysqlaesencrypt(string encryptstring) { try{ return new string(hex.encodehex(encryptcipher.dofinal(encryptstring.getbytes(encoding)))).touppercase(); } catch (badpaddingexception e) { throw new runtimeexception(e); } catch (unsupportedencodingexception e) { throw new runtimeexception(e); } catch (illegalblocksizeexception e) { throw new runtimeexception(e); } } /** * 解密算法 * @param decryptstring * @return */ public string mysqlaesdecrypt(string decryptstring){ try { return new string(decryptchipher.dofinal(hex.decodehex(decryptstring.tochararray()))); } catch (decoderexception nspe) { throw new runtimeexception(nspe); } catch (badpaddingexception nsae) { throw new runtimeexception(nsae); } catch (illegalblocksizeexception ike) { throw new runtimeexception(ike); } } /** * 产生mysql-aes_encrypt * @param key 加密的密盐 * @param encoding 编码 * @return */ public static secretkeyspec generatemysqlaeskey(final string key, final string encoding) { try { final byte[] finalkey = new byte[16]; int i = 0; for(byte b : key.getbytes(encoding)) finalkey[i++%16] ^= b; return new secretkeyspec(finalkey, "aes"); } catch(unsupportedencodingexception e) { throw new runtimeexception(e); } } } mysqlutils
2.4baseinfo类的实现
/** * created by bright on 2017/2/22. * * @author : */ public class baseinfo implements cloneable, encryptdecryptinterface { /** * 拷贝一个对象,并对新对象进行加密 * 该方法主要用在日志打印上,可防止原对象被加密而影响程序执行 * @param <t> * @return */ public <t extends baseinfo> t cloneandencrypt() { t clonet = null; try { clonet = (t) this.clone(); } catch (clonenotsupportedexception e) { e.printstacktrace(); return null; } if(clonet !=null) return clonet.encryptself(); throw new runtimeexception("拷贝对象异常"); } /** * 重写clone方法 * @return * @throws clonenotsupportedexception */ @override protected object clone() throws clonenotsupportedexception { try { return super.clone(); } catch (clonenotsupportedexception e) { e.printstacktrace(); return null; } } /** * 实现自加密 * * @param <t> * @return */ public <t> t encryptself() { field[] declaredfields = this.getclass().getdeclaredfields(); try { if (declaredfields != null && declaredfields.length > 0) { for (field field : declaredfields) { if (field.isannotationpresent(encryptfiled.class) && field.gettype().tostring().endswith("string")) { field.setaccessible(true); string fieldvalue = (string) field.get(this); if (stringutils.isnotempty(fieldvalue)) { field.set(this, mysqlutils.getinstance().mysqlaesencrypt(fieldvalue)); } field.setaccessible(false); } } } } catch (illegalaccessexception e) { throw new runtimeexception(e); } return (t) this; } /** * 实现自解密 * * @param <t> * @return */ public <t> t decryptself() { field[] declaredfields = this.getclass().getdeclaredfields(); try { if (declaredfields != null && declaredfields.length > 0) { for (field field : declaredfields) { if (field.isannotationpresent(decryptfiled.class) && field.gettype().tostring().endswith("string")) { field.setaccessible(true); string fieldvalue = (string)field.get(this); if(stringutils.isnotempty(fieldvalue)) { field.set(this, mysqlutils.getinstance().mysqlaesdecrypt(fieldvalue)); } } } } } catch (illegalaccessexception e) { throw new runtimeexception(e); } return (t) this; } } baseinfo
2.5一个简单的对象
/** * created by bright on 2017/2/22. * * @author : */ public class simpledomain extends baseinfo{ @encryptfiled @decryptfiled private string id; public string getid() { return id; } public void setid(string id) { this.id = id; } } simpledomain
2.6来个调用
public class client { @test public void test(){ simpledomain sd = new simpledomain();//要进行加密解密的实体类 sd.setid("6029131988005021537");//注入身份证号 system.out.println(json.tojsonstring(sd.encryptself()));//执行自加密后输出 system.out.println(json.tojsonstring(sd.decryptself()));//执行自解密后输出 } } client
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持!
上一篇: 用了这么多年的Spring 你还记得?