Bootstrap

JAVA使用RSA实现非对称加密


import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.UUID;

/**
 * RSA 工具
 * RSA加密明文最大长度117字节,解密要求密文最大长度为128字节,所以在加密和解密的过程中需要分块进行。
 * @author chunyang.leng
 * @date 2021-12-06 3:04 下午
 */
public class RsaUtils {
    /**
     * RSA最大加密明文大小
     */
    private static final int MAX_ENCRYPT_BLOCK = 117;

    /**
     * RSA最大解密密文大小
     */
    private static final int MAX_DECRYPT_BLOCK = 128;

    /**
     * 加密算法
     */
    private static final String ALGORITHM = "RSA";

    public static void main(String[] args) throws Exception {
        // 获取密码对
        KeyPair keyPair = getKeyPair(1024);

        // 获取公钥
        PublicKey publicKey = keyPair.getPublic();
        // 获取私钥
        PrivateKey privateKey = keyPair.getPrivate();

        for (int i = 0; i < 10000; i++) {
            // 循环1w次,做编解码测试
            String uuid = UUID.randomUUID().toString();
            // 使用公钥加密
            String encrypt1 = encrypt(uuid, publicKey);
            String encrypt2 = encrypt(uuid, getPublicKeyBase64(publicKey));

            // 使用私钥解密
            String decrypt1 = decrypt(encrypt1, privateKey);
            String decrypt2 = decrypt(encrypt2, getPrivateKeyBase64(privateKey));
            // 输出加解密结果
            System.out.println(decrypt1.equals(decrypt2) && uuid.equals(decrypt1));
        }
    }


    /**
     * 获取密钥对创建对象
     * @param keySize 密钥长度,正整数,如果过大,加解密速度会很慢
     * @return 密钥对
     * @throws NoSuchAlgorithmException
     */
    public static KeyPair getKeyPair(int keySize) throws NoSuchAlgorithmException {
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(ALGORITHM);
        keyPairGen.initialize(keySize);
        return keyPairGen.generateKeyPair();
    }


    /**
     * 根据 publicKey 对象,获取可以传输的 base64 公钥
     * @param publicKey rsa 公钥对象
     * @return 可以传输的 base64 公钥
     */
    public static String getPublicKeyBase64(PublicKey publicKey){
        return Base64.getEncoder().encodeToString(publicKey.getEncoded());
    }


    /**
     * 根据 privateKey 对象,获取可以传输的 base64 私钥
     * @param privateKey rsa 私钥对象
     * @return 可以传输的 base64 私钥
     */
    public static String getPrivateKeyBase64(PrivateKey privateKey){
        return Base64.getEncoder().encodeToString(privateKey.getEncoded());
    }


    /**
     * 根据公钥字符串,创建 RSAPublicKey
     * @param publicKey 公钥字符串
     * @return RSAPublicKey
     * @throws Exception
     */
    public static PublicKey getPublicKey(String publicKey) throws Exception {
        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
        byte[] keyBytes = Base64.getDecoder().decode(publicKey);
        X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
        return keyFactory.generatePublic(spec);
    }

    /**
     * 根据 私钥字符串 创建RSAPrivateKey
     * @param privateKey 私钥字符串
     * @return RSAPrivateKey 对象
     * @throws Exception
     */
    public static PrivateKey getPrivateKey(String privateKey) throws Exception {

        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
        byte[] keyBytes = Base64.getDecoder().decode(privateKey);
        // Only RSAPrivate(Crt)KeySpec and PKCS8EncodedKeySpec supported for RSA private keys
        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
        return keyFactory.generatePrivate(spec);
    }

    /**
     * 使用公钥加密数据
     * @param message 待加密的数据
     * @param publicKeyBase64 rsa 公钥字符串
     * @return 加密后的字符串
     * @throws Exception
     */
    public static String encrypt(String message,String publicKeyBase64) throws Exception {
        if (message == null ){
            return null;
        }
        PublicKey publicKeyObject = getPublicKey(publicKeyBase64);
        return encrypt(message,publicKeyObject);
    }

    /**
     * 使用公钥加密
     * @param message 待加密待信息
     * @param publicKey rsa 公钥对象
     * @return 加密后待字符串
     * @throws Exception
     */
    public static String encrypt(String message,PublicKey publicKey) throws Exception {
        if (message == null ){
            return null;
        }
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.PUBLIC_KEY, publicKey);

        byte[] data = message.getBytes(StandardCharsets.UTF_8);
        int inputLen = data.length;
        try (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();
            return Base64.getEncoder().encodeToString(encryptedData);
        }
    }



    /**
     * 根据私钥,解密信息
     * @param encodedMessage 待解密的信息
     * @param privateKeyBase64 rsa 私钥字符串
     * @return 解密后的信息
     */
    public static String decrypt(String encodedMessage,String privateKeyBase64) throws Exception{
        if (encodedMessage == null ){
            return null;
        }
        PrivateKey privateKey = getPrivateKey(privateKeyBase64);
        return decrypt(encodedMessage,privateKey);
    }

    /**
     * 根据私钥,解密信息
     * @param encodedMessage 待解密的信息
     * @param privateKey rsa 私钥 对象
     * @return 解密后的信息
     */
    public static String decrypt(String encodedMessage,PrivateKey privateKey) throws Exception {
        if (encodedMessage == null ){
            return null;
        }
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.PRIVATE_KEY, privateKey);

        byte[] encryptedData = Base64.getDecoder().decode(encodedMessage);

        int inputLen = encryptedData.length;

        try (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();
            return new String(decryptedData, StandardCharsets.UTF_8);
        }
    }

}

;