前言
在一些安全性要求比较高的项目里,避免不了要对敏感信息进行加解密,比如配置文件中的敏感信息。
第一种方法(自定义加解密)
加解密工具类:
public class SecurityTools {
public static final String ALGORITHM = "AES/ECB/PKCS5Padding"; //算法类型
/**
*功能描述: 解密
* @author zhouwenjie
* @date 2023/3/9 16:49
* @param req
* @return org.hwdz.common.util.security.entity.SecurityResp
*/
public static SecurityResp valid(SecurityReq req) {
SecurityResp resp=new SecurityResp();
String pubKey=req.getPubKey();
String aesKey=req.getAesKey();
String data=req.getData();
String signData=req.getSignData();
RSA rsa=new RSA(null, Base64Decoder.decode(pubKey));
Sign sign= new Sign(SignAlgorithm.SHA1withRSA,null,pubKey);
byte[] decryptAes = rsa.decrypt(aesKey, KeyType.PublicKey);
//log.info("rsa解密后的秘钥"+ Base64Encoder.encode(decryptAes));
AES aes = SecureUtil.aes(decryptAes);
String dencrptValue =aes.decryptStr(data);
//log.info("解密后报文"+dencrptValue);
resp.setData(dencrptValue);
boolean verify = sign.verify(dencrptValue.getBytes(), Base64Decoder.decode(signData));
resp.setSuccess(verify);
return resp;
}
/**
*功能描述: 加密
* @author zhouwenjie
* @date 2023/3/9 16:49
* @param req
* @return org.hwdz.common.util.security.entity.SecuritySignResp
*/
public static SecuritySignResp sign(SecuritySignReq req) {
SecretKey secretKey = SecureUtil.generateKey(ALGORITHM);
byte[] key= secretKey.getEncoded();
String prikey=req.getPrikey();
String data=req.getData();
AES aes = SecureUtil.aes(key);
aes.getSecretKey().getEncoded();
String encrptData =aes.encryptBase64(data);
RSA rsa=new RSA(prikey,null);
byte[] encryptAesKey = rsa.encrypt(secretKey.getEncoded(), KeyType.PrivateKey);
//log.info(("rsa加密过的秘钥=="+Base64Encoder.encode(encryptAesKey));
Sign sign= new Sign(SignAlgorithm.SHA1withRSA,prikey,null);
byte[] signed = sign.sign(data.getBytes());
//log.info(("签名数据===》》"+Base64Encoder.encode(signed));
SecuritySignResp resp=new SecuritySignResp();
resp.setAesKey(Base64Encoder.encode(encryptAesKey));
resp.setData(encrptData);
resp.setSignData(Base64Encoder.encode(signed));
return resp;
}
/**
*功能描述: 生成公钥、密钥
* @author zhouwenjie
* @date 2023/3/9 16:49
* @param
* @return org.hwdz.common.util.security.entity.MyKeyPair
*/
public static MyKeyPair generateKeyPair(){
KeyPair keyPair= SecureUtil.generateKeyPair(SignAlgorithm.SHA1withRSA.getValue(),2048);
String priKey= Base64Encoder.encode(keyPair.getPrivate().getEncoded());
String pubkey= Base64Encoder.encode(keyPair.getPublic().getEncoded());
MyKeyPair resp=new MyKeyPair();
resp.setPriKey(priKey);
resp.setPubKey(pubkey);
return resp;
}
}
实体类:
@Data
public class MyKeyPair {
private String priKey;
private String pubKey;
}
@Data
public class SecurityReq {
private String data;
private String pubKey;
private String signData;
private String aesKey;
}
@Data
public class SecurityResp {
private Boolean success;
private String data;
}
@Data
public class SecuritySignReq {
private String data;
private String prikey;
}
@Data
public class SecuritySignResp {
private String data;
private String signData;
private String aesKey;
}
使用:
//加密
MyKeyPair myKeyPair = SecurityTools.generateKeyPair();
System.out.println(myKeyPair);
SecuritySignReq securitySignReq = new SecuritySignReq();
securitySignReq.setData("qazQAZ123");
securitySignReq.setPrikey(CommonConstant.priKey);
SecuritySignResp sign = SecurityTools.sign(securitySignReq);
System.out.println(sign);
//解密
SecurityReq securityReq = new SecurityReq();
securityReq.setSignData(sign.getSignData());
securityReq.setData(sign.getData());
securityReq.setAesKey(sign.getAesKey());
securityReq.setPubKey(CommonConstant.pubKey);
SecurityResp valid = SecurityTools.valid(securityReq);
System.out.println(valid);
第二种方法 (使用srpingboot druid)
使用srpingboot druid自带的方法
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
工具类:
/**
* 使用Druid数据库密码加密配置
* @param args
*/
public static void main(String[] args) {
//加密
try {
String miwenofter = ConfigTools.encrypt("aaa");
System.out.println("加密后"+miwenofter);
} catch (Exception e) {
e.printStackTrace();
}
//解密
try {
String mingwen = ConfigTools.decrypt("frL2qjh4LPrVaWZdzZkfVKDPgyrbfaEofNBMrk9fHoYE7KJ08RSQEjCS+9JMKe/w==");
System.out.println("解密后:"+mingwen);
} catch (Exception e) {
e.printStackTrace();
}
}
配置文件:
server.port=8080
spring.datasource.druid.driverClassName=com.mysql.jdbc.Driver
spring.datasource.druid.url=jdbc:mysql://XXX:3306/vehicle?useSSL=false&allowPublicKeyRetrieval=true&rewriteBatchedStatements=true
spring.datasource.druid.username=vehicle
#密码
spring.datasource.druid.password=通过测试类获取到加密后密码
spring.datasource.type: com.alibaba.druid.pool.DruidDataSource
# 初始化大小、最小、最大连接数
spring.datasource.druid.initial-size=3
spring.datasource.druid.min-idle=3
spring.datasource.druid.max-active=10
# 配置获取连接等待超时的时间
spring.datasource.druid.max-wait=60000
# 监控后台账号和密码
spring.datasource.druid.stat-view-servlet.login-username=admin
spring.datasource.druid.stat-view-servlet.login-password=admin
# 配置 StatFilter
spring.datasource.druid.filter.stat.log-slow-sql=true
spring.datasource.druid.filter.stat.slow-sql-millis=2000
#数据库加密 这两步很重要 ***************
spring.datasource.druid.filters = config,wall,stat
spring.datasource.druid.connectionProperties=druid.stat.slowSqlMillis=200;druid.stat.logSlowSql=true;config.decrypt=true
注意,这里只适用druid配置的数据库信息,比如,配置文件有下边的配置,将druid配置排除在外就不可以。
第三种方法(常用,Jasypt实现数据加解密)
简介:
不仅可以实现数据加解密,通过注解无感操作配置文件解密
1. 配置版本
mvn仓库选择对应版本
2. 集成项目
在启动类上添加注解:`@EnableEncryptableProperties``
3. yml配置
主要配置盐值、加密方法、编码形式,除了盐值(password),其他两项为默认值,如果没有特殊要求就用默认值即可。
提示:
不配置盐值容易出现 must be provided for Password-based or Asymmetric encryption
错误!
4.使用加解密
之后将生成的加密串配置到对应的地方即可。
注意:记得加前缀和后缀ENC()
,当然这个前后缀也是可以换成自己想要的
5.数据脱敏
也是加解密,只不过需要手动,在aop中,参考文章Jasypt实现数据加解密(脱敏)
6.完善细节
虽然上边的配置已经可以了,但是将加解密秘钥放在配置文件中是不安全的,也就是上边的盐值(password),所以我们可以放在代码里或者其地方,下边提供两种参考
启动类加载
配置文件
/**
* 配置StringEncryptor
*/
@Bean("jasyptStringEncryptor")
public StringEncryptor stringEncryptor() {
PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
SimpleStringPBEConfig config = new SimpleStringPBEConfig();
config.setPassword("EbfYkitulv73I2p0mXI50JMXoaxZTKJ7");
config.setAlgorithm("PBEWithMD5AndDES");
config.setKeyObtentionIterations("1000");
config.setPoolSize("1");
config.setProviderName("SunJCE");
config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator");
config.setIvGeneratorClassName("org.jasypt.salt.NoOpIVGenerator");
config.setStringOutputType("base64");
encryptor.setConfig(config);
return encryptor;
}
可能遇到问题:
Encryption raised an exception. A possible cause is you are using strong encryption algorithms and you have not installed the Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files in this Java Virtual Machine
解决办法:
因为Jasypt的2.x版本,jasypt.encryptor.algorithm默认值为PBEWithMD5AndDES
,而3.x版本中,该属性的默认值为 PBEWITHHMACSHA512ANDAES_256
。
那么你可以安装JCE,或者指定 jasypt.encryptor.algorithm
值为 PBEWithMD5AndDES
。