需要注意的是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"); } }