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

以上是 Java 敏感信息加密处理 的全部内容, 来源链接: utcz.com/z/351148.html

回到顶部