Skip to main content
 首页 » 编程设计

java使用RSA加解密,支持长文本自动分割

2022年08月02日81mayingbao

由于对称加密DES等算法安全性一般,所以使用RSA非对称加密以提高安全性

本代码java使用RSA加解密,支持长文本自动分割,基础代码是从网上找的


加密算法类

import java.io.ByteArrayOutputStream; 
import java.security.Key; 
import java.security.KeyFactory; 
import java.security.KeyPair; 
import java.security.KeyPairGenerator; 
import java.security.PrivateKey; 
import java.security.PublicKey; 
import java.security.Signature; 
import java.security.interfaces.RSAPrivateKey; 
import java.security.interfaces.RSAPublicKey; 
import java.security.spec.PKCS8EncodedKeySpec; 
import java.security.spec.X509EncodedKeySpec; 
import java.util.Base64; 
import java.util.HashMap; 
import java.util.Map; 
 
import javax.crypto.Cipher; 
 
/** 
 * <p> 
 * RSA公钥/私钥/签名工具包 
 * </p> 
 * <p> 
 * 罗纳德·李维斯特(Ron [R]ivest)、阿迪·萨莫尔(Adi [S]hamir)和伦纳德·阿德曼(Leonard [A]dleman) 
 * </p> 
 * <p> 
 * 字符串格式的密钥在未在特殊说明情况下都为BASE64编码格式<br/> 
 * 由于非对称加密速度极其缓慢,一般文件不使用它来加密而是使用对称加密,<br/> 
 * 非对称加密算法可以用来对对称加密的密钥加密,这样保证密钥的安全也就保证了数据的安全 
 * </p> 
 *  
 * @author IceWee 
 * @date 2012-4-26 
 * @version 1.0 
 */ 
public class RSAUtils { 
 
    /** 
     * 加密算法RSA 
     */ 
    public static final String KEY_ALGORITHM = "RSA"; 
     
    /** 
     * 签名算法 
     */ 
    public static final String SIGNATURE_ALGORITHM = "MD5withRSA"; 
 
    /** 
     * 获取公钥的key 
     */ 
    private static final String PUBLIC_KEY = "RSAPublicKey"; 
     
    /** 
     * 获取私钥的key 
     */ 
    private static final String PRIVATE_KEY = "RSAPrivateKey"; 
     
    /** 
     * RSA最大加密明文大小 
     */ 
    private static final int MAX_ENCRYPT_BLOCK = 117; 
     
    /** 
     * RSA最大解密密文大小 
     */ 
    private static final int MAX_DECRYPT_BLOCK = 128; 
 
