RSA加密解密工具

座右铭:天行健,君子以自强不息;地势坤,君子以厚德载物。


每个人都有惰性,但不断学习新东西是好好生活的根本,共勉!


文章均为学习整理笔记,分享记录为主,如有错误请指正,共同学习进步。

文章目录

  • 一、RSA加密简介
  • 二、开发环境:
  • 三、具体实现
    • 1.引入依赖
    • 2.工具类
    • 3.测试类
    • 4.对比


一、RSA加密简介

RSA是一种公钥密码算法,它的名字是由它的三位开发者,即Ron Rivest、Adi Shamir 和 Leonard Adleman 的姓氏的首字母组成的。RSA可以被用于公钥密码和数字签名。RSA是被研究得最广泛的公钥算法,从提出到现在已近三十年,经历了各种攻击的考验,逐渐为人们接受,普遍认为是目前最优秀的公钥方案之一。


二、开发环境:

JDK版本:1.8
maven版本:3.9.0
开发工具:IDEA社区版ideaIC-2018.3
项目框架:spring boot 版本为 2.6.3 springboot搭建传送门

三、具体实现

1.引入依赖

所需依赖

无,使用java自带依赖即可实现

2.工具类

RsaUtils.java

package com.rsa.utils;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;

/**
 * @ClassDescription: 加密解密工具类
 * @Author:李白
 * @Date:2023/3/22 13:05
 */
public class RsaUtils {
    /**
     * 常量字符串
     */
    private static final String RSA = "RSA";
    
    /**
     * 获取密钥对象
     * @param keySize RSA算法模长(个人理解应该是模长越大加密安全性越高,但加密过程可能也越长)
     * @return
     * @throws NoSuchAlgorithmException
     */
    public static List<Key> getRsaObject(int keySize) throws NoSuchAlgorithmException {
        //创建list用来接收公钥对象和私钥对象
        List<Key> keyList = new ArrayList<>();
        //创建RSA密钥生成器
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(RSA);
        //设置密钥大小,RSA算法的模长=最大加密数据的大小
        keyPairGenerator.initialize(keySize);
        //调用函数生成公钥私钥对象(以对生成密钥)
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        //获取公钥放入list
        keyList.add(keyPair.getPublic());
        //获取私钥放入list
        keyList.add(keyPair.getPrivate());
        //返回list
        return keyList;
    }

