How do I load an Elliptic Curve PEM encoded Privat

2019-07-11 11:05发布

问题:

This question already has an answer here:

  • Reading elliptic curve private key from file with BouncyCastle 3 answers

I've generated an elliptic curve private/public key pair using OpenSSL. The private and public keys are PEM encoded. I've figured out how to load the public key thanks to this. However, I can't figure out how to load the private key, as the above message just ends up with an InvalidKeySpecException: key spec not recognized.

I then found this, but it also ends up with an "encoded key spec not recognised". How can I load my private key?

private PrivateKey loadPrivateKey(String location) {
    try {
        // Strip the guarding strings
        byte[] bytes = stripGuardLines(location);

        return KeyFactory.getInstance("ECDH").generatePrivate(new PKCS8EncodedKeySpec(bytes));
    } catch (FileNotFoundException e) {
        LoggerFactory.getLogger("Nectar").error("Failed to find Private KEY: " + location);
        System.exit(1);
    } catch (IOException e) {
        LoggerFactory.getLogger("Nectar").error("IOException while loading Private Key!");
        e.printStackTrace();
        System.exit(1);
    } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
        e.printStackTrace();
        System.exit(1);
    }

    return null;
}

private byte[] stripGuardLines(String location) throws IOException {
    BufferedReader r = new BufferedReader(new FileReader(location));

    String line;
    StringBuilder sb = new StringBuilder();
    while((line = r.readLine()) != null) {
        if(line.contains("EC PRIVATE KEY")) { //Check if guard line
            continue;
        }
        sb.append(line);
    }
    // Guard lines stripped, now decode base64

    return Base64.getDecoder().decode(sb.toString());
}

Here is the private key file:

-----BEGIN EC PRIVATE KEY-----
MIGkAgEBBDD2MFRv6BpJU6/zDI2yBfVbe0oeU1nFAoYMedDGtcdwHyWNJSeiYRBA
pVNzMxPSBLWgBwYFK4EEACKhZANiAAQBttEp/qUGnDlmL+o6KZnVs+RoBnEBEGho
PxSUu1Xfj77QQqfuqHOCRzWXseQA1aZB/h6VQEiFovugtG1G3HaMxxrqLLxb10g2
BMaRcAfZyeqc3O0Ui8XXb1esn0gOrCU=
-----END EC PRIVATE KEY-----

回答1:

Your code outputs only the key itself. It is missing the algorithm specifiers required for PKCS#8 encoded private keys. Fortunately the key itself always has the same size when encoded (it doesn't use any ASN.1 integers, which may have different sizes as far as I can see).

That means that you can simply concatenate the header from another key:

// static header you can put in front
byte[] header = Hex.decode("30 81bf 020100 301006072a8648ce3d020106052b81040022 0481a7");
// your key from the PEM above
byte[] fromPEM = Base64.decode("MIGkAgEBBDD2MFRv6BpJU6/zDI2yBfVbe0oeU1nFAoYMedDGtcdwHyWNJSeiYRBApVNzMxPSBLWgBwYFK4EEACKhZANiAAQBttEp/qUGnDlmL+o6KZnVs+RoBnEBEGhoPxSUu1Xfj77QQqfuqHOCRzWXseQA1aZB/h6VQEiFovugtG1G3HaMxxrqLLxb10g2BMaRcAfZyeqc3O0Ui8XXb1esn0gOrCU=");
byte[] bytes = Arrays.concatenate(header, fromPEM);
PrivateKey ecPrivate = KeyFactory.getInstance("EC").generatePrivate(new PKCS8EncodedKeySpec(bytes));

this code is both Bouncy Castle compatible as compatible with the default implementation in the Java JRE from Oracle.


Note that you might as well use Oracle compatible code to create your key pair as well:

KeyPairGenerator kpGen = KeyPairGenerator.getInstance("EC");
kpGen.initialize(new ECGenParameterSpec("secp384r1"));
KeyPair ecKP = kpGen.generateKeyPair();