需要注意的是RSA加密内容是有长度限制的,1024位密钥可以加密128字节(1024位),不满128字节的使用随机数填充,但是RSA实现中必须要加随机数(11字节以上),所以明文长度最大为117字节,然后剩下的加入随机数。这也产生了每次加密结果每一次都不一样的特点。
如果明文长度超过限制怎么办?
可以分段加密。将明文按117字节分成多段,加密后再拼接起来。由于每一段密文长度都是128字节,所以解密时按照128字节分段解密
RSA加密内容过长导致抛异常javax.crypto.IllegalBlockSizeException: Data must not be longer than 117 bytes......解决方案
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.security.KeyFactory;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
/**
* @author: BUGHZ
* @description: RSA公私钥
* @className: RsaUtils
* @createDate: 2023-07-05 10:22:30
*/
public class RsaUtils {
private static Logger logger= LoggerFactory.getLogger(RsaUtils.class);
// RSA最大加密明文大小
private static final int MAX_ENCRYPT_BLOCK = 117;
// RSA最大解密密文大小
private static final int MAX_DECRYPT_BLOCK = 128;
/**
* 公钥分段加密
*
* @param str
* @param publicKey
* @return
* @throws Exception
*/
public static String publicKeyEncrypt(String str, String publicKey) throws Exception {
byte[] decoded = org.apache.commons.codec.binary.Base64.decodeBase64(publicKey);
RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA")
.generatePublic(new X509EncodedKeySpec(decoded));
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(1, pubKey);
// 分段加密
// URLEncoder编码解决中文乱码问题
byte[] data = URLEncoder.encode(str, "UTF-8").getBytes("UTF-8");
// 加密时超过117字节就报错。为此采用分段加密的办法来加密
byte[] enBytes = null;
for (int i = 0; i < data.length; i += MAX_ENCRYPT_BLOCK) {
// 注意要使用2的倍数,否则会出现加密后的内容再解密时为乱码
byte[] doFinal = cipher.doFinal(ArrayUtils.subarray(data, i, i + MAX_ENCRYPT_BLOCK));
enBytes = ArrayUtils.addAll(enBytes, doFinal);
}
String outStr = org.apache.commons.codec.binary.Base64.encodeBase64String(enBytes);
return outStr;
}
/**
* 私钥分段解密
*
* @param str
* @param privateKey
* @return
* @throws Exception
*/
public static String privateKeyDecrypt(String str, String privateKey) throws Exception {
// 获取公钥
byte[] decoded = org.apache.commons.codec.binary.Base64.decodeBase64(privateKey);
RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA")
.generatePrivate(new PKCS8EncodedKeySpec(decoded));
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(2, priKey);
byte[] data = org.apache.commons.codec.binary.Base64.decodeBase64(str.getBytes("UTF-8"));
// 返回UTF-8编码的解密信息
int inputLen = data.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] cache;
int i = 0;
// 对数据分段解密
while (inputLen - offSet > 0) {
if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
cache = cipher.doFinal(data, offSet, MAX_DECRYPT_BLOCK);
} else {
cache = cipher.doFinal(data, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
offSet = i * 128;
}
byte[] decryptedData = out.toByteArray();
out.close();
return URLDecoder.decode(new String(decryptedData, "UTF-8"), "UTF-8");
}
/**
* 私钥分段加密
*
* @param str
* @param privateKey
* @return
* @throws Exception
*/
public static String privateKeyEncrypt(String str, String privateKey) throws Exception {
byte[] decoded = org.apache.commons.codec.binary.Base64.decodeBase64(privateKey);
RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA")
.generatePrivate(new PKCS8EncodedKeySpec(decoded));
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(1, priKey);
// 分段加密
// URLEncoder编码解决中文乱码问题
byte[] data = URLEncoder.encode(str, "UTF-8").getBytes("UTF-8");
// 加密时超过117字节就报错。为此采用分段加密的办法来加密
byte[] enBytes = null;
for (int i = 0; i < data.length; i += MAX_ENCRYPT_BLOCK) {
// 注意要使用2的倍数,否则会出现加密后的内容再解密时为乱码
byte[] doFinal = cipher.doFinal(ArrayUtils.subarray(data, i, i + MAX_ENCRYPT_BLOCK));
enBytes = ArrayUtils.addAll(enBytes, doFinal);
}
String outStr = org.apache.commons.codec.binary.Base64.encodeBase64String(enBytes);
return outStr;
}
/**
* 公钥分段解密
*
* @param str
* @param publicKey
* @return
* @throws Exception
*/
public static String publicKeyDecrypt(String str, String publicKey) throws Exception {
// 获取公钥
byte[] decoded = org.apache.commons.codec.binary.Base64.decodeBase64(publicKey);
RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA")
.generatePublic(new X509EncodedKeySpec(decoded));
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(2, pubKey);
byte[] data = Base64.decodeBase64(str.getBytes("UTF-8"));
// 返回UTF-8编码的解密信息
int inputLen = data.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] cache;
int i = 0;
// 对数据分段解密
while (inputLen - offSet > 0) {
if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
cache = cipher.doFinal(data, offSet, MAX_DECRYPT_BLOCK);
} else {
cache = cipher.doFinal(data, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
offSet = i * 128;
}
byte[] decryptedData = out.toByteArray();
out.close();
return URLDecoder.decode(new String(decryptedData, "UTF-8"), "UTF-8");
}
}