0

I've been trying to convert the below pasted code to a public key. I'm trying to create a shared secret. I have the uncompressed HEX representation of the key. I want to create a public key from it. Likewise, I want the same for creating a private key and joining them after.

String plainPublicKey = "042E3E5CCF6B9AB04BE7A22F3FACCFDE73C87E87155394A34815408A896CA18A374DAC669AF3BF6220FC863767F4AF47507C5BC221FC4A19874DAF39B4074E3EB8";
        EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(Hex.decodeHex(plainPublicKey.toCharArray()));
        KeyFactory kf = KeyFactory.getInstance("EC");
        PublicKey pub = kf.generatePublic(publicKeySpec);
        return pub;
java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: invalid key format
    at jdk.crypto.ec/sun.security.ec.ECKeyFactory.engineGeneratePublic(ECKeyFactory.java:157)
    at java.base/java.security.KeyFactory.generatePublic(KeyFactory.java:352)
    at AESExample.getPublicKey(AESExample.java:66)
    at AESExample.main(AESExample.java:74)
Caused by: java.security.InvalidKeyException: invalid key format
    at java.base/sun.security.x509.X509Key.decode(X509Key.java:386)
    at java.base/sun.security.x509.X509Key.decode(X509Key.java:401)
    at jdk.crypto.ec/sun.security.ec.ECPublicKeyImpl.<init>(ECPublicKeyImpl.java:71)
    at jdk.crypto.ec/sun.security.ec.ECKeyFactory.implGeneratePublic(ECKeyFactory.java:219)
    at jdk.crypto.ec/sun.security.ec.ECKeyFactory.engineGeneratePublic(ECKeyFactory.java:153)
    ... 3 more
James Z
  • 12,209
  • 10
  • 24
  • 44
  • 3
    To derive a `java.security.PublicKey` from an uncompressed public EC key see e.g. [here](https://stackoverflow.com/a/56170785/9014097). Additionally the curve name is needed. You also have to remove the leading `04` byte of the key (marks an uncompressed key). – Topaco Aug 11 '20 at 17:49
  • 1
    For the private key see [here](https://stackoverflow.com/a/31443277/9014097). This code uses BouncyCastle to derive `ECParameterSpec`. Alternatively, `ecParameterSpecForCurve(...)` can be used from the first link. For this, of course, the raw private EC key is required. – Topaco Aug 11 '20 at 18:46
  • Thank-you so much! I tried with the public key according to the mentioned link after removing the leading 04 byte. Still getting InvalidKey exception. How am I supposed to know which curve to use? Randomly tried secp256r1 and secp256k1. Both didn't work. – automationFormation Aug 11 '20 at 21:30
  • @automationFormation: what do you mean with "Both didn't work" ? Did you get an error on creating the Public Key or what is your code that is failing now ? – Michael Fehr Aug 11 '20 at 21:34
  • 2
    An `InvalidKeyException` can be thrown for various reasons, usually additional information is displayed, e.g. _Key must be instance of PrivateKey_. So please edit your question and add at the end the _complete_ stacktrace, the used Java version and your _most recent_ code. The curve name (or the [domain parameters](https://en.wikipedia.org/wiki/Elliptic-curve_cryptography#Domain_parameters)) must be known because they are the reference system for the keys. Both sides must therefore agree on a common curve name. – Topaco Aug 12 '20 at 08:31
  • I tried different curves to check which ones work. Out of the list several worked. I checked for the OID that I wanted and used that curve for my code. Both public and private keys are being provided from above provided links. Thank you! @Topaco As a side note, if you can kindly can you suggest how which curve should I be using? I know NIST P-256 is what I'm looking for but the associated curve, I'm not certain. – automationFormation Aug 12 '20 at 11:46
  • 1
    Depending on the organization, different names are used for the same curves, e.g. NIST P-256 (NIST) is also known as secp256r1 (SECG) or prime256v1 (ANSI X9.62), see [Rfc4492](https://tools.ietf.org/search/rfc4492#appendix-A). The linked codes accept the first two names (`NIST P-256` and `secp256r1`). By the way, the public key you posted is indeed a point on this curve and therefore valid. – Topaco Aug 12 '20 at 12:48
  • @Topaco You've been a great help! It is indeed the case. Much appreciated! – automationFormation Aug 13 '20 at 09:50

1 Answers1

0

I see that this is an old question, but I'll post a solution anyway so it can maybe help somebody else.

First you must specify the curve that was used to generate your public key, like this:

ECParameterSpec ecParameterSpec = ECNamedCurveTable.getParameterSpec("secp256r1");
ECNamedCurveSpec params = new ECNamedCurveSpec("secp256r1", ecParameterSpec.getCurve(), ecParameterSpec.getG(), ecParameterSpec.getN());

Take a look at this question to see how to find out supported curves for the provider you are using: Supported EC curves.

Then you decode your public key like following:

ECPoint publicPoint =  ECPointUtil.decodePoint(params.getCurve(), parseHexBinary(pubKey));

And use it to generate a public key:

ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(publicPoint, params);
KeyFactory kf = KeyFactory.getInstance("EC");
PublicKey publicKey =  kf.generatePublic(pubKeySpec);

Additionaly here is a link to my question and solution about the same topic: Hex to public key in java.

M.Mark
  • 71
  • 1
  • 6