RSA分段加密 - Java


前言

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 -
一個努力中的公眾號
關注一下吧


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM