Java之RSAUtil类的使用

发布时间 2023-03-22 21:11:18作者: 罗毅豪

我在项目中遇到选择审批人时,传到前端的审批人信息ID需要加密,然后传回后端需要解密的情况。

我们可以采用RSA算法实现公私钥加解密。

RSAUtil类内容如下:

package com.cmit.kapok.system.utils;

import com.cmit.kapok.system.api.cdy_encrypt_keys.ICdyEncryptKeysService;

import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

public class RSAUtil {
    private static final String RSA = "RSA";
    private static final String mode = "RSA/ECB/PKCS1Padding";

    private static ICdyEncryptKeysService cdyEncryptKeysService;

    public static PublicKey getPublicKey(String base64PublicKey) {
        PublicKey publicKey = null;
        try {
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(base64PublicKey.getBytes()));
            KeyFactory keyFactory = KeyFactory.getInstance(RSA);
            publicKey = keyFactory.generatePublic(keySpec);
            return publicKey;
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (InvalidKeySpecException e) {
            e.printStackTrace();
        }
        return publicKey;
    }

    public static String encrypt(String data) throws Exception {
        if (cdyEncryptKeysService == null) {
            cdyEncryptKeysService = SpringBeanFactoryUtils.getBean(ICdyEncryptKeysService.class);
        }
        String publicKey = cdyEncryptKeysService.getPublicKey();
        return Base64.getEncoder().encodeToString(encrypt(data.getBytes(), getPublicKey(publicKey)));
    }

    public static byte[] encrypt(byte[] plainBytes, PublicKey publicKey) throws Exception {
        int keyByteSize = 2048 / 8;
        int encryptBlockSize = keyByteSize - 11;
        int nBlock = plainBytes.length / encryptBlockSize;
        if ((plainBytes.length % encryptBlockSize) != 0) {
            nBlock += 1;
        }
        ByteArrayOutputStream outbuf = null;
        try {
            Cipher cipher = Cipher.getInstance(mode);
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);

            outbuf = new ByteArrayOutputStream(nBlock * keyByteSize);
            for (int offset = 0; offset < plainBytes.length; offset += encryptBlockSize) {
                int inputLen = plainBytes.length - offset;
                if (inputLen > encryptBlockSize) {
                    inputLen = encryptBlockSize;
                }
                byte[] encryptedBlock = cipher.doFinal(plainBytes, offset, inputLen);
                outbuf.write(encryptedBlock);
            }
            outbuf.flush();
            return outbuf.toByteArray();
        } catch (Exception e) {
            throw new Exception("ENCRYPT ERROR:", e);
        } finally {
            try {
                if (outbuf != null) {
                    outbuf.close();
                }
            } catch (Exception e) {
                outbuf = null;
                throw new Exception("CLOSE ByteArrayOutputStream ERROR:", e);
            }
        }
    }

    public static PrivateKey getPrivateKey(String base64PrivateKey) {
        PrivateKey privateKey = null;
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(base64PrivateKey.getBytes()));
        KeyFactory keyFactory = null;
        try {
            keyFactory = KeyFactory.getInstance(RSA);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        try {
            privateKey = keyFactory.generatePrivate(keySpec);
        } catch (InvalidKeySpecException e) {
            e.printStackTrace();
        }
        return privateKey;
    }

    public static String decrypt(String data, String base64PrivateKey) throws Exception {
        return new String(decrypt(Base64.getDecoder().decode(data.getBytes()), getPrivateKey(base64PrivateKey)));
    }


    public static byte[] decrypt(byte[] encryptedBytes, PrivateKey privateKey) throws Exception {
        int keyByteSize = 2048 / 8;
        int decryptBlockSize = keyByteSize - 11;
        int nBlock = encryptedBytes.length / keyByteSize;
        ByteArrayOutputStream outbuf = null;
        try {
            Cipher cipher = Cipher.getInstance(mode);
            cipher.init(Cipher.DECRYPT_MODE, privateKey);

            outbuf = new ByteArrayOutputStream(nBlock * decryptBlockSize);
            for (int offset = 0; offset < encryptedBytes.length; offset += keyByteSize) {
                int inputLen = encryptedBytes.length - offset;
                if (inputLen > keyByteSize) {
                    inputLen = keyByteSize;
                }
                byte[] decryptedBlock = cipher.doFinal(encryptedBytes, offset, inputLen);
                outbuf.write(decryptedBlock);
            }
            outbuf.flush();
            return outbuf.toByteArray();
        } catch (Exception e) {
            throw new Exception("DEENCRYPT ERROR:", e);
        } finally {
            try {
                if (outbuf != null) {
                    outbuf.close();
                }
            } catch (Exception e) {
                outbuf = null;
                throw new Exception("CLOSE ByteArrayOutputStream ERROR:", e);
            }
        }
    }

    public static void generateKeyPair() throws NoSuchAlgorithmException {
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(RSA);
        keyPairGen.initialize(2048);//密钥位数
        //By default, the private key is generated in PKCS#8 format and the public key is generated in X.509 format.
        KeyPair keyPair = keyPairGen.generateKeyPair();//密钥对

        PublicKey publicKey = keyPair.getPublic(); // 公钥
        PrivateKey privateKey = keyPair.getPrivate();// 私钥
        System.out.println(Base64.getEncoder().encodeToString(publicKey.getEncoded()));
        System.out.println(Base64.getEncoder().encodeToString(privateKey.getEncoded()));
    }

    public static void main(String[] args) throws NoSuchAlgorithmException {
        generateKeyPair();
    }
}

1.使用generateKeyPair可以生成一对base64编码的公私钥,可手动存储在数据库表里。

2.调用encrypt(str),函数内部会调用getPublicKey从数据库获取公钥,然后调用encrpt(byte[],publicKey),然后再构造成字符串。

3.调用decrypt(str,base64PrivateKey),函数内部会调用getPrivateKey获取私钥,然后调用decrypt(byte[],privateKey),然后再构造成字符串。