    /** 
     * <p> 
     * 生成密钥对(公钥和私钥) 
     * </p> 
     *  
     * @return 
     * @throws Exception 
     */ 
    public static Map<String, Object> genKeyPair() throws Exception { 
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM); 
        keyPairGen.initialize(1024); 
        KeyPair keyPair = keyPairGen.generateKeyPair(); 
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); 
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); 
        Map<String, Object> keyMap = new HashMap<String, Object>(2); 
        keyMap.put(PUBLIC_KEY, publicKey); 
        keyMap.put(PRIVATE_KEY, privateKey); 
        return keyMap; 
    } 
     
    /** 
     * <p> 
     * 用私钥对信息生成数字签名 
     * </p> 
     *  
     * @param data 已加密数据 
     * @param privateKey 私钥(BASE64编码) 
     *  
     * @return 
     * @throws Exception 
     */ 
    public static String sign(String msg, String privateKey) throws Exception { 
    	byte[] data = msg.getBytes(); 
        byte[] keyBytes = Base64.getDecoder().decode(privateKey); 
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); 
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); 
        PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec); 
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM); 
        signature.initSign(privateK); 
        signature.update(data); 
        return Base64.getEncoder().encodeToString(signature.sign()); 
    } 
 
    /** 
     * <p> 
     * 校验数字签名 
     * </p> 
     *  
     * @param data 已加密数据 
     * @param publicKey 公钥(BASE64编码) 
     * @param sign 数字签名 
     *  
     * @return 
     * @throws Exception 
     *  
     */ 
    public static boolean verify(String msg, String publicKey, String sign) 
            throws Exception { 
    	byte[] data = msg.getBytes(); 
        byte[] keyBytes = Base64.getDecoder().decode(publicKey); 
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); 
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); 
        PublicKey publicK = keyFactory.generatePublic(keySpec); 
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM); 
        signature.initVerify(publicK); 
        signature.update(data); 
        return signature.verify(Base64.getDecoder().decode(sign)); 
    } 
 
    /** 
     * <P> 
     * 私钥解密 
     * </p> 
     *  
     * @param encryptedData 已加密数据 
     * @param privateKey 私钥(BASE64编码) 
     * @return 
     * @throws Exception 
     */ 
    public static String decryptByPrivateKey(String encryptedDataStr, String privateKey) 
            throws Exception { 
    	byte[] encryptedData = Base64.getDecoder().decode(encryptedDataStr); 
        byte[] keyBytes = Base64.getDecoder().decode(privateKey); 
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); 
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); 
        Key privateK = keyFactory.generatePrivate(pkcs8KeySpec); 
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); 
        cipher.init(Cipher.DECRYPT_MODE, privateK); 
        int inputLen = encryptedData.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(encryptedData, offSet, MAX_DECRYPT_BLOCK); 
            } else { 
                cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet); 
            } 
            out.write(cache, 0, cache.length); 
            i++; 
            offSet = i * MAX_DECRYPT_BLOCK; 
        } 
        byte[] decryptedData = out.toByteArray(); 
        out.close(); 
        return new String(decryptedData); 
    } 
 
    /** 
     * <p> 
     * 公钥解密 
     * </p> 
     *  
     * @param encryptedData 已加密数据 
     * @param publicKey 公钥(BASE64编码) 
     * @return 
     * @throws Exception 
     */ 
    public static String decryptByPublicKey(String encryptedDataStr, String publicKey) 
            throws Exception { 
		byte[] encryptedData = Base64.getDecoder().decode(encryptedDataStr); 
        byte[] keyBytes = Base64.getDecoder().decode(publicKey); 
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes); 
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); 
        Key publicK = keyFactory.generatePublic(x509KeySpec); 
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); 
        cipher.init(Cipher.DECRYPT_MODE, publicK); 
        int inputLen = encryptedData.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(encryptedData, offSet, MAX_DECRYPT_BLOCK); 
            } else { 
                cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet); 
            } 
            out.write(cache, 0, cache.length); 
            i++; 
            offSet = i * MAX_DECRYPT_BLOCK; 
        } 
        byte[] decryptedData = out.toByteArray(); 
        out.close(); 
        return new String(decryptedData); 
    } 
 
    /** 
     * <p> 
     * 公钥加密 
     * </p> 
     *  
     * @param data 源数据 
     * @param publicKey 公钥(BASE64编码) 
     * @return 
     * @throws Exception 
     */ 
    public static String encryptByPublicKey(String msg, String publicKey) 
            throws Exception { 
    	byte[] data =  msg.getBytes(); 
    	byte[] keyBytes = Base64.getDecoder().decode(publicKey); 
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes); 
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); 
        Key publicK = keyFactory.generatePublic(x509KeySpec); 
        // 对数据加密 
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); 
        cipher.init(Cipher.ENCRYPT_MODE, publicK); 
        int inputLen = data.length; 
        ByteArrayOutputStream out = new ByteArrayOutputStream(); 
        int offSet = 0; 
        byte[] cache; 
        int i = 0; 
        // 对数据分段加密 
        while (inputLen - offSet > 0) { 
            if (inputLen - offSet > MAX_ENCRYPT_BLOCK) { 
                cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK); 
            } else { 
                cache = cipher.doFinal(data, offSet, inputLen - offSet); 
            } 
            out.write(cache, 0, cache.length); 
            i++; 
            offSet = i * MAX_ENCRYPT_BLOCK; 
        } 
        byte[] encryptedData = out.toByteArray(); 
        out.close(); 
         
        String encryptedDataStr = Base64.getEncoder().encodeToString(encryptedData); 
        return encryptedDataStr; 
    } 
 
    /** 
     * <p> 
     * 私钥加密 
     * </p> 
     *  
     * @param data 源数据 
     * @param privateKey 私钥(BASE64编码) 
     * @return 
     * @throws Exception 
     */ 
    public static String encryptByPrivateKey(String msg, String privateKey) 
            throws Exception { 
    	byte[] data = msg.getBytes(); 
        byte[] keyBytes = Base64.getDecoder().decode(privateKey); 
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); 
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); 
        Key privateK = keyFactory.generatePrivate(pkcs8KeySpec); 
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); 
        cipher.init(Cipher.ENCRYPT_MODE, privateK); 
        int inputLen = data.length; 
        ByteArrayOutputStream out = new ByteArrayOutputStream(); 
        int offSet = 0; 
        byte[] cache; 
        int i = 0; 
        // 对数据分段加密 
        while (inputLen - offSet > 0) { 
            if (inputLen - offSet > MAX_ENCRYPT_BLOCK) { 
                cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK); 
            } else { 
                cache = cipher.doFinal(data, offSet, inputLen - offSet); 
            } 
            out.write(cache, 0, cache.length); 
            i++; 
            offSet = i * MAX_ENCRYPT_BLOCK; 
        } 
        byte[] encryptedData = out.toByteArray(); 
        out.close(); 
         
        String encryptedDataStr = Base64.getEncoder().encodeToString(encryptedData); 
        return encryptedDataStr; 
    } 
 
    /** 
     * <p> 
     * 获取私钥 
     * </p> 
     *  
     * @param keyMap 密钥对 
     * @return 
     * @throws Exception 
     */ 
    public static String getPrivateKey(Map<String, Object> keyMap) 
            throws Exception { 
        Key key = (Key) keyMap.get(PRIVATE_KEY); 
        return Base64.getEncoder().encodeToString(key.getEncoded()); 
    } 
 
    /** 
     * <p> 
     * 获取公钥 
     * </p> 
     *  
     * @param keyMap 密钥对 
     * @return 
     * @throws Exception 
     */ 
    public static String getPublicKey(Map<String, Object> keyMap) 
            throws Exception { 
        Key key = (Key) keyMap.get(PUBLIC_KEY); 
        return Base64.getEncoder().encodeToString(key.getEncoded()); 
    } 
 
}





