# encrypt-spring-boot-starter
**Repository Path**: LevelCoder/encrypt-spring-boot-starter
## Basic Information
- **Project Name**: encrypt-spring-boot-starter
- **Description**: 多场景加解密 混合加密 支持任意请求 任意参数 数据加密 starter
- **Primary Language**: Java
- **License**: Apache-2.0
- **Default Branch**: master
- **Homepage**: https://www.longfa.cloud
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 5
- **Created**: 2024-09-29
- **Last Updated**: 2024-09-29
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# **encrypt-spring-boot-starter**
## maven坐标
```xml
cloud.longfa
encrypt-spring-boot-starter
1.0.6-RELEASE
```
WEB应用加解密请查看此根目录WEBAPP.md文档 配套使用
## 实现方案
aop、反射机制、递归算法 、策略模式
## 优势
1. **全注解、支持spel表达式(改造过,易用)、支持任意字段、任意参数、任意请求方式**
2. **支持多种场景(传输场景、存储场景)**
3. **支持扩展其他场景(已经实现网络传输、存储加解密)**
4. **支持扩展其他的加密算法**
5. **支持的加密模式:单类算法加密(多参数单算法)、多类算法混合(单参数|字段单算法)、混合模式(单参数 多种算法)、混合模式之随机密钥**
6. **支持任意请求方式 、任意多个参数、body 支持java集合、实体类等等**
7. **支持RPC框架 实现前端后、端对端数据加密**
8. **支持任意多个字段|参数 任意多种加密算法同时用**
## 数据加密 场景启动器
### 支持的场景
#### 一 、传输场景加密解密
网络传输后端加减密 *前端加解密没空写*
支持RPC框架 远程调用 多种算法混合使用 能控制到每一个字段 都使用独立的算法 不必担心解不了密!!! 怎么加怎么解
#### 二 、存储场景 加密解密
支持存储加解密 多种算法混合使用
## 支持的请求方式
任意请求方式 不仅仅只是争对body 也支持请求参数(任意个)
## 层级要求
无限层 支持无限套娃!!!
比如集合嵌套集合 支持多层级嵌套
## 支持的加密模式
支持的加密算法 AES、RSA、SM4 混合加密 动态密钥混合加密 同时也支持扩展其他算法
1. 单模式加密:
一个接口只使用一种加密算法
2. 多种算法单模式
一个接口下每一个参数使用单独的加密算法
3. 混合加密:
两种以上的加密算法融合使用 密钥使用自己配置的
4. 动态混合加密:
密钥是随机生成 每一次请求密钥都是不一样 提供了外部获取密钥的方式
## 目录结构
老版本:
```
├─src
│ └─main
│ ├─java
│ │ └─cloud
│ │ └─longfa
│ │ └─encrypt
│ │ ├─anotation
│ │ │ Decrypt.java 加密注解
│ │ │ EnableEncrypt.java 导入模块注解
│ │ │ Encrypt.java 解密注解
│ │ │
│ │ ├─aspectj
│ │ │ EncryptHandler.java 注解处理器 aop
│ │ │
│ │ ├─badger
│ │ │ HoneyBadgerEncrypt.java 加密实现类
│ │ │
│ │ ├─config
│ │ │ AESConfiguration.java AES配置
│ │ │ EncryptAutoConfiguration.java
│ │ │ EncryptConfiguration.java
│ │ │ EncryptImportSelector.java
│ │ │ EncryptProvider.java
│ │ │ RSAConfiguration.java RSA配置
│ │ │
│ │ ├─cron
│ │ │ CronServer.java
│ │ │
│ │ ├─enums
│ │ │ CipherMode.java 算法枚举
│ │ │ Scenario.java 场景枚举
│ │ │
│ │ ├─generator
│ │ │ GeneratorSecretKey.java 密钥生成代理接口
│ │ │
│ │ ├─handler
│ │ │ ExecutorPostProcessor.java
│ │ │ ScenarioEncryptSchedule.java 场景调度
│ │ │ ScenarioHandler.java 场景处理
│ │ │ ScenarioHolder.java 核心容器
│ │ │ ScenarioPostProcessor.java
│ │ │ ScenarioSchedule.java 场景调度实现类
│ │ │ StorageScenario.java 存储场景
│ │ │ TransmitScenario.java 传输场景
│ │ │
│ │ ├─register
│ │ │ RegisterBeanDefinition.java 注册密钥生成代理类 工厂模式
│ │ │
│ │ ├─spel
│ │ │ SpELExpressionHandler.java spel表达式处理类
│ │ │ SpELParserContext.java
│ │ │
│ │ └─util
│ │ EncryptUtils.java 工具类
```
## 使用说明
1. 导入maven坐标
```xml
cloud.longfa
encrypt-spring-boot-starter
1.0.5-RELEASE
```
## 配置说明
```yaml
badger:
encrypt:
#16字节 1byte = 8bit
aes-iv: 2404308462934f9f
#128/192/256 bits 16/24/32/ 字节
aes-key: c4a98b23a8d94035bc9e0896b620b6a7
public-key-base64: xxx #rsa加密算法公钥
private-key-base64: xxx #rsa加密算法私钥
sm4-key: xxxxxx #长度为16个字节
sm4-iv: xxxxxxx #长度为16个字节
```
## 注解参数说明
- > 在启动类上标注 **@EnableEncrypt** 注解 表示 启用加密模块
- 加密注解:**@Encrypt**
- 解密注解:**@Decypt**
- 字段注解:**@Badger**
**加解密参数一样**
1、scenario
scenario值为枚举类型
```java
/**
* The enum Scenario.
* @author : longfa
* @email : longfa0130@gmail.com
* @description : 应用场景 网络接传输 、存储
* @since : 1.0.0
*/
public enum Scenario{
/**
* Transmit scenario.
*/
transmit, //传输
/**
* Storage scenario.
*/
storage, //存储
}
```
2 cipher
cipher值为枚举类型
```java
/**
* The enum Cipher mode.
*
* @author : longfa
* @email : longfa0130@gmail.com
* @description : 加密模式
* @since : 1.0.0
*/
public enum CipherMode {
/**
* Aes cipher mode.
*/
AES,
/**
* Rsa cipher mode.
*/
RSA,
/**
* Sm 4 cipher mode.
*/
SM4,
/**
* 混合加密 AES_RSA
*/
AES_RSA,
/**
*混合加密 SM4_RSA
*/
SM4_RSA,
/**
* 该值不能用于 @Encrypt @Decrypt注解 这用于 @Badger
* 如果为DEFAULT 则会使用@Encrypt 或者@Decrypt的加密模式 @Badger注解的默认值为DEFAULT
* 你可以切换成其他支持的属性 比如AES RSA SM4 或者 混合加密方式
*/
DEFAULT,
}
```
3 caseSensitive其值未做处理 所以不用设置 默认不区分大小写
4 fields
fields 值为数组类型 加密的字段名(多个)
```java
/**
* 加密的字段名方法加密需要指定字段名称 默认是对data字段解密
*
* @return the string [ ]
*/
String[] fields() default {"data"};
@RequestMapping("/efj")
@Decrypt(fields = {"password","card","address"},cipher = CipherMode.RSA,scenario = Scenario.transmit)
public Map> test1(@RequestBody Map> map){
return map;
}
Test类
public class Test implements Cloneable{
private String username;
private String password;
private String email;
private String phone;
private String address;
private String card;
```
5 value spel 表达式 已经经过加工 简单应用 @[beanName].[方法方法/常量名]
```java
/**
* SpEL表达式 对SpEL表达式的支持
* * @beanName.method or @beanName.field the field not be -> private decorated
* * @ss.abc() @ss.name
*
* @return the string
*/
String value() default "";
```
6 dynamic 动态属性
使用规则 结合混合加密算法使用 否则不生效
```java
/**
* 动态密钥 支持混合算法 sm4-rsa aes-rsa {@CipherMode}
* @return the boolean
*/
boolean dynamic() default false;
```
## 使用教程
启动类上标注 @EnableEncrypt
```java
@EnableEncrypt //启动该模块 不标注不生效!!!
@SpringBootApplication
public class TestApplication {
public static void main(String[] args) {
SpringApplication.run(TestApplication.class, args);
}
}
```
### (一) 、传输场景案例
*非混合加密模式*
#### 1.1 **简单易用法**
*@Encrypt 安装字段进行加解密 属性: fields = {"username","password"} 不光是对字段名生效 参数也生效* AES加密 那么就用AES解密
实体类
```java
public class Test implements Cloneable{
private String username;
private String password;
private String email;
private String phone;
private String address;
```
控制器
```java
xxxController //控制器
//传输加密 @ENC.SYSTEM_USER 同等 Fields.SYS_USER 同等 @ENC.custom()
@GetMapping("/aaa")
@Encrypt( fields = {"username","password"},cipher = CipherMode.AES,scenario = Scenario.transmit)
public Map> getTest1(){
return queryData(); //模拟100条数据
}
private Map> queryData(){
Map> stringListHashMap = new HashMap<>();
Test testF = new Test();
List testList = new ArrayList<>();
for (int i = 0; i < 2; i++) {
Test test = testF.clone();
test.setUsername("少林寺张三丰"+new Random().nextFloat());
test.setPassword("密码8个8 你来破解啊"+ UUID.randomUUID());
test.setAddress("xx省xx市xxx");
test.setEmail("longfaxxxx@163.com");
test.setPhone("18886137xxx");
test.setCard("xxx6xx19xx01306xxx");
testList.add(test);
}
stringListHashMap.put("data",testList);
return stringListHashMap;
}
```
**如果解密呢???**
xxx控制器
```java
//传输解密
@PostMapping("/bbb")
@Decrypt(fields = {"username","password"},cipher = CipherMode.AES,scenario = Scenario.transmit)
public Map> test1(@RequestBody Map> map){
return map;
}
```
#### 1.2 spel表达式
@Encrypt 注解属性:value = "@类名.方法" 跟fields属性一样 方法返回的必须是数组 也是返回待加密的字段 {"username","password"}
```java
xxxController //控制器
//传输加密 @ENC.SYSTEM_USER 同等 Fields.SYS_USER 同等 @ENC.custom()
//ta们最终返回的是数组 {"username","password"} 不用好奇 用了模板解析
@GetMapping("/aaa")
@Encrypt(value ="@ENC.SYSTEM_USER",cipher = CipherMode.RSA,scenario = Scenario.transmit)
public Map> getTest1(){
return queryData(); //模拟的数据
}
```
#### 1.3 @Badger
@Badger 标注在需要加密的字段上
属性只有一个:
```java
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Badger {
/**
* 默认加密方式 AES算法加密 DEFAULT则会根据@Encrypt 或者@Decrypt cipher 的值
*
* @return {@link CipherMode}
*/
CipherMode cipher() default CipherMode.DEFAULT;
}
```
跟@Encrypt @Decrypt 上的一个属性一模一样
如果你修改了默认值CipherMode.DEFAULT 则会用@Badger注解上的为准
**每一个字段每一种加密算法 会出现上面后果呢???**
不用担心会导致多层加密 它会根据你选择的加密算法来加密该字段
实体类
```java
@Badger(cipher = CipherMode.SM4)
private String phone;
@Badger(cipher = CipherMode.RSA)
private String address;
```
控制器
```java
@GetMapping("/aaa")
@Encrypt(cipher = CipherMode.SM4,scenario = Scenario.transmit)
public Map> getTest1(){
return queryData();
}
```
#### 1.4 每个字段每一种加密算法
```java
@Badger(cipher = CipherMode.AES)
private String email;
@Badger(cipher = CipherMode.SM4)
private String phone;
@Badger(cipher = CipherMode.RSA)
private String address;
```
#### 1.5 无敌模式
```java
//xxx控制器
@GetMapping("/aaa")
@Encrypt(value =SPEL.SYS_USER,fileds={"username","password"},cipher = CipherMode.RSA,scenario = Scenario.transmit)
public Map> getTest1(){
return queryData();
}
```
```java
//xxx 实体类
private String username;
private String password;
@Badger(cipher = CipherMode.AES)
private String email;
@Badger(cipher = CipherMode.SM4)
private String phone;
@Badger(cipher = CipherMode.RSA)
private String address;
```
放心 这种方式也是支持的!!!!
#### 1.6 解密
```java
//xxx控制器
//传输解密
@PostMapping("/bbb")
@Decrypt(value = SPEL.SYS_USER,cipher = CipherMode.SM4,scenario = Scenario.transmit)
public Map> test1(@RequestBody Map> map){
return map;
}
// value 属性 就是类名.变量 前提是这个变量 类能访问得到
@Component("ENC")
public class SPEL {
//1 系统用户
public static final String SYS_USER = "@ENC.SYSTEM_USER";
public static final String[] SYSTEM_USER = {"email","password"};
//xxx实体类
private String username;
@Badger //默认 跟随上级 @Decrypt所指得加密算法
private String password;
@Badger(cipher = CipherMode.AES) //这个字段用AES加密算法
private String email;
@Badger(cipher = CipherMode.SM4) //这个字段用SM4加密算法
private String phone;
@Badger(cipher = CipherMode.RSA) //这个字段用RSA加密算法
private String address;
private String card;
```
### (二)、混合加密
#### 2.1 传输场景-混合加密
```java
//传输加密 模拟从service获取数据 @ENC.SYSTEM_USER 同等 Fields.SYS_USER 同等 @ENC.custom() 等同于使用@Badger该注解进行标识
// 更推荐 "@ENC.SYSTEM_USER" @Badger 这种写法 支持任意的请求方式 支持多属性混合使用 value fields 注解同时使用 不仅仅是支持web容器
//支持rpc远程调用加解密 @Badger 的值默认就是跟随@Encrypt的加密模式 你可以指定某一个字段用何种加密模式 可以混合使用
//dynamic = true 则你的cipher参数必须也是支持动态密钥的 仅支持SM4-RSA AES-RSA 两种混合模式
//dynamic = true 每一次的密钥都是变化的 你可以通过 HoneyBadgerEncrypt 实例获取变化后的密钥 推荐使用过滤器
@GetMapping("/aaa")
@Encrypt(value =SPEL.SYS_USER,cipher = CipherMode.SM4_RSA,scenario = Scenario.transmit)
public Map> getTest1(){
return queryData();
}
//实体类
@Badger
private String username;
@Badger
private String password;
@Badger
private String email;
```
*仅支持SM4-RSA AES-RSA 两种混合模式*
RSA加密AES 或者是SM4的密钥
获取RSA加密后的AES 、SM4密钥
```java
/**
* @author : longfa
* @email : longfa0130@gmail.com
* @description : 案例
* @since : 1.0.0
*/
@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {
public static String AESKEY = "AES-RSA";
public static String SM4KEY = "SM4-RSA";
@Override
public boolean supports(MethodParameter returnType, Class converterType) {
return true;
}
@Nullable
@Override
public Object beforeBodyWrite(@Nullable Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
// 拿到密钥 设置到响应头 前端获取 通过RSA解密获取AES密钥 再通过AES解密器对密文解密
response.getHeaders().set(AESKEY, HoneyBadgerEncrypt.getAesKeyRSACiphertext());
//拿到密钥 设置到响应头 前端获取 通过RSA解密获取SM4密钥 再通过SM4解密器对密文解密
response.getHeaders().set(SM4KEY,HoneyBadgerEncrypt.getSm4KeyRSACiphertext());
return body;
}
}
```
#### 2.2 前端传过来的密钥怎么接收???
*不是随机密钥 自然不用去配置!!!!*
做个判断即可
```java
/**
* @author : longfa
* @email : longfa0130@gmail.com
* @description : 案例
* @since : 1.0.0
*/
@Component
public class xxxxxxxxx extends OncePerRequestFilter {
public static String AESKEY = "AES-RSA";
public static String SM4KEY = "SM4-RSA";
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String aesKey = request.getHeader(AESKEY);
String sm4Key = request.getHeader(SM4KEY);
if (StringUtils.hasText(aesKey)){ //判断一 四行代码 花不了多少时间 复制粘贴就行了 异常处理还没有做!!!
HoneyBadgerEncrypt.setRSACiphertextForAESKey(aesKey);
}
if (StringUtils.hasText(sm4Key)){ //判断二
HoneyBadgerEncrypt.setRSACiphertextForSM4Key(sm4Key);
}
filterChain.doFilter(request,response);
}
}
```
*基本上复制粘贴就完工了!!!*
#### 2.2 混合解密之随机密钥
跟上面一样 区别在于 密钥会动态生成 dynamic 属性设置为true就行了
```java
@GetMapping("/aaa")
@Encrypt(value =SPEL.SYS_USER,cipher = CipherMode.SM4_RSA,scenario = Scenario.transmit,dynamic = true)
public Map> getTest1(){
return queryData();
}
```
### (三) 存储场景案例
传输场景你会了 那么存储场景就是so easy!!! 设置 scenario = Scenario.storage
```java
xxxController //控制器
//传输加密 @ENC.SYSTEM_USER 同等 Fields.SYS_USER 同等 @ENC.custom() 你用注解标注字段可以 怎么方便怎么用
@GetMapping("/aaa")
@Encrypt(value ="@ENC.SYSTEM_USER",cipher = CipherMode.RSA,scenario = Scenario.storage)
public Map> getTest1(){
return queryData(); //模拟的数据
}
//传输解密
@PostMapping("/bbb")
@Decrypt(value = SPEL.SYS_USER,cipher = CipherMode.RSA,scenario = Scenario.transmit)
public Map> test1(@RequestBody Map> map){
return map;
}
//类名ENC 配合spel表达式使用 更方便
// 比如 value= "@ENC.SYSTEM_USER" 经过加密框架解析后的值: {"address","username","email","password"}
// 同上来讲就是方法调用 你可以写成 类名.常量 类名.方法
@Component("ENC")
public class SPEL {
//1 系统用户
public static final String SYS_USER = "@ENC.SYSTEM_USER";
//1 待加密字段 地址、用户名、邮箱、密码
public static final String[] SYSTEM_USER = {"address","username","email","password"};
//1
public String[] custom(){
return new String[]{"address","username","email"};
}
}
//测试类 service层 模拟存储至数据库 从数据库取出数据 的加解密过程
@Service("testService")
public class TestService {
//or value = "@ENCRYPT.ADMIN_USER", 同等 Fields.ADM_USER
@Encrypt(value = SPEL.ADM_USER,cipher = CipherMode.AES,scenario = Scenario.storage)
@Decrypt(value = "@ENC.ADMIN_USER",cipher = CipherMode.AES,scenario = Scenario.storage)
public List testList(List testList, HttpServletRequest request, HttpServletResponse response){
System.out.println(testList+"\n加密了");
return testList;
}
}
```
## 参与贡献
写的潦草 您有好的想法或者意见 欢迎提出来 一同完善!!!
## 性能
cpu:轻薄本 i7 8550u
混合加密 8万条数据 耗时 2.5秒左右 解密 1.8秒 没有出现栈内存溢出这种极端的情况
作者:longfa email:longfa0130@163.com || longfa0130@gmail.com