Skip to content

How to check if a file is pkcs#8 DER format in Java?

I need to check if a file is pkcs#8 DER format in Java when uploading the file, I think maybe PKCS8EncodedKeySpec and getFormat() can be used.

class FileFormatePkcs8{
    public static void main(String[] args) {
    String filename = args[0];
        try {
            File f = new File(filename);
            byte[] encodedKey = new byte[(int)f.length()];
            PKCS8EncodedKeySpec pkcs8Key = new PKCS8EncodedKeySpec(encodedKey);
            if(pkcs8Key.getFormat().equals("PKCS#8")) {
                System.out.println("It's pkcs8.");
            }
            else {
                System.out.println("It's not pkcs8.");
            }
        }
        catch (Exception ex) {
            System.out.println("exception:"+ex.getMessage());
        }
    }

}

All the files input will get the “It’s pkcs8.” result. I realize “PKCS8EncodedKeySpec” will create the pkcs#8 key, but I don’t know using which class to replace it.

Note that: both of PKCS#8 and DER need to be check, so I think org.bouncycastle.openssl.PEMParser can be ignored. Or am I on the wrong track?

Answer

First, you don’t actually read the contents of the file at all. You just create an empty buffer the same size as the file. Since this buffer doesn’t contain any data, the non-present data is not in PKCS8 format, nor JKS format, nor Bitcoin wallet format, nor any other format. (Note instead of multiple steps, you can just use byte[] data = Files.readAllBytes(Paths.get(filename))).

Second, there are two PKCS8 DER formats.

OOTB Java visibly supports PKCS8-unencrypted (clear) PrivateKeyInfo only if you know the algorithm to which the key applies (RSA, DSA, ECDSA/ECDH, etc). If you do, simply call KeyFactory.getInstance for that algorithm, then call .generatePrivateKey with a PKCS8EncodedKeySpec containing the (purported) PKCS8-clear, and if it returns an appropriate subclass of PrivateKey (and doesn’t throw an exception) then the data was in fact PKCS8-clear and for that algorithm. If you don’t know the algorithm but only a limited set are permitted or possible, you can simply try each in turn and see if any (and which) works.

Otherwise, you must either parse the ASN.1 yourself (possible, but nontrivial), or use BouncyCastle (but not the PEM part): call org.bouncycastle.asn1.pkcs.PrivateKeyInfo.getInstance(der) and if it succeeds the input data either is PKCS8-clear or a very good imitation.

For PKCS8-encrypted, Java does expose javax.crypto.EncryptedPrivateKeyInfo; just invoke the constructor on the data and if it doesn’t throw the data looked like PKCS8-encrypted. This does not check however that this data can be decrypted and when decrypted is actually a privatekey as it should be; for that if you know the password use epki.getKeySpec() combined with checking the resulting purported PKCS8-clear as above.