    /**
     * 生成公钥私钥的字符串
     * @param keySize 模长
     * @return
     * @throws NoSuchAlgorithmException
     */
    public static List<String> getRsaKeyString(int keySize) throws NoSuchAlgorithmException {
        //创建list用来接收公钥对象和私钥对象
        List<String> keyList = new ArrayList<>();
        //创建RSA密钥生成器
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(RSA);
        //设置密钥大小,RSA算法的模长=最大加密数据的大小
        keyPairGenerator.initialize(keySize);
        //调用函数生成公钥私钥对象(以对生成密钥)
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        //将公钥对象转换为字符串通过base64加密
        String publicKey = Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded());
        //将私钥对象转换为字符串通过base64加密
        String privateKey = Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded());
        //获取公钥放入list
        keyList.add(publicKey);
        //获取私钥放入list
        keyList.add(privateKey);
        //返回list
        return keyList;
    }

    /**
     * 通过公钥字符串生成公钥对象(RSAPublicKey类型)
     * X509EncodeKeySpec方式(字符串公钥转为RSAPublicKey公钥)
     * @param publicKeyStr  公钥字符串
     * @return 返回RSAPublicKey类型的公钥对象
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeySpecException
     */
    public static RSAPublicKey getRSAPublicKeyByX509(String publicKeyStr) throws NoSuchAlgorithmException, InvalidKeySpecException {
        //密钥工厂创建
        KeyFactory keyFactory = KeyFactory.getInstance(RSA);
        //公钥字符解密为bytes数组
        byte[] keyBytes = Base64.getDecoder().decode(publicKeyStr);
        //公钥字符串转x509
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(keyBytes);
        //x509转RSAPublicKey
        return (RSAPublicKey) keyFactory.generatePublic(x509EncodedKeySpec);
    }

    /**
     * 通过私钥字符串生成私钥对象(RSAPrivateKey类型)
     * PKCS8EncodedKeySpec方式(字符串私钥转为RSAPrivateKey公钥)
     * @param privateKey 私钥字符串
     * @return 返回RSAPrivateKey类型的私钥对象
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeySpecException
     */
    public static RSAPrivateKey getRSAPrivateKeyByPKCS8(String privateKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
        //密钥工厂创建
        KeyFactory keyFactory = KeyFactory.getInstance(RSA);
        //私钥字符串解密为bytes数组
        byte[] keyBytes = Base64.getDecoder().decode(privateKey);
        //私钥字符串转pkcs8
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(keyBytes);
        //pkcs8转RSAPrivateKey
        return (RSAPrivateKey) keyFactory.generatePrivate(pkcs8EncodedKeySpec);
    }

    /**
     * 公钥加密
     * @param message 需要加密的信息
     * @param rsaPublicKey rsa公钥对象
     * @return 返回信息被加密后的字符串
     * @throws NoSuchPaddingException
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     * @throws IllegalBlockSizeException
     * @throws BadPaddingException
     * @throws IOException
     */
    public static String encryptByPublicKey(String message, RSAPublicKey rsaPublicKey) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, IOException {
        //RSA加密实例
        Cipher cipher = Cipher.getInstance(RSA);
        //初始化公钥
        cipher.init(Cipher.ENCRYPT_MODE, rsaPublicKey);
        //模长转为字节数
        int modulusSize = rsaPublicKey.getModulus().bitLength()/8;
        //PKCS PADDING长度为11字节,解密数据是除去这11byte
        int maxSingleSize = modulusSize-11;
        //切分字节数,每段不大于maxSingleSize
        byte[][] dataArray = splitArray(message.getBytes(), maxSingleSize);
        //字节数组输出流
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        //分组加密,加密后内容写入输出字节流
        for (byte[] s : dataArray){
            byteArrayOutputStream.write(cipher.doFinal(s));
        }
        //使用base64将字节数组转为string类型
        return Base64.getEncoder().encodeToString(byteArrayOutputStream.toByteArray());
    }
    
    /**
     * 私钥解密密
     * @param encryptedMessage 信息加密后的字符串
     * @param rsaPrivateKey rsa私钥对象
     * @return 返回解密后的字符串
     * @throws NoSuchPaddingException
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     * @throws IllegalBlockSizeException
     * @throws BadPaddingException
     * @throws IOException
     */
    public static String decryptByPrivateKey(String encryptedMessage, RSAPrivateKey rsaPrivateKey) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, IOException {
        //RSA加密实例
        Cipher cipher = Cipher.getInstance(RSA);
        //初始化公钥
        cipher.init(Cipher.DECRYPT_MODE, rsaPrivateKey);
        //加密算法模长
        int modulusSize = rsaPrivateKey.getModulus().bitLength()/8;
        byte[] dataBytes = encryptedMessage.getBytes();
        //加密做了转码,这里也要用base64转回来
        byte[] decodeData = Base64.getDecoder().decode(dataBytes);
        //切分字节数,每段不大于maxSingleSize
        byte[][] dataArray = splitArray(decodeData, modulusSize);
        //字节数组输出流
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        //分组解密,解密后内容写入输出字节流
        for (byte[] s : dataArray){
            byteArrayOutputStream.write(cipher.doFinal(s));
        }
        //使用base64将字节数组转为string类型
        return new String(byteArrayOutputStream.toByteArray());
    }
    
    /**
     * 按指定长度切分数组
     * @param byteArrayInfo 需要切分的byte数组
     * @param maxSize 单个字节数组长度
     * @return
     */
    private static byte[][] splitArray(byte[] byteArrayInfo, int maxSize){
        int dataLen = byteArrayInfo.length;
        if(dataLen<=maxSize){
            return new byte[][]{byteArrayInfo};
        }
        byte[][] result = new byte[(dataLen-1)/maxSize+1][];
        int resultLen = result.length;
        for (int i = 0; i < resultLen; i++) {
            if(i==resultLen-1){
                int sLen = dataLen-maxSize*i;
                byte[] single = new byte[sLen];
                System.arraycopy(byteArrayInfo, maxSize*i, single, 0, sLen);
                result[i] = single;
                break;
            }
            byte[] single = new byte[maxSize];
            System.arraycopy(byteArrayInfo, maxSize*i, single, 0, maxSize);
            result[i] = single;
        }
        return result;
    }

}

