Java读取pem文件使用RSA加密解密

pem文件的生成使用openssl程序,在这里我使用的是PHP的脚本生成的,因为需要PHP和Java能共用

 

生成的脚本地址:

https://www.cnblogs.com/xuweiqiang/p/9784584.html

遇到的坑主要是:


1、读取pem文件的时候需要将标识头和标识结尾删除还有换行符也删除;

2、transformationCode需要一致;

 

 

Java代码:

package com.example.one.utils;

import cn.hutool.core.io.FileUtil;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import javax.crypto.Cipher;
import java.security.*;

public class RSAUtils {

    private static final String encrypt_file = "/Users/xuweiqiang/nginx/www/php_rsa/encrypt_file.txt";
    private static final String private_key = "/Users/xuweiqiang/nginx/www/php_rsa/private_key.pem";
    private static final String public_key = "/Users/xuweiqiang/nginx/www/php_rsa/public_key.pem";
    private static final String transformationCode = "RSA/ECB/PKCS1Padding";

    public static void main(String[] args) {
        byte[] encryptFile = FileUtil.readBytes(encrypt_file);
        String content = new String(encryptFile, StandardCharsets.UTF_8);
        PrivateKey p = null;
        try {
            p = readPrivateKey(private_key);
        } catch (IOException e) {
            e.printStackTrace();
        }
        String c = decryptRSA(p, content);
        System.out.println(c);
        PublicKey pbk = null;
        try {
            pbk = readPublicKey(public_key);
        } catch (IOException e) {
            e.printStackTrace();
        }
        String d = encryptRSA(pbk, "hello world");
        System.out.println(d);

    }

    // 返回 RSA 加密的结果
    public static String encryptRSA(Key publicKey, String text) {
        try {
            Cipher rsa = Cipher.getInstance(transformationCode);
            rsa.init(Cipher.ENCRYPT_MODE, publicKey);
            byte[] originBytes = text.getBytes();
            //大于117时进行分段 加密
            int subLength = originBytes.length / 117 + (originBytes.length % 117 == 0 ? 0 : 1);
            byte[] finalByte = new byte[128 * subLength];
            for (int i = 0; i < subLength; i++) {
                //需要加密的字节长度
                int len = i == subLength - 1 ? (originBytes.length - i * 117) : 117;
                //加密完成的字节数组
                byte[] doFinal = rsa.doFinal(originBytes, i * 117, len);
                //复制这次加密的数组
                System.arraycopy(doFinal, 0, finalByte, i * 128, doFinal.length);
            }
            return new String(Base64.getEncoder().encode(finalByte),
                    StandardCharsets.UTF_8);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 返回 RSA 解密的结果
     */
    public static String decryptRSA(Key privateKey, String content) {
        try {
            byte[] text = Base64.getDecoder().decode(content);
            Cipher rsa = Cipher.getInstance(transformationCode);
            rsa.init(Cipher.DECRYPT_MODE, privateKey);
            //大于128时进行分段 解密
            int subLength = text.length / 128;
            StringBuilder finalString = new StringBuilder();
            for (int i = 0; i < subLength; i++) {
                finalString.append(new String(rsa.doFinal(text, i * 128, 128), StandardCharsets.UTF_8));
            }
            return finalString.toString();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    //根据文件路径返回公匙
    public static PublicKey readPublicKey(String filePath) throws IOException {
        return readPublicKey(new FileInputStream(filePath));
    }

    // 根据输入流返回公匙
    public static PublicKey readPublicKey(InputStream input) throws IOException {
        final ByteArrayOutputStream output = new ByteArrayOutputStream();
        int n;
        final byte[] buffer = new byte[1024 * 4];
        while (-1 != (n = input.read(buffer))) {
            output.write(buffer, 0, n);
        }
        String publicPEM = output.toString()
                .replace("-----BEGIN PUBLIC KEY-----", "")
                .replaceAll(System.lineSeparator(), "")
                .replace("-----END PUBLIC KEY-----", "");
        X509EncodedKeySpec spec =
                new X509EncodedKeySpec(Base64.getMimeDecoder().decode(publicPEM.getBytes(StandardCharsets.UTF_8)));
        try {
            KeyFactory kf = KeyFactory.getInstance("RSA");
            return kf.generatePublic(spec);
        } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
            e.printStackTrace();
        }
        return null;
    }

    // 根据文件路径返回私匙
    public static PrivateKey readPrivateKey(String filePath) throws IOException {
        return readPrivateKey(new FileInputStream(filePath));
    }

    // 根据输入流返回私匙
    public static PrivateKey readPrivateKey(InputStream input) throws IOException {
        final ByteArrayOutputStream output = new ByteArrayOutputStream();
        int n;
        final byte[] buffer = new byte[1024 * 4];
        while (-1 != (n = input.read(buffer))) {
            output.write(buffer, 0, n);
        }
        if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
            Security.addProvider(new BouncyCastleProvider());
        }
        String privateKeyPEM = output.toString()
                .replace("-----BEGIN PRIVATE KEY-----", "")
                .replaceAll(System.lineSeparator(), "")
                .replace("-----END PRIVATE KEY-----", "");
        PKCS8EncodedKeySpec spec =
                new PKCS8EncodedKeySpec(org.apache.commons.codec.binary.Base64.decodeBase64(privateKeyPEM.getBytes(StandardCharsets.UTF_8)));
        try {
            KeyFactory kf = KeyFactory.getInstance("RSA");
            return kf.generatePrivate(spec);
        } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
            e.printStackTrace();
        }
        return null;
    }
}

那个 hutools 缺失的话引入一下:

<dependency>
   <groupId>cn.hutool</groupId>
   <artifactId>hutool-all</artifactId>
   <version>5.7.5</version>
</dependency>

如果遇到 base64 非法格式,使用 getMimeDecoder 试试

特别感谢:

https://blog.csdn.net/weixin_34124577/article/details/91403667 

 

posted @ 2022-05-21 21:16  许伟强  阅读(1860)  评论(0编辑  收藏  举报