Java实现RSA加密算法工具类

166 阅读4分钟

我们CTO是个二逼,在与第三方对接时,需要传输加密,调研了一天,发现rsa加密最符合我们的需求,便在网上搜索了Java如何实现RSA加密,二逼CTO看到后说不够洁癖,我就缝缝补补,最终版,拿走即用


import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.Serial;
import java.io.Serializable;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;

/**
 * RSA加密算法是一种非对称加密算法
 *
 * @author 老子
 * @since 1.0.0
 */
public final class RsaCipherUtils {

    private static final String ALGORITHM = "RSA";

    private static final String CIPHER_ALGORITHM = "RSA/ECB/PKCS1Padding";
    private static final String SIGN_ALGORITHMS = "SHA1WithRSA";

    /**
     * RSA key长度
     */
    public static final int KEY_SIZE = 1024;

    private final String publicKey;
    private final String privateKey;


    public RsaCipherUtils() {
        this(KEY_SIZE);
    }


    public RsaCipherUtils(int keySize) {
        Cipher cipher = createKeys(keySize);
        this.publicKey = cipher.getPublicKey();
        this.privateKey = cipher.getPrivateKey();
    }

    public RsaCipherUtils(String publicKey, String privateKey) {
        this.publicKey = publicKey;
        this.privateKey = privateKey;
    }

    public static RsaCipherUtils buildPublicKey(String publicKey) {
        return new RsaCipherUtils(publicKey, null);
    }

    public static RsaCipherUtils buildPrivateKey(String privateKey) {
        return new RsaCipherUtils(null, privateKey);
    }

    public static Cipher createKeys() {
        return createKeys(KEY_SIZE);
    }

    public static Cipher createKeys(int keySize) {
        // 为RSA算法创建一个KeyPairGenerator对象
        KeyPairGenerator kpg;
        try {
            kpg = KeyPairGenerator.getInstance(ALGORITHM);
        } catch (NoSuchAlgorithmException e) {
            throw new BusinessException("No such algorithm-->[" + ALGORITHM + "]");
        }

        // 初始化KeyPairGenerator对象,密钥长度
        kpg.initialize(keySize);
        // 生成密匙对
        KeyPair keyPair = kpg.generateKeyPair();
        // 得到公钥
        Key publicKey = keyPair.getPublic();
        // 得到私钥
        Key privateKey = keyPair.getPrivate();

        Base64.Encoder encoder = Base64.getEncoder();

        return new Cipher(encoder.encodeToString(publicKey.getEncoded()),
                encoder.encodeToString(privateKey.getEncoded()));
    }

