1. 程式人生 > >java程式碼生成相容openssl可用的rsa公私鑰,pkcs8轉換pkcs1,

java程式碼生成相容openssl可用的rsa公私鑰,pkcs8轉換pkcs1,

java預設的KeyPairGenerator生成的rsa 公私鑰不能直接被openssl來使用

java生成的私鑰是pkcs8 格式 公鑰是x.509格式

openssl生成和使用的是pkcs1格式,pem公私鑰檔案,所以需要轉換

本專案可以動態生成openssl相容的,openssl可使用的公私鑰

maven專案

//pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.dddd</groupId>
    <artifactId>jrsa</artifactId>
    <version>1.0</version>

    <dependencies>
        <dependency>
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
            <version>1.11</version>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.5</version>
        </dependency>
        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcprov-jdk15on</artifactId>
            <version>1.60</version>
        </dependency>
    </dependencies>


</project>
//Test3.java
import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemWriter;

import java.io.StringWriter;
import java.security.KeyPair;
import java.security.KeyPairGenerator;

/**
 * java生成openssl相容的rsa 公私鑰
 *
 * KeyPairGenerator生成的 私鑰是pkcs8格式,需要先轉為pkcs1格式,再由pkcs1轉為pem格式(openssl生成的pem)
 * KeyPairGenerator生成的 公鑰是x509格式,需要替換_為/,替換-為+,格式化後,加-----BEGIN PUBLIC KEY-----頭,-----END PUBLIC KEY-----尾,就與openssl生成的公鑰一致了
 *
 * 根據私鑰生成公鑰,公私鑰是一對一 openssl rsa -pubout -in rsa_private_key.pem -out rsa_public_key.pem
 */
public class Test3 {

    public static void main(String[] args) throws Exception{
        KeyPairGenerator kpg =KeyPairGenerator.getInstance("RSA");
        kpg.initialize(1024);
        KeyPair keyPair = kpg.generateKeyPair();

        String  publicKey = Base64.encodeBase64URLSafeString(keyPair.getPublic().getEncoded());
        String  privateKey = Base64.encodeBase64URLSafeString(keyPair.getPrivate().getEncoded());

        System.out.println(privateKey);
        String pem = privatePem(privateKey);
        System.out.println("openssl 生成的私鑰.pem:");
        System.out.println(pem);

        System.out.println(publicKey);
        System.out.println("openssl 生成的公鑰.pem");
        System.out.println("-----BEGIN PUBLIC KEY-----");
        formatKey(publicKey.replace("_","/").replace("-","+"));
        System.out.println("-----END PUBLIC KEY-----");


    }

    public static String publicPem(String publicKey) throws Exception{
        byte[] pubBytes = Base64.decodeBase64(publicKey);

        SubjectPublicKeyInfo spkInfo = SubjectPublicKeyInfo.getInstance(pubBytes);
        ASN1Primitive primitive = spkInfo.parsePublicKey();
        byte[] publicKeyPKCS1 = primitive.getEncoded();

        PemObject pemObject = new PemObject("RSA PUBLIC KEY", publicKeyPKCS1);
        StringWriter stringWriter = new StringWriter();
        PemWriter pemWriter = new PemWriter(stringWriter);
        pemWriter.writeObject(pemObject);
        pemWriter.close();
        String pemString = stringWriter.toString();

        return pemString;
    }

    public static String privatePem(String privateKey) throws Exception{
        byte[] privBytes = Base64.decodeBase64(privateKey);

        PrivateKeyInfo pkInfo = PrivateKeyInfo.getInstance(privBytes);
        ASN1Encodable encodable = pkInfo.parsePrivateKey();
        ASN1Primitive primitive = encodable.toASN1Primitive();
        byte[] privateKeyPKCS1 = primitive.getEncoded();

        return pkcs1ToPem(privateKeyPKCS1,false);
    }

    public static String pkcs1ToPem(byte[] pcks1KeyBytes,boolean isPublic) throws Exception{
        String type;
        if(isPublic){
            type = "RSA PUBLIC KEY";
        }else{
            type = "RSA PRIVATE KEY";
        }

        PemObject pemObject = new PemObject(type, pcks1KeyBytes);
        StringWriter stringWriter = new StringWriter();
        PemWriter pemWriter = new PemWriter(stringWriter);
        pemWriter.writeObject(pemObject);
        pemWriter.close();
        String pemString = stringWriter.toString();

        return pemString;
    }

    /**
     * 格式化java生成的key,一行長的,不適合pem中的-----BEGIN PUBLIC KEY-----,pem已經有換行了
     * @param key
     */
    public static void formatKey(String key){
        if(key==null) return;

        key = key.replace("\n","");

        int count = (key.length()-1)/64+1;
        for(int i=0;i<count;i++){
            if(i+1==count){
                //迴圈的最後一次
                System.out.println(key.substring(i*64));
            }else{
                System.out.println(key.substring(i*64,i*64+64));
            }
        }
    }

    /**
     * 從pem格式(-----BEGIN PUBLIC KEY-----)的key獲取一行key
     * @param pem
     * @return
     */
    public static String pemToKey(String pem){
        if(pem==null) return "";
        if(pem.indexOf("KEY-----")>0){
            pem = pem.substring(pem.indexOf("KEY-----")+"KEY-----".length());
        }
        if(pem.indexOf("-----END")>0){
            pem = pem.substring(0,pem.indexOf("-----END"));
        }
        return pem.replace("\n","");
    }
}

執行後生成的公私鑰
線上RSA公私金鑰校驗