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 }

 

posted @ 2023-12-05 10:21  明天,你好啊  阅读(270)  评论(0编辑  收藏  举报