• RSA分段加密


    前言

    RSA的 key 长度为 1024 用公钥加密比较长的字符串时会异常,这里介绍 java 如何对长文本进行分段加密


    具体实现

    • 实现类
    import com.alibaba.fastjson.JSONObject;
    import org.apache.commons.lang3.ArrayUtils;
    import javax.crypto.Cipher;
    import java.io.ByteArrayOutputStream;
    import java.net.URLDecoder;
    import java.net.URLEncoder;
    import java.security.KeyFactory;
    import java.security.PrivateKey;
    import java.security.PublicKey;
    import java.security.spec.EncodedKeySpec;
    import java.security.spec.PKCS8EncodedKeySpec;
    import java.security.spec.X509EncodedKeySpec;
    import java.util.Base64;
    import java.util.HashMap;
    import java.util.Map;
    
    public class RSAUtils {
    
        /**
         * 公钥
         */
        private static final String PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCaaI4MBywkCjIppZnraqN3pbrcZTq/t0+aMBo8K3pK9BDD6XkM6N2Yfcva7BSFbUWuAcI7piXak0UKn9CElDuhNzUSgQn4IXKxIt3Iva5cV83qYumj+0yRjjLT8Muu1Y1rgBZjY9oBwhVoV+Twg25+UJ+6Q6HM4xTwQQJDoyy4jwIDAQAB";
    
        /**
         * 私钥
         */
        private static final String PRIVATE_KEY = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAJpojgwHLCQKMimlmetqo3elutxlOr+3T5owGjwrekr0EMPpeQzo3Zh9y9rsFIVtRa4BwjumJdqTRQqf0ISUO6E3NRKBCfghcrEi3ci9rlxXzepi6aP7TJGOMtPwy67VjWuAFmNj2gHCFWhX5PCDbn5Qn7pDoczjFPBBAkOjLLiPAgMBAAECgYBnBBKhG7frY5IMDxwd4Euna767hB4qAlbte+JE+ozgrOzyiDXm0wXk0yjKqm8WhczTRwEbYsImjdKmP/GSQoN1AU7yEzM8j0Jgq46m9ZVrHhu2NpuZpr+XueWnA6FNz6tybBgcCwA4t8dvfbOrvjqhrCu01O1xWIpjronyFBN4IQJBAPGuF58xjXyANnp5YU8NhUQ73tTIveRlOpMXDSYkf9lWG26XIGUIsTe0f5jssiNmYtxG+lUm9LLfZgOLcrVkDZ0CQQCjjrBNMXub49efVTCg+nCGT2QXW2BHg/qs5vu8Y34LUHoD/hoEJ+AOWOdnhpRoYOpBwJAm3Gu4a1VmZGGafp0bAkAdfY3aWhSWtZpwNXF/UPoLCnc1Zc1uGkAchLqRBfEn1w7/3qcQTRA66OaNBYzzLuIvWOXhECDZ1tK+6fw0UCItAkAOLibW6n1fDKf7JnWq30u2OVfiNofoa2bmarhUowOgk3+grP0wcwyX8dlOPnrLeeuVe86DsASe3p9u2zEjJesVAkEAhkLiv4TXrC1QlJl7ghksUfFmdT7M4Zxlzj10ConMgq68HkLdmn2nNLsjhUHGwJe3EqM6aozn4zw/Z7uPIT9Fsw==";
    
        /**
         * 私钥分段加密
         * @param content
         * @return
         * @throws Exception
         */
        public static String encryptLongByPrivateKey(String content) throws Exception {
            // 获取私钥
            PrivateKey privateKey = getPrivateKey(PRIVATE_KEY);
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE, privateKey);
    
            // URLEncoder编码解决中文乱码问题
            byte[] data = URLEncoder.encode(content, "UTF-8").getBytes("UTF-8");
            // 加密时超过117字节就报错。为此采用分段加密的办法来加密
            byte[] enBytes = null;
            for (int i = 0; i < data.length; i += 117) {
                // 注意要使用2的倍数,否则会出现加密后的内容再解密时为乱码
                byte[] doFinal = cipher.doFinal(ArrayUtils.subarray(data, i, i + 117));
                enBytes = ArrayUtils.addAll(enBytes, doFinal);
            }
            return Base64.getEncoder().encodeToString(enBytes);
        }
    
        /**
         * 公钥分段解密
         * @param content
         * @return
         * @throws Exception
         */
        public static String decryptLongByPublicKey(String content) throws Exception {
            //获取公钥
            PublicKey publicKey = getPublicKey(PUBLIC_KEY);
            Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
            cipher.init(Cipher.DECRYPT_MODE, publicKey);
            byte[] data =  Base64.getDecoder().decode(content);
    
            // 返回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 > 128) {
                    cache = cipher.doFinal(data, offSet, 128);
                } 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"));
        }
    
        /**
         * 将base64编码后的公钥字符串转成PublicKey实例
         * @param publicKey 公钥
         * @return PublicKey实例
         * @throws Exception 异常信息
         */
        public static PublicKey getPublicKey(String publicKey) throws Exception {
            EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(publicKey));
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            return keyFactory.generatePublic(keySpec);
        }
    
        /**
         * 将base64编码后的私钥字符串转成PrivateKey实例
         * @param privateKey 私钥
         * @return PrivateKey实例
         * @throws Exception 异常信息
         */
        private static PrivateKey getPrivateKey(String privateKey) throws Exception {
            byte[] keyBytes = Base64.getDecoder().decode(privateKey);
            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            return keyFactory.generatePrivate(keySpec);
        }
    
        public static void main(String[] args) throws Exception {
    
            Map<String,Object> map = new HashMap<>();
            map.put("name", "Cosini");
            map.put("phone", "13888888888");
            String content = JSONObject.toJSONString(map);
    
            // 密文
            String cipherText = RSAUtils.encryptLongByPrivateKey(content);
            System.out.println("cipherText: " + cipherText);
    
            // 明文
            String plainText = RSAUtils.decryptLongByPublicKey(cipherText);
            System.out.println("plainText: " + plainText);
        }
    
    }
    

    • 结果如下所示:
      在这里插入图片描述

    • 注:分段加密中文乱码是因为一个中文3个字节,在解密最大长度分界如果被分隔成了两段转成 String 就会产生乱码。这里使用 URLEncoder 进行编码,解决中文字符乱码问题。


    源码

    - End -
    一个努力中的公众号
    关注一下吧
    以上为本篇文章的主要内容,希望大家多提意见,如果喜欢记得点个推荐哦
    作者:Maggieq8324
    本文版权归作者和博客园共有,欢迎转载,转载时保留原作者和文章地址即可。
  • 相关阅读:
    设计模式笔记——策略模式(Strategy Pattern)
    C#基础笔记——集合和LINQ
    C#基础笔记——命名规范
    C#基础笔记——语言基础
    C#基础笔记——代码整洁
    C#基础笔记——序列化(Serialize)和反序列化(NonSerialize)
    C#基础笔记——资源管理
    C#基础笔记——协变(Covariance)和逆变(Contravariance)
    C#基础笔记——委托(Delegate)和事件(Event)
    C#基础笔记——泛型(Genericity)
  • 原文地址:https://www.cnblogs.com/maggieq8324/p/15065697.html
Copyright © 2020-2023  润新知