May 30, 2018

How to Read PEM PKCS#1 or PKCS#8 Encoded Private Key In Java

import java.io.InputStream;
import java.math.BigInteger;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.RSAPrivateCrtKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

import org.junit.Ignore;
import org.junit.Test;

import sun.security.util.DerInputStream;
import sun.security.util.DerValue;

public class PEMTest {

    // (PKCS#1 has the 'BEGIN RSA PRIVATE KEY' header while PKCS#8 has the 'BEGIN PRIVATE KEY' header)
    @Test
    public void readPrivateKeyPKCS1PEM() throws Exception {
        String content = new String(
                Files.readAllBytes(Paths.get(ClassLoader.getSystemResource("server.key.pkcs1.pem").toURI())));
        content = content.replaceAll("\\n", "").replace("-----BEGIN RSA PRIVATE KEY-----", "")
                .replace("-----END RSA PRIVATE KEY-----", "");
        System.out.println("'" + content + "'");
        byte[] bytes = Base64.getDecoder().decode(content);

        DerInputStream derReader = new DerInputStream(bytes);
        DerValue[] seq = derReader.getSequence(0);
        // skip version seq[0];
        BigInteger modulus = seq[1].getBigInteger();
        BigInteger publicExp = seq[2].getBigInteger();
        BigInteger privateExp = seq[3].getBigInteger();
        BigInteger prime1 = seq[4].getBigInteger();
        BigInteger prime2 = seq[5].getBigInteger();
        BigInteger exp1 = seq[6].getBigInteger();
        BigInteger exp2 = seq[7].getBigInteger();
        BigInteger crtCoef = seq[8].getBigInteger();

        RSAPrivateCrtKeySpec keySpec =
                new RSAPrivateCrtKeySpec(modulus, publicExp, privateExp, prime1, prime2, exp1, exp2, crtCoef);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
        System.out.println(privateKey);
    }

    // (PKCS#1 has the 'BEGIN RSA PRIVATE KEY' header while PKCS#8 has the 'BEGIN PRIVATE KEY' header)
    @Test
    public void readPrivateKeyPKCS8PEM() throws Exception {
        String content = new String(
                Files.readAllBytes(Paths.get(ClassLoader.getSystemResource("server.key.pkcs8.pem").toURI())));
        content = content.replaceAll("\\n", "").replace("-----BEGIN PRIVATE KEY-----", "")
                .replace("-----END PRIVATE KEY-----", "");
        System.out.println("'" + content + "'");
        byte[] bytes = Base64.getDecoder().decode(content);

        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(bytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
        System.out.println(privateKey);
    }
}