3.测试类

RsaTest.java

package com.rsa.controller;

import com.rsa.utils.RsaUtils;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.util.List;

/**
 * @ClassDescription: 测试类
 * @Author:李白
 * @Date:2023/3/22 13:04
 */
public class RsaTest {

    public static void main(String[]args) throws NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, IOException, InvalidKeyException, InvalidKeySpecException {
        String message = "sanQinShan";
        System.out.println("加密前的信息内容:"+message);

        System.out.println("-----------------------RSA密钥对象加密解密--------------------------------");
        //生成密钥对象
        List<Key> keyList = RsaUtils.getRsaObject(1024);
        //RSA类型的公钥对象
        RSAPublicKey rsaPublicKey = (RSAPublicKey) keyList.get(0);
        //RSA类型的私钥对象
        RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyList.get(1);
        //通过RSA类型的公钥对象加密信息
        String encryptedMsg = RsaUtils.encryptByPublicKey(message, rsaPublicKey);
        System.out.println("加密后的字符串encryptedMsg:\r\n"+encryptedMsg);
        //通过RSA类型的私钥对象解密
        String  decryptedMsg = RsaUtils.decryptByPrivateKey(encryptedMsg, rsaPrivateKey);
        System.out.println("------");
        System.out.println("解密后的字符串decryptedMsg:\r\n"+decryptedMsg);

        System.out.println();
        System.out.println("-----------------------字符串类型的密钥对象转为RSA密钥对象后的加密解密--------------------------");
        //生成密钥(字符串类型的密钥)
        List<String> keyStringList = RsaUtils.getRsaKeyString(1024);
        //字符串类型的公钥
        String publicKeyString = keyStringList.get(0);
        //字符串类型的私钥
        String privateKeyString = keyStringList.get(1);
        //将字符串类型的公钥私钥转为RSA类型
        RSAPublicKey rsaPublicKey1 = RsaUtils.getRSAPublicKeyByX509(publicKeyString);
        RSAPrivateKey rsaPrivateKey1 = RsaUtils.getRSAPrivateKeyByPKCS8(privateKeyString);
        //通过字符串公钥转为RSA类型的公钥 加密
        String encryptedMsg1 = RsaUtils.encryptByPublicKey(message, rsaPublicKey1);
        System.out.println("使用字符串转的rsa公钥对象加密后的字符串encryptedMsg1:\r\n"+encryptedMsg1);
        //通过字符串私钥转为RSA类型的私钥 解密
        String decryptedMsg1 = RsaUtils.decryptByPrivateKey(encryptedMsg1, rsaPrivateKey1);
        System.out.println("------");
        System.out.println("使用字符串转的私钥对象解密后的字符串decryptedMsg1:\r\n"+decryptedMsg1);

    }
}


4.对比

控制台输出信息
RSA加密解密工具_第1张图片
第一次加密解密后的结果与原信息内容一致
第二次加密解密后的结果与原信息内容一致
验证了两次加密解密的方式都可以正常得到原信息内容


你可能感兴趣的:(工具,java,后端)