注解实现字段自动解密

最近有个项目要传输密码,密码当然不能明文传输。需要前端加密,后端解密。
加密算法使用 RSA。

使用注解加 AOP 实现

RSA 工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
import javax.crypto.Cipher;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import java.util.Base64;

/**
* @author chaoli
* @date 2020-07-09 10:45
* @Description
**/
public class RSAUtil {

//非对称密钥算法
private static final String KEY_ALGORITHM = "RSA";
//密钥长度,在512到65536位之间,建议不要太长,否则速度很慢,生成的加密数据很长
private static final int KEY_SIZE = 512;
//字符编码
private static final String CHARSET = "UTF-8";

/**
* 生成密钥对
*
* @return KeyPair 密钥对
*/
public static KeyPair getKeyPair() throws Exception {
return getKeyPair(null);
}

/**
* 生成密钥对
* @param password 生成密钥对的密码
* @return
* @throws Exception
*/
public static KeyPair getKeyPair(String password) throws Exception {
//实例化密钥生成器
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM);
//初始化密钥生成器
if(password == null){
keyPairGenerator.initialize(KEY_SIZE);
}else {
SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
secureRandom.setSeed(password.getBytes(CHARSET));
keyPairGenerator.initialize(KEY_SIZE, secureRandom);
}
//生成密钥对
return keyPairGenerator.generateKeyPair();
}

/**
* 取得私钥
*
* @param keyPair 密钥对
* @return byte[] 私钥
*/
public static byte[] getPrivateKeyBytes(KeyPair keyPair) {
return keyPair.getPrivate().getEncoded();
}

/**
* 取得Base64编码的私钥
*
* @param keyPair 密钥对
* @return String Base64编码的私钥
*/
public static String getPrivateKey(KeyPair keyPair) {
return Base64.getEncoder().encodeToString(getPrivateKeyBytes(keyPair));
}

/**
* 取得公钥
*
* @param keyPair 密钥对
* @return byte[] 公钥
*/
public static byte[] getPublicKeyBytes(KeyPair keyPair) {
return keyPair.getPublic().getEncoded();
}

/**
* 取得Base64编码的公钥
*
* @param keyPair 密钥对
* @return String Base64编码的公钥
*/
public static String getPublicKey(KeyPair keyPair) {
return Base64.getEncoder().encodeToString(getPublicKeyBytes(keyPair));
}

/**
* 私钥加密
*
* @param data 待加密数据
* @param privateKey 私钥字节数组
* @return byte[] 加密数据
*/
public static byte[] encryptByPrivateKey(byte[] data, byte[] privateKey) throws Exception {
//实例化密钥工厂
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
//生成私钥
PrivateKey key = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(privateKey));
//数据加密
Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, key);
return cipher.doFinal(data);
}

/**
* 私钥加密
*
* @param data 待加密数据
* @param privateKey Base64编码的私钥
* @return String Base64编码的加密数据
*/
public static String encryptByPrivateKey(String data, String privateKey) throws Exception {
byte[] key = Base64.getDecoder().decode(privateKey);
return Base64.getEncoder().encodeToString(encryptByPrivateKey(data.getBytes(CHARSET), key));
}

/**
* 公钥加密
*
* @param data 待加密数据
* @param publicKey 公钥字节数组
* @return byte[] 加密数据
*/
public static byte[] encryptByPublicKey(byte[] data, byte[] publicKey) throws Exception {
//实例化密钥工厂
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
//生成公钥
PublicKey key = keyFactory.generatePublic(new X509EncodedKeySpec(publicKey));
//数据加密
Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, key);
return cipher.doFinal(data);
}

/**
* 公钥加密
*
* @param data 待加密数据
* @param publicKey Base64编码的公钥
* @return String Base64编码的加密数据
*/
public static String encryptByPublicKey(String data, String publicKey) throws Exception {
byte[] key = Base64.getDecoder().decode(publicKey);
return Base64.getEncoder().encodeToString(encryptByPublicKey(data.getBytes(CHARSET), key));
}

/**
* 私钥解密
*
* @param data 待解密数据
* @param privateKey 私钥字节数组
* @return byte[] 解密数据
*/
public static byte[] decryptByPrivateKey(byte[] data, byte[] privateKey) throws Exception {
//实例化密钥工厂
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
//生成私钥
PrivateKey key = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(privateKey));
//数据解密
Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, key);
return cipher.doFinal(data);
}

