RSA分段加密方案
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 }