    /**
     * 使用公钥进行加密
     *
     * @param plaintext .
     * @return {byte[]}
     */
    private byte[] encrypt(byte[] plaintext) {
        try {
            // 使用默认RSA
            RSAPublicKey publicKey = createPublicKey(this.publicKey);
            javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance(ALGORITHM);

            cipher.init(javax.crypto.Cipher.ENCRYPT_MODE, publicKey);

            int bitLengthOfPuk = publicKey.getModulus().bitLength() / 8;
            int blockSize = bitLengthOfPuk - 11;
            if (plaintext.length > blockSize) {
                List<byte[]> blocks = block(plaintext, blockSize);
                ByteBuffer buffer = ByteBuffer.allocate(blocks.size() * bitLengthOfPuk);
                for (byte[] block : blocks) {
                    buffer.put(cipher.doFinal(block));
                }
                return buffer.array();
            } else {
                return cipher.doFinal(plaintext);
            }

        } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException |
                 BadPaddingException | InvalidKeySpecException e) {
            throw new BusinessException("加密失败", e);
        }
    }

    /**
     * 使用公钥进行加密
     *
     * @param plaintext .
     * @return {byte[]}
     */
    public String encrypt(String plaintext) {
        return Base64.getEncoder().encodeToString(encrypt(plaintext.getBytes()));
    }

    /**
     * 使用私钥进行解密
     *
     * @param ciphertext .
     * @return {byte[]}
     */
    private byte[] decrypt(byte[] ciphertext) {
        try {
            // 使用默认RSA
            RSAPrivateKey privateKey = createPrivateKey(this.privateKey);
            javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance(CIPHER_ALGORITHM);

            cipher.init(javax.crypto.Cipher.DECRYPT_MODE, privateKey);

            int blockSize = privateKey.getModulus().bitLength() / 8;
            if (ciphertext.length > blockSize) {
                List<byte[]> blocks = block(ciphertext, blockSize);
                ByteBuffer buffer = ByteBuffer.allocate(blocks.size() * blockSize);
                for (byte[] block : blocks) {
                    buffer.put(cipher.doFinal(block));
                }

                buffer.flip();
                byte[] result = new byte[buffer.limit()];
                buffer.get(result);
                return result;
            } else {
                return cipher.doFinal(ciphertext);
            }
        } catch (NoSuchAlgorithmException | BadPaddingException | IllegalBlockSizeException | InvalidKeyException |
                 NoSuchPaddingException | InvalidKeySpecException e) {
            throw new BusinessException("解密失败", e);
        }
    }

    /**
     * 使用私钥进行解密
     *
     * @param ciphertext .
     * @return {byte[]}
     */
    public String decrypt(String ciphertext) {

        byte[] decode;

        Base64.Decoder decoder = Base64.getDecoder();

        try {
            decode = decoder.decode(ciphertext);
        } catch (Exception e) {
            decode = decoder.decode(ciphertext.getBytes(StandardCharsets.UTF_8));
        }
        return new String(decrypt(decode));
    }

    private RSAPublicKey createPublicKey(String puk) throws NoSuchAlgorithmException, InvalidKeySpecException {
        byte[] buffer = Base64.getDecoder().decode(puk);
        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
        KeySpec keySpec = new X509EncodedKeySpec(buffer);
        return (RSAPublicKey) keyFactory.generatePublic(keySpec);
    }

    private RSAPrivateKey createPrivateKey(String prk) throws NoSuchAlgorithmException, InvalidKeySpecException {
        byte[] buffer = Base64.getDecoder().decode(prk);
        KeySpec keySpec = new PKCS8EncodedKeySpec(buffer);
        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
        return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
    }

    /**
     * 签名
     *
     * @param data  .
     * @param nonce .
     * @return {byte[]}
     */
    public byte[] sign(byte[] data, byte[] nonce) {
        try {
            PrivateKey privateKey = createPrivateKey(this.privateKey);
            Signature signature = Signature.getInstance(SIGN_ALGORITHMS);
            signature.initSign(privateKey);

            byte[] withSalt = concat(data, nonce);

            signature.update(withSalt);
            return signature.sign();
        } catch (NoSuchAlgorithmException | SignatureException | InvalidKeyException | InvalidKeySpecException e) {
            throw new BusinessException("签名失败", e);
        }
    }

    /**
     * 验签
     *
     * @param data      .
     * @param nonce     .
     * @param signature .
     * @return {boolean}
     */
    public boolean verify(byte[] data, byte[] nonce, byte[] signature) {
        try {
            PublicKey publicKey = createPublicKey(this.publicKey);
            Signature instance = Signature.getInstance(SIGN_ALGORITHMS);
            instance.initVerify(publicKey);
            byte[] withSalt = concat(data, nonce);
            instance.update(withSalt);
            return instance.verify(signature);
        } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException | InvalidKeySpecException e) {
            throw new BusinessException("签名验证失败", e);
        }
    }

    private byte[] concat(byte[] b1, byte[] b2) {
        byte[] withSalt = new byte[b1.length + b2.length];
        System.arraycopy(b1, 0, withSalt, 0, b1.length);
        System.arraycopy(b2, 0, withSalt, b1.length, b2.length);
        return withSalt;
    }

    private List<byte[]> block(byte[] src, int blockSize) {
        int group;
        if (src.length % blockSize == 0) {
            group = src.length / blockSize;
        } else {
            group = src.length / blockSize + 1;
        }

        List<byte[]> blocks = new ArrayList<>();
        for (int i = 0; i < group; i++) {
            int from = i * blockSize;
            int to = Math.min(src.length, (i + 1) * blockSize);

            byte[] block = Arrays.copyOfRange(src, from, to);

            blocks.add(block);
        }
        return blocks;
    }


    public String getPublicKey() {
        return publicKey;
    }

    public String getPrivateKey() {
        return privateKey;
    }

    public static class Cipher {


        /**
         * 公钥
         */
        private String publicKey;


        /**
         * 私钥
         */
        private String privateKey;

        public Cipher(String publicKey, String privateKey) {
            this.publicKey = publicKey;
            this.privateKey = privateKey;
        }

        public String getPublicKey() {
            return publicKey;
        }

        public void setPublicKey(String publicKey) {
            this.publicKey = publicKey;
        }

        public String getPrivateKey() {
            return privateKey;
        }

        public void setPrivateKey(String privateKey) {
            this.privateKey = privateKey;
        }
    }


}

