Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create any PrivateKey instance (RSA or DSA or EC) from PKCS8 encoded data

I have an unencrypted PKCS8 encoded file that represents a Private Key. It can be any of these private key types - RSA, DSA or EC. I viewed these files in an ASN1 decoder (https://lapo.it/asn1js/) and I could see the type (RSA, DSA or EC) in the data.

Is there a way to read the PKC8 private key data into the correct Private Key Java object without specifying the key type in code like this -

PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(pkcs8key);
KeyFactory factory = KeyFactory.getInstance("RSA"); // Avoid "RSA" here?
PrivateKey privateKey = factory.generatePrivate(spec);

Is there a way to avoid specifying the algorithm in KeyFactory.getInstance("RSA")? Shouldn't this be determined from the PKCS8EncodedKeySpec since it is available in the PKCS8 data?

Sample unencrypted PKCS8 data and their ASN1 decodings which show the key type -

DSA - link

EC - link

RSA - link

like image 925
MediumOne Avatar asked Aug 21 '18 14:08

MediumOne


1 Answers

This can be achieved with the help of BouncyCastle APIs -

/** Read a PKCS#8 format private key. */
private static PrivateKey readPrivateKey(InputStream input)
throws IOException, GeneralSecurityException {
    try {
        byte[] buffer = new byte[4096];
        int size = input.read(buffer);
        byte[] bytes = Arrays.copyOf(buffer, size);
        /* Check to see if this is in an EncryptedPrivateKeyInfo structure. */
        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(bytes);
        /*
         * Now it's in a PKCS#8 PrivateKeyInfo structure. Read its Algorithm
         * OID and use that to construct a KeyFactory.
         */
        ASN1InputStream bIn = new ASN1InputStream(new ByteArrayInputStream(spec.getEncoded()));
        PrivateKeyInfo pki = PrivateKeyInfo.getInstance(bIn.readObject());
        String algOid = pki.getPrivateKeyAlgorithm().getAlgorithm().getId();
        return KeyFactory.getInstance(algOid).generatePrivate(spec);
    } finally {
        input.close();
    }
}
like image 102
MediumOne Avatar answered Sep 19 '22 18:09

MediumOne