1.背景
RSA加密对加密的内容是有长度限制的,如果超出了长度限制,就会报错。所以需要采用分段加密,案例如下。
2.代码
1 package com.demo.util;
2
3 import org.apache.commons.codec.binary.Base64;
4 import org.apache.commons.lang3.ArrayUtils;
5
6 import javax.crypto.Cipher;
7 import java.io.ByteArrayOutputStream;
8 import java.net.URLDecoder;
9 import java.net.URLEncoder;
10 import java.nio.charset.StandardCharsets;
11 import java.security.*;
12 import java.security.interfaces.RSAPrivateKey;
13 import java.security.interfaces.RSAPublicKey;
14 import java.security.spec.PKCS8EncodedKeySpec;
15 import java.security.spec.X509EncodedKeySpec;
16 import java.util.HashMap;
17 import java.util.Map;
18
19 /**
20 * @author mingtian
21 * @desc rsa 分段加解密工具类
22 */
23 public final class RsaUtils {
24
25 // RSA最大加密明文大小
26 private static final int MAX_ENCRYPT_BLOCK = 117;
27
28 // RSA最大解密密文大小
29 private static final int MAX_DECRYPT_BLOCK = 128;
30
31 private RsaUtils() {
32 }
33
34 /**
35 * 获取公钥和私钥对,key为公钥,value为私钥
36 *
37 * @return
38 * @throws NoSuchAlgorithmException
39 */
40 public static Map<String, String> genKeyPair() throws NoSuchAlgorithmException {
41 KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
42 keyPairGen.initialize(1024, new SecureRandom());
43 KeyPair keyPair = keyPairGen.generateKeyPair();
44 RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
45 RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
46 String publicKeyString = new String(Base64.encodeBase64(publicKey.getEncoded()), StandardCharsets.UTF_8);
47 String privateKeyString = new String(Base64.encodeBase64(privateKey.getEncoded()), StandardCharsets.UTF_8);
48 Map<String, String> keyPairMap = new HashMap<>();
49 keyPairMap.put("publicKey", publicKeyString);
50 keyPairMap.put("privateKey", privateKeyString);
51 return keyPairMap;
52 }
53
54 /**
55 * 加密
56 *
57 * @param str
58 * @param publicKey
59 * @return
60 * @throws Exception
61 */
62 public static String encrypt(String str, String publicKey) throws Exception {
63 byte[] decoded = Base64.decodeBase64(publicKey);
64 RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
65 Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
66 cipher.init(1, pubKey);
67 // 分段加密
68 // URLEncoder编码解决中文乱码问题
69 byte[] data = URLEncoder.encode(str, "UTF-8").getBytes(StandardCharsets.UTF_8);
70 // 加密时超过117字节就报错。为此采用分段加密的办法来加密
71 byte[] enBytes = null;
72 for (int i = 0; i < data.length; i += MAX_ENCRYPT_BLOCK) {
73 // 注意要使用2的倍数,否则会出现加密后的内容再解密时为乱码
74 byte[] doFinal = cipher.doFinal(ArrayUtils.subarray(data, i, i + MAX_ENCRYPT_BLOCK));
75 enBytes = ArrayUtils.addAll(enBytes, doFinal);
76 }
77 return Base64.encodeBase64String(enBytes);
78 }
79
80 /**
81 * 公钥分段解密
82 *
83 * @param str
84 * @param privateKey
85 * @return
86 * @throws Exception
87 */
88 public static String decrypt(String str, String privateKey) throws Exception {
89 // 获取公钥
90 byte[] decoded = Base64.decodeBase64(privateKey);
91 RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
92 Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
93 cipher.init(2, priKey);
94 byte[] data = Base64.decodeBase64(str.getBytes("UTF-8"));
95
96 // 返回UTF-8编码的解密信息
97 int inputLen = data.length;
98 ByteArrayOutputStream out = new ByteArrayOutputStream();
99 int offSet = 0;
100 byte[] cache;
101 int i = 0;
102 // 对数据分段解密
103 while (inputLen - offSet > 0) {
104 if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
105 cache = cipher.doFinal(data, offSet, MAX_DECRYPT_BLOCK);
106 } else {
107 cache = cipher.doFinal(data, offSet, inputLen - offSet);
108 }
109 out.write(cache, 0, cache.length);
110 i++;
111 offSet = i * 128;
112 }
113 byte[] decryptedData = out.toByteArray();
114 out.close();
115 return URLDecoder.decode(new String(decryptedData, StandardCharsets.UTF_8), String.valueOf(StandardCharsets.UTF_8));
116 }
117 }