Test类

import java.util.Map; 
 
public class RSATester { 
 
    static String publicKey; 
    static String privateKey; 
 
     
    public static void main(String[] args) throws Exception { 
    	//获得公钥和私钥 
    	try { 
            Map<String, Object> keyMap = RSAUtils.genKeyPair(); 
            publicKey = RSAUtils.getPublicKey(keyMap); 
            privateKey = RSAUtils.getPrivateKey(keyMap); 
            System.err.println("公钥: \n" + publicKey); 
            System.err.println("私钥: \n" + privateKey); 
        } catch (Exception e) { 
            e.printStackTrace(); 
        } 
    	 
    	//yfx:RSA加解密效率低,并且好像是新线程执行的,导致下面的日志输出位置,不是按照代码顺序 
        test(); 
//        testSign(); 
//        testHttpSign(); 
         
    } 
 
    static void test() throws Exception { 
    	System.out.println("==========================================1"); 
        System.err.println("公钥加密——私钥解密"); 
        String source = "test()这是一行没有任何意义的文字,你看完了等于没看,不是吗?"; 
        System.out.println("\r加密前文字:\r\n" + source); 
        String encodedData = RSAUtils.encryptByPublicKey(source, publicKey); 
        System.out.println("加密后文字:\r\n" + encodedData); 
        String decodedData = RSAUtils.decryptByPrivateKey(encodedData, privateKey); 
        System.out.println("解密后文字: \r\n" + decodedData); 
    } 
 
    static void testSign() throws Exception { 
    	System.out.println("==========================================22"); 
        System.err.println("私钥加密——公钥解密"); 
        String source = "testSign()这是一行测试RSA数字签名的无意义文字"; 
        System.out.println("原文字:\r\n" + source); 
        String encodedData = RSAUtils.encryptByPrivateKey(source, privateKey); 
        System.out.println("加密后:\r\n" + encodedData); 
        String decodedData = RSAUtils.decryptByPublicKey(encodedData, publicKey); 
        System.out.println("解密后: \r\n" + decodedData); 
        System.out.println("==========================================333"); 
        System.err.println("私钥签名——公钥验证签名"); 
        String sign = RSAUtils.sign(encodedData, privateKey); 
        System.err.println("签名:\r" + sign); 
        boolean status = RSAUtils.verify(encodedData, publicKey, sign); 
        System.err.println("验证结果:\r" + status); 
    } 
     
    static void testHttpSign() throws Exception { 
    	System.out.println("==========================================4444"); 
        String param = "id=1&name=张三"; 
        String encodedData = RSAUtils.encryptByPrivateKey(param, privateKey); 
        System.out.println("加密后:" + encodedData); 
         
        String decodedData = RSAUtils.decryptByPublicKey(encodedData, publicKey); 
        System.out.println("解密后:" + new String(decodedData)); 
         
        String sign = RSAUtils.sign(encodedData, privateKey); 
        System.err.println("签名:" + sign); 
         
        boolean status = RSAUtils.verify(encodedData, publicKey, sign); 
        System.err.println("签名验证结果:" + status); 
    } 
     
     
}


Base64本代码用的java8自带的,java8以下没有这个类,可以考虑用Apache Commons Codec工具包的Base64,

需要引入commons-codec-1.6.jar,也可以用下面的maven引入

<dependency>
    <groupId>commons-codec</groupId>
    <artifactId>commons-codec</artifactId>
    <version>1.6</version>
</dependency>




本文参考链接:https://yfx000.blog.csdn.net/article/details/79014920