Java 中 RSA 工具类
Wenhao Wang 2020-07-23 RSA
Java 中使用 RSA 的工具类
# RSAUtil
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.ResourceUtils;
import javax.crypto.Cipher;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author wwh
* @date 2019/11/7 17:40
* @description
*/
public class RSAUtil {
public static final String ALGORITHM = "RSA";
/**
* 生成的公钥文件名称
*/
public static final String PUBLIC_KEY_NAME = "public.key";
/**
* 生成的私钥文件名称
*/
public static final String PRIVATE_KEY_NAME = "private.key";
/**
* Key文件存放目录
*/
public static final String KEY_PATH = "key";
/**
* 指定生成多少位的密钥
*/
private static final int KEY_BIT = 2048;
/**
* RSA最大加密明文大小
* 1024位的密钥要改成117,2048位的是245
*/
private static final int MAX_ENCRYPT_BLOCK = 245;
/**
* RSA最大解密密文大小
* 1024位的密钥要改成128,2048位的是256
*/
private static final int MAX_DECRYPT_BLOCK = 256;
private static final Map<String, String> KEY_MAP = new ConcurrentHashMap<>(2);
/**
* 签名算法
*/
// public static final String SIGNATURE_ALGORITHM = "MD5withRSA";
// public static final String SIGNATURE_ALGORITHM = "SHA1withRSA";
public static final String SIGNATURE_ALGORITHM = "SHA256withRSA";
/**
* 生成密钥对:密钥对中包含公钥和私钥
*
* @return 包含 RSA 公钥与私钥的 keyPair
* @throws NoSuchAlgorithmException NoSuchAlgorithmException
*/
public static KeyPair generateKeyPair() throws NoSuchAlgorithmException {
// 获得RSA密钥对的生成器实例
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM);
// 获得一个安全的随机数
SecureRandom secureRandom = new SecureRandom(String.valueOf(System.currentTimeMillis()).getBytes(StandardCharsets.UTF_8));
// 这里可以是1024、2048 初始化一个密钥对
keyPairGenerator.initialize(KEY_BIT, secureRandom);
// 获得密钥对
return keyPairGenerator.generateKeyPair();
}
/**
* 生成密钥对写入到文件
*
* @throws NoSuchAlgorithmException NoSuchAlgorithmException
*/
public static void generateKeyPair(String privateKeyName, String publicKeyName, String keyPath) throws NoSuchAlgorithmException, IOException {
KeyPair keyPair = generateKeyPair();
String privateKey = getPrivateKey(keyPair);
writeFile(keyPath + File.separator + privateKeyName, privateKey.getBytes(StandardCharsets.UTF_8));
String publicKey = getPublicKey(keyPair);
writeFile(keyPath + File.separator + publicKeyName, publicKey.getBytes(StandardCharsets.UTF_8));
}
/**
* 写入key到文件
*
* @param fileName key文件名称
* @param data key内容
* @throws IOException IOException
*/
private static void writeFile(String fileName, byte[] data) throws IOException {
if (Files.notExists(Paths.get(fileName))) {
Files.createFile(Paths.get(fileName));
}
try (RandomAccessFile rw = new RandomAccessFile(fileName, "rw")) {
rw.write(data, 0, data.length);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 获取公钥 (并进行 Base64 编码,返回一个 Base64 编码后的字符串)
*
* @param keyPair:RSA 密钥对
* @return 返回一个 Base64 编码后的公钥字符串
*/
public static String getPublicKey(KeyPair keyPair) {
PublicKey publicKey = keyPair.getPublic();
byte[] bytes = publicKey.getEncoded();
return Base64.getEncoder().encodeToString(bytes);
}
/**
* 从文件中读取公钥
*
* @param publicKeyName 公钥文件名称
* @return 公钥 BASE64编码
*/
public static String getPublicKey(String publicKeyName) {
return KEY_MAP.computeIfAbsent(PUBLIC_KEY_NAME, key -> readFile(publicKeyName));
}
/**
* 从文件中读取私钥
*
* @param privateKeyName 私钥文件名称
* @return 私钥 BASE64编码
*/
public static String getPrivateKey(String privateKeyName) {
return KEY_MAP.computeIfAbsent(PRIVATE_KEY_NAME, key -> readFile(privateKeyName));
}
/**
* 写入key文件
*
* @param keyName key文件名称
* @return key
*/
private static String readFile(String keyName) {
try (InputStream inputStream = new ClassPathResource(KEY_PATH + File.separator + keyName).getInputStream();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
byte[] buffer = new byte[1024];
int len;
while ((len = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, len);
}
return outputStream.toString(StandardCharsets.UTF_8.name());
} catch (IOException e) {
e.printStackTrace();
System.exit(0);
}
return null;
}
/**
* 获取私钥(并进行Base64编码,返回一个 Base64 编码后的字符串)
*
* @param keyPair:RSA 密钥对
* @return 返回一个 Base64 编码后的私钥字符串
*/
public static String getPrivateKey(KeyPair keyPair) {
PrivateKey privateKey = keyPair.getPrivate();
byte[] bytes = privateKey.getEncoded();
return Base64.getEncoder().encodeToString(bytes);
}
/**
* 将 Base64 编码后的公钥转换成 PublicKey 对象
*
* @param publicKey:Base64 编码后的公钥字符串
* @return PublicKey publicKey
*/
public static PublicKey string2PublicKey(String publicKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
byte[] bytes = Base64.getDecoder().decode(publicKey);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes);
KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
return keyFactory.generatePublic(keySpec);
}
/**
* 将 Base64 码后的私钥转换成 PrivateKey 对象
*
* @param privateKey Base64 编码后的私钥字符串
* @return PrivateKey privateKey
*/
public static PrivateKey string2PrivateKey(String privateKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
byte[] bytes = Base64.getDecoder().decode(privateKey);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(bytes);
KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
return keyFactory.generatePrivate(keySpec);
}
/**
* 使用私钥分段加密
*
* @param data 要加密的数据
* @param privateKey 私钥
* @return 加密后的数据 BASE64编码
*/
public static byte[] encrypt(byte[] data, PrivateKey privateKey) throws GeneralSecurityException, IOException {
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
return Base64.getEncoder().encode(segment(data, cipher, MAX_ENCRYPT_BLOCK));
}
/**
* 使用私钥分段加密
*
* @param data 要加密的数据
* @param privateKey 私钥
* @return 加密后的数据 BASE64编码
*/
public static String encrypt(String data, PrivateKey privateKey) throws GeneralSecurityException, IOException {
byte[] encrypt = encrypt(data.getBytes(StandardCharsets.UTF_8), privateKey);
return new String(encrypt);
}
/**
* 使用公钥分段加密
*
* @param data 要加密的数据
* @param publicKey 公钥
* @return 加密后的数据
*/
public static byte[] encrypt(byte[] data, PublicKey publicKey) throws GeneralSecurityException, IOException {
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return Base64.getEncoder().encode(segment(data, cipher, MAX_ENCRYPT_BLOCK));
}
/**
* 使用公钥分段加密
*
* @param data 要加密的数据
* @param publicKey 公钥
* @return 加密后的数据 BASE64编码
*/
public static String encrypt(String data, PublicKey publicKey) throws GeneralSecurityException, IOException {
byte[] encrypt = encrypt(data.getBytes(StandardCharsets.UTF_8), publicKey);
return new String(encrypt);
}
/**
* 使用公钥/私钥分段加密
*
* @param data 要加密的数据
* @param secretKey 秘钥
* @param keyType 秘钥类型
* @return 加密后的数据 BASE64编码
*/
public static String encrypt(String data, String secretKey, KeyType keyType) throws GeneralSecurityException, IOException {
byte[] encrypt;
if (Objects.equals(KeyType.PRIVATE_KEY, keyType)) {
encrypt = encrypt(data.getBytes(StandardCharsets.UTF_8), string2PrivateKey(secretKey));
return new String(encrypt);
}
if (Objects.equals(KeyType.PUBLIC_KEY, keyType)) {
encrypt = encrypt(data.getBytes(StandardCharsets.UTF_8), string2PrivateKey(secretKey));
return new String(encrypt);
}
return null;
}
/**
* 使用私钥分段解密
*
* @param data 要解密的数据
* @param privateKey 私钥
* @return 解密后的数据
*/
public static byte[] decrypt(byte[] data, PrivateKey privateKey) throws GeneralSecurityException, IOException {
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return segment(Base64.getDecoder().decode(data), cipher, MAX_DECRYPT_BLOCK);
}
/**
* 使用私钥分段解密
*
* @param data 要解密的数据 BASE64编码
* @param privateKey 私钥
* @return 解密后的数据
*/
public static String decrypt(String data, PrivateKey privateKey) throws GeneralSecurityException, IOException {
byte[] encrypt = decrypt(data.getBytes(StandardCharsets.UTF_8), privateKey);
return new String(encrypt);
}
/**
* 使用公钥分段解密
*
* @param data 要解密的数据
* @param publicKey 公钥
* @return 解密后的数据
*/
public static byte[] decrypt(byte[] data, PublicKey publicKey) throws GeneralSecurityException, IOException {
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, publicKey);
return segment(Base64.getDecoder().decode(data), cipher, MAX_DECRYPT_BLOCK);
}
/**
* 使用公钥分段解密
*
* @param data 要解密的数据 BASE64编码
* @param publicKey 公钥
* @return 解密后的数据
*/
public static String decrypt(String data, PublicKey publicKey) throws GeneralSecurityException, IOException {
byte[] encrypt = decrypt(data.getBytes(StandardCharsets.UTF_8), publicKey);
return new String(encrypt);
}
/**
* 使用公钥/私钥分段解密
*
* @param data 要解密的数据 BASE64编码
* @param secretKey 秘钥
* @param keyType 秘钥类型
* @return 解密后的数据
*/
public static String decrypt(String data, String secretKey, KeyType keyType) throws GeneralSecurityException, IOException {
byte[] encrypt;
if (Objects.equals(KeyType.PUBLIC_KEY, keyType)) {
encrypt = decrypt(data.getBytes(StandardCharsets.UTF_8), string2PublicKey(secretKey));
return new String(encrypt);
}
if (Objects.equals(KeyType.PRIVATE_KEY, keyType)) {
encrypt = decrypt(data.getBytes(StandardCharsets.UTF_8), string2PrivateKey(secretKey));
return new String(encrypt);
}
return null;
}
/**
* 分段进行加密/解密
*
* @param data 要加密/解密的数据
* @param cipher cipher 实例
* @param maxBlock 分段加密块的大小
* @return 加密/解密后的数据
* @throws GeneralSecurityException GeneralSecurityException
* @throws IOException IOException
*/
private static byte[] segment(byte[] data, Cipher cipher, int maxBlock) throws GeneralSecurityException, IOException {
int dataLength = data.length;
int offset = 0;
byte[] cache;
int i = 0;
try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
// 数据分段加密
while (dataLength - offset > 0) {
if (dataLength - offset > maxBlock) {
cache = cipher.doFinal(data, offset, maxBlock);
} else {
cache = cipher.doFinal(data, offset, dataLength - offset);
}
out.write(cache, 0, cache.length);
++i;
offset = i * maxBlock;
}
return out.toByteArray();
}
}
/**
* 签名
*
* @param data 要签名的数据
* @param privateKey 私钥
* @return 签名 BASE编码
* @throws GeneralSecurityException GeneralSecurityException
*/
public static byte[] sign(byte[] data, PrivateKey privateKey) throws GeneralSecurityException {
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
signature.initSign(privateKey);
signature.update(data);
return Base64.getEncoder().encode(signature.sign());
}
/**
* 签名
*
* @param data 要签名的数据
* @param privateKey 私钥
* @return 签名 BASE编码
* @throws GeneralSecurityException GeneralSecurityException
*/
public static String sign(String data, PrivateKey privateKey) throws GeneralSecurityException {
byte[] sign = sign(data.getBytes(StandardCharsets.UTF_8), privateKey);
return new String(sign);
}
/**
* 签名
*
* @param data 要签名的数据
* @param privateKey 私钥
* @return 签名 BASE编码
* @throws GeneralSecurityException GeneralSecurityException
*/
public static String sign(String data, String privateKey) throws GeneralSecurityException {
if (Objects.isNull(data) || Objects.isNull(privateKey)) {
return null;
}
byte[] sign = sign(data.getBytes(StandardCharsets.UTF_8), string2PrivateKey(privateKey));
return new String(sign);
}
/**
* 验签
*
* @param data 私钥加密后的数据 BASE64编码
* @param sign 私钥签名 BASE64编码
* @param publicKey 公钥
* @return true-合法签名 false-非法签名
*/
public static boolean verify(byte[] data, String sign, PublicKey publicKey) throws GeneralSecurityException {
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
signature.initVerify(publicKey);
signature.update(data);
return signature.verify(Base64.getDecoder().decode(sign));
}
/**
* 验签
*
* @param data 私钥加密后的数据 BASE64编码
* @param sign 私钥签名 BASE64编码
* @param publicKey 公钥
* @return true-合法签名 false-非法签名
*/
public static boolean verify(String data, String sign, PublicKey publicKey) throws GeneralSecurityException {
return verify(data.getBytes(StandardCharsets.UTF_8), sign, publicKey);
}
/**
* 验签
*
* @param data 私钥加密后的数据 BASE64编码
* @param sign 私钥签名 BASE64编码
* @param publicKey 公钥
* @return true-合法签名 false-非法签名
*/
public static boolean verify(String data, String sign, String publicKey) throws GeneralSecurityException {
if (Objects.isNull(data) || Objects.isNull(sign) || Objects.isNull(publicKey)) {
return false;
}
return verify(data.getBytes(StandardCharsets.UTF_8), sign, string2PublicKey(publicKey));
}
/**
* key类型
*/
public enum KeyType {
/**
* 公钥
*/
PUBLIC_KEY,
/**
* 私钥
*/
PRIVATE_KEY
}
public static void main(String[] args) throws NoSuchAlgorithmException, IOException {
// 在项目根目录生成key
File path = ResourceUtils.getFile(KEY_PATH);
if (!path.exists()) {
boolean mkdir = path.mkdir();
}
generateKeyPair(PUBLIC_KEY_NAME, PRIVATE_KEY_NAME, KEY_PATH);
}
}
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
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
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
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492