/**
* 私钥解密
*
* @param data Base64编码的待解密数据
* @param privateKey Base64编码的私钥
* @return String 解密数据
*/
public static String decryptByPrivateKey(String data, String privateKey) throws Exception {
byte[] key = Base64.getDecoder().decode(privateKey);
return new String(decryptByPrivateKey(Base64.getDecoder().decode(data), key), CHARSET);
}

/**
* 公钥解密
*
* @param data 待解密数据
* @param publicKey 公钥字节数组
* @return byte[] 解密数据
*/
public static byte[] decryptByPublicKey(byte[] data, byte[] publicKey) throws Exception {
//实例化密钥工厂
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
//产生公钥
PublicKey key = keyFactory.generatePublic(new X509EncodedKeySpec(publicKey));
//数据解密
Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, key);
return cipher.doFinal(data);
}

/**
* 公钥解密
*
* @param data Base64编码的待解密数据
* @param publicKey Base64编码的公钥
* @return String 解密数据
*/
public static String decryptByPublicKey(String data, String publicKey) throws Exception {
byte[] key = Base64.getDecoder().decode(publicKey);
return new String(decryptByPublicKey(Base64.getDecoder().decode(data), key), CHARSET);
}

/**
* 测试加解密方法
*
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
//生成密钥对,一般生成之后可以放到配置文件中
KeyPair keyPair = RSAUtil.getKeyPair();
//公钥
String publicKey = RSAUtil.getPublicKey(keyPair);
//私钥
String privateKey = RSAUtil.getPrivateKey(keyPair);

System.out.println("公钥:\n" + publicKey);
System.out.println("私钥:\n" + privateKey);

String data = "123321";
{
System.out.println("\n===========私钥加密,公钥解密==============");
String s1 = RSAUtil.encryptByPrivateKey(data, privateKey);
System.out.println("加密后的数据:" + s1);
String s2 = RSAUtil.decryptByPublicKey(s1, publicKey);
System.out.println("解密后的数据:" + s2 + "\n\n");
}

{
System.out.println("\n===========公钥加密,私钥解密==============");
String s1 = RSAUtil.encryptByPublicKey(data, publicKey);
System.out.println("加密后的数据:" + s1);
String s2 = RSAUtil.decryptByPrivateKey(s1, privateKey);
System.out.println("解密后的数据:" + s2 + "\n\n");
}

}
}

字段注解

1
2
3
4
5
6
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RSAField {
}

方法注解

1
2
3
4
5
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)//声明此注解生命周期 使用runtime可以在运行时动态获得注解信息
@Documented
public @interface RSAMethod {
}

AOP 实现。
代理所有加了 RSAMethod 注解的方法,遍历所有参数对象的字段,如果字段有 RSAField 注解,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
@Component
@Aspect
@Slf4j
public class EncryptDecryptAop {

@Value("${privateKey}")
private String privateKey;

@Pointcut("@annotation(xx.xx.xx.xx.RSAMethod)")
public void annotationPointCut() {
}

@Around("annotationPointCut()")
public Object doProcess(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
//捕获方法参数列表
List<Object> methodArgs = this.getMethodArgs(proceedingJoinPoint);
//循环所有参数
for (Object item : methodArgs) {
//捕获参数类中的所有字段
Field[] fields = item.getClass().getDeclaredFields();
//遍历所有字段
for (Field field : fields) {
//若该字段被EncryptField注解,则进行加密
if (null != AnnotationUtils.findAnnotation(field, RSAField.class)) {
String raw = null;
try {
//设置private类型允许访问
field.setAccessible(Boolean.TRUE);
raw = field.get(item).toString();
} catch (Exception e) {
continue;
}
if (raw == null || raw.isEmpty()) {
continue;
}
// log.info("{}解密前{}", field.getName(), raw);
String decrypt = null;
try {
//解密
decrypt = RSAUtil.decryptByPrivateKey(raw, privateKey);
} catch (Exception e) {
log.warn("RAS解密失败{}", field.getName());
// throw new ServiceException(ErrorEnums.PARAM_ERROR.getCode(), "加密解密失败");
}
field.set(item, decrypt);
// log.info("{}解密后{}", field.getName(), field.get(item).toString());
field.setAccessible(Boolean.FALSE);
}
}
}
return proceedingJoinPoint.proceed();
}

/**
* 获取方法请求参数
*/
private List<Object> getMethodArgs(ProceedingJoinPoint proceedingJoinPoint) {
List<Object> methodArgs = Lists.newArrayList();
for (Object arg : proceedingJoinPoint.getArgs()) {
if (null != arg) {
methodArgs.add(arg);
}
}
return methodArgs;
}
}


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!