Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to load PEM encoded Elliptic Curve public keys into Bouncy Castle?

I have a PEM encoded Elliptic Curve public key that I'm trying to load into Bouncy Castle and everything I tried so far is failing. This is an example of the key I'm trying to load:

-----BEGIN PUBLIC KEY-----
MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBhsFCcWY2GaiN1BjPEd1v+ESKO6/0
D0sUR4y1amHnOr3FZx6TdqdoSBqxownQrnAKGCwagGxUb7BWwPFgHqKQJHgBq+J7
F+6m5SKAEL1wS5pqya91N7oudF3yFW8oZRE4RQRdSLl3fV2aVXKwGDXciwhUhw8k
x5OS4iZpMAY+LI4WVGU=
-----END PUBLIC KEY-----

It is generated by NodeJS Crypto module and the curve name is secp521r1. It's later on encoded into PEM by the npm package key-encoder. I already used it in JavaScript (ClojureScript actually) to verify a signature and now I need to verify the signature on the server with Java (Clojure actually).

I tried removing the guards from the key, coverting to a byte[] and creating a X509EncodedKeySpec. That didn't work. It crashed with:

InvalidKeySpecException encoded key spec not recognised  org.bouncycastle.jcajce.provider.asymmetric.util.BaseKeyFactorySpi.engineGeneratePublic (:-1)

The code to I'm using to load the key:

KeyFactory.
  getInstance("ECDSA", "BC").
  generatePublic(new X509EncodedKeySpec(publicKey.getBytes()))

Just in case, this is my Clojure code:

(-> (KeyFactory/getInstance "ECDSA")
    (.generatePublic (X509EncodedKeySpec. (.getBytes public-key)))) 

I also tried PKCS8EncodedKeySpec but I got the error:

InvalidKeySpecException key spec not recognised  org.bouncycastle.jcajce.provider.asymmetric.util.BaseKeyFactorySpi.engineGeneratePublic (:-1)

I also tried this method here: https://gist.github.com/wuyongzheng/0e2ed6d8a075153efcd3#file-ecdh_bc-java-L47-L50 but when running decodePoint I get the error:

IllegalArgumentException Invalid point encoding 0x4d  org.bouncycastle.math.ec.ECCurve.decodePoint (:-1)

when I removed the guards and:

IllegalArgumentException Invalid point encoding 0x2d  org.bouncycastle.math.ec.ECCurve.decodePoint (:-1)

with the guards on.

Any ideas what I'm doing wrong or how to fix it?

Also, in case it helps, this is the private key:

-----BEGIN EC PRIVATE KEY-----
MIHbAgEBBEEjNeo52qeffbIQvSxRcWAPlyJjeEOov2JNxxwWKCtlowi07HsYNNyE
jFDdSn8tSYAGx0rROrgpGuuJoG0zarPKz6AHBgUrgQQAI6GBiQOBhgAEAYbBQnFm
NhmojdQYzxHdb/hEijuv9A9LFEeMtWph5zq9xWcek3anaEgasaMJ0K5wChgsGoBs
VG+wVsDxYB6ikCR4AaviexfupuUigBC9cEuaasmvdTe6LnRd8hVvKGUROEUEXUi5
d31dmlVysBg13IsIVIcPJMeTkuImaTAGPiyOFlRl
-----END EC PRIVATE KEY-----

and everything seems to be valid:

$ openssl ec -in private.pem  -pubout
read EC key
writing EC key
-----BEGIN PUBLIC KEY-----
MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBhsFCcWY2GaiN1BjPEd1v+ESKO6/0
D0sUR4y1amHnOr3FZx6TdqdoSBqxownQrnAKGCwagGxUb7BWwPFgHqKQJHgBq+J7
F+6m5SKAEL1wS5pqya91N7oudF3yFW8oZRE4RQRdSLl3fV2aVXKwGDXciwhUhw8k
x5OS4iZpMAY+LI4WVGU=
-----END PUBLIC KEY-----
like image 750
pupeno Avatar asked Nov 05 '16 02:11

pupeno


People also ask

Does Bouncycastle support PKCS1 keys?

Moreover, the BouncyCastle library supports the PKCS1 format as well. Despite the fact that PKCS1 is also a popular format used to store cryptographic keys (only RSA keys), Java doesn't support it on its own. 5. Conclusion

What is the difference between public and private keys in PEM?

The public key is used to encrypt the message while only the owner of the private key can decrypt the message. In this tutorial, we’re going to see how to read public and private keys from a PEM file.

How are pkcs8 private keys encrypted?

The private key can be optionally encrypted using a symmetric algorithm. Not only can RSA private keys can be handled by this standard, but also other algorithms. The PKCS8 private keys are typically exchanged through the PEM encoding format. PEM is a base-64 encoding mechanism of a DER certificate.

What kind of data is encoded in a pem file?

PEM may also encode other kinds of data such as public/private keys and certificate requests. A PEM file also contains a header and a footer describing the type of encoded data: -----BEGIN PUBLIC KEY----- ...Base64 encoding of the DER encoded certificate...


2 Answers

Doing a bit of massaging I finally managed to load it:

(require '[clojure.string :as s])
(import '[java.security KeyFactory]
        '[java.security.spec X509EncodedKeySpec]
        '[java.util Base64])

(def public-key "-----BEGIN PUBLIC KEY-----
MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBhsFCcWY2GaiN1BjPEd1v+ESKO6/0
D0sUR4y1amHnOr3FZx6TdqdoSBqxownQrnAKGCwagGxUb7BWwPFgHqKQJHgBq+J7
F+6m5SKAEL1wS5pqya91N7oudF3yFW8oZRE4RQRdSLl3fV2aVXKwGDXciwhUhw8k
x5OS4iZpMAY+LI4WVGU=
-----END PUBLIC KEY-----")

(as-> public-key key
      (s/replace key "-----BEGIN PUBLIC KEY-----" "")
      (s/replace key "-----END PUBLIC KEY-----" "")
      (s/replace key #"\s" "")
      (.decode (Base64/getDecoder) key)
      (X509EncodedKeySpec. key)
      (.generatePublic (KeyFactory/getInstance "ECDSA" "BC") key))
like image 98
pupeno Avatar answered Sep 20 '22 10:09

pupeno


Since you have BC, it can dePEMify instead of doing it 'by hand' (I only do plain Java):

Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
Reader rdr = new StringReader("-----BEGIN PUBLIC KEY-----\n"
        +"MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBhsFCcWY2GaiN1BjPEd1v+ESKO6/0\n"
        +"D0sUR4y1amHnOr3FZx6TdqdoSBqxownQrnAKGCwagGxUb7BWwPFgHqKQJHgBq+J7\n"
        +"F+6m5SKAEL1wS5pqya91N7oudF3yFW8oZRE4RQRdSLl3fV2aVXKwGDXciwhUhw8k\n"
        +"x5OS4iZpMAY+LI4WVGU=\n" +"-----END PUBLIC KEY-----\n"); // or from file etc.

org.bouncycastle.util.io.pem.PemObject spki = new org.bouncycastle.util.io.pem.PemReader(rdr).readPemObject();
PublicKey key = KeyFactory.getInstance("EC","BC").generatePublic(new X509EncodedKeySpec(spki.getContent()));

System.out.println (key.getAlgorithm() + " " + ((ECPublicKey)key).getW().toString());

Example output:
EC java.security.spec.ECPoint@47244700

FYI, PKCS8 encoding is only for private keys; see javadoc for java.security.Key.getFormat()

like image 21
dave_thompson_085 Avatar answered Sep 19 '22 10:09

dave_thompson_085