0

Small question regarding getting an elliptic curve private key with Java please.

I run this command in my terminal:

openssl ecparam -name secp256k1 -genkey -noout -out ec-secp256k1-dummy-priv-key.pem

This commands is working fine, generating the file fine, I can even cat the file, which I can see:

-----BEGIN EC PRIVATE KEY-----
MHQCAQEEIDHE7OA9hgIYW427NieIsXz/qAipMVhqVUIwVcEIWwuAoAcGBSuBBAAK
oUQDQgAEcMu2KlVzJLKQ9XfoWvF0jZ+JwbPeUekHqTYVTFK9ISoKLgBN9abxIxyc
JumqIshcc74GUVtm/sJJoiPJNdEPEQ==
-----END EC PRIVATE KEY-----

(please note here it is written BEGIN EC PRIVATE KEY and not BEGIN PRIVATE KEY)

Now, I get ride of the \n and spaces, etc, basically to have the "inside" of the key, configured as a one line string.

String s = "MHQCAQEEIDHE7OA9hgIYW427NieIsXz/qAipMVhqVUIwVcEIWwuAoAcGBSuBBAAKoUQDQgAEcMu2KlVzJLKQ9XfoWvF0jZ+JwbPeUekHqTYVTFK9ISoKLgBN9abxIxycJumqIshcc74GUVtm/sJJoiPJNdEPEQ==";

(please let me know if this step is wrong)

What I tried: I then use this piece of code to get the private key

String s = "MHQCAQEEIDHE7OA9hgIYW427NieIsXz/qAipMVhqVUIwVcEIWwuAoAcGBSuBBAAKoUQDQgAEcMu2KlVzJLKQ9XfoWvF0jZ+JwbPeUekHqTYVTFK9ISoKLgBN9abxIxycJumqIshcc74GUVtm/sJJoiPJNdEPEQ==";

        byte[] keyData = Base64.getDecoder().decode(s);
        EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(keyData);
        KeyFactory kf = KeyFactory.getInstance("EC");
        PrivateKey privKey = kf.generatePrivate(privKeySpec);

Unfortunately, it is yielding this error

SEVERE: null
java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException : version mismatch: (supported:     00, parsed:     01

Caused by: java.security.InvalidKeyException: IOException : version mismatch: (supported:     00, parsed:     01
    at java.base/sun.security.pkcs.PKCS8Key.decode(PKCS8Key.java:350)
    at java.base/sun.security.pkcs.PKCS8Key.decode(PKCS8Key.java:355)

I am having a bit of a hard time understanding the issue, and how to fix this.

If possible, I would like to avoid falling back to bouncy castle, avoid changing the way the key is being generated, avoid having to convert the key to yet again another format.

May I ask what did I do wrong, and what is the correct way to fix this issue please?

Thank you

PatPanda
  • 3,644
  • 9
  • 58
  • 154
  • While I agree converting to pkcs8 as answered is the best way, you _can_ read this format in plain Java by adding a fixed-per-curve prefix to the decoded (binary) SEC1 format to make it PKCS8 format, along the lines shown in https://stackoverflow.com/questions/41927859/how-do-i-load-an-elliptic-curve-pem-encoded-private-key but that case is secp384r1 and you'd need a different actual prefix for secp256k1. – dave_thompson_085 Dec 02 '21 at 06:14

1 Answers1

4

As far as I can read from the PKCS8EncodedKeySpec Javadocs, the input to the constructor must be a PKCS8 encoded private key. However, the openssl ecparam command apparently does not generate the key in PKCS8 format. If I understand the documentation correctly, you would need to convert the private key to PKCS8 like so:

openssl pkcs8 -topk8 -nocrypt -in ec-secp256k1-dummy-priv-key.pem -out p8file.pem

Then you can strip the newlines and BEGIN/END tags and feed that into PKCS8EncodedKeySpec.

D-FENS
  • 1,438
  • 8
  • 21