下面展示此工具类的使用方式


public static void main(String[] args) {

    // 提供三种构造方式来获取 RsaCipherUtils 实例

    // 方式一: keySize 默认 1024
    RsaCipherUtils utils = new RsaCipherUtils();

    // 方式二: 指定 keySize 大小
    //utils = new RsaCipherUtils(2048);

    // 方式三: 通过公钥和私钥构造
    //utils = new RsaCipherUtils("", "");


    // 获取公钥
    String publicKey = utils.getPublicKey();
    System.out.println("公钥:" + publicKey);

    // 获取私钥
    String privateKey = utils.getPrivateKey();
    System.out.println("私钥:" + privateKey);

    // 加密
    String encrypt = utils.encrypt("abc");
    System.out.println("加密后的结果:" + encrypt);

    // 解密
    String decrypt = utils.decrypt(encrypt);
    System.out.println("结密后的结果:" + decrypt);
}

运行结果

公钥:MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCQ5isPrFOPkAk+5bqqye2noPXjH6FUzmwxXNJCTrp33/SQEVigcPAcMS75GL6vANiCoflscTIUza5EsxJ5UJvMcgepdZkFdiUFRZXYB0kcjrTD7FchyHJqKD4sPH/gbD0Ygd+rD3hbAdhnBPfUUqUsP4QW0cNrjZTln/8/5vNK/QIDAQAB
私钥:MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAJDmKw+sU4+QCT7luqrJ7aeg9eMfoVTObDFc0kJOunff9JARWKBw8BwxLvkYvq8A2IKh+WxxMhTNrkSzEnlQm8xyB6l1mQV2JQVFldgHSRyOtMPsVyHIcmooPiw8f+BsPRiB36sPeFsB2GcE99RSpSw/hBbRw2uNlOWf/z/m80r9AgMBAAECgYBCq40TrJRUIY+Hf7eIftnZP8/zfanDNimE+vMJrGTS5FqIcVrIk75/EkhNOAwAxNBaJwH3WgwTk2HEXWq6JBNS6L37QmgEFbjwMhGar18pM51JevNHrhw9aQ88HqSPEIVMOiKFENm1OCLnLVMMl89tlRxKziy0SXxSFw5NrogOhwJBALz/02Es9wsZzJ5KqX3n7FCKaiFD627sWgLf2PRXmIFZVSrzi0bPVzzC+C/kzor+Y3WY5PC8DzAnFlK4n2XWfNcCQQDERCI6cdm+CKmRy6G3JOpzntCPmDjhauZ/ZTNMXMh99e2//fAaX+j7cidgqJj2E6ba/g4jVjeFzfvToQ9/ughLAkEAtISU3QgZndyyd65QXRWbvQG3hLZetL/C6WPs0NSpsUIl+rRLnwKDDGIcs4ITVObNEJFMejLlPtTWmYQFmztWWQJBAJNY26GpK+Hhuvy8NlK7IlFfYBEOJVYG3bmzDoo79kGqyq2jRglnDBEKqMmGih/krRYoOhEJf3GzLWa6uloYHnUCQQCyeL4YRDLw2paPNKwr30sSAw0rDx5plZYTL3y4ILHo0IKTg/Gv4MHhAoTlG0ce1Et4fpqMlZ06KFI6kl2T+84g
加密后的结果:b1QAAqa52JCSyah7qveSkHJ0X15AXhSs1g7Pk2j2SUG9G0u9iCZl9WTJbs1eOJ3FdNqoxelqOA78t2/MBo/TrgZu4YNaJVdgqoo7C75ihOxMWmxMNhWLOV9GEnPK3kuiHBlUGwZHyfruSsiOdO3kWoVyW82/y36zsjiKwdfXUlY=
解密后的结果:abc