1

I created an ECDSA keypair and exported the public key using OpenSSL, but I'm unable to read the public key in from Java.

Key generation in OpenSSL:

$ openssl ecparam -name secp256k1 -genkey -noout -outform DER | openssl ec -inform DER -pubout -outform DER > secp256k1.public.der

Clojure code that reads a key in from file, with [org.bouncycastle/bcprov-jdk15on "1.56"] as a dependency:

(ns adhoc.ecdsa-mismatch
  (:import (java.nio.file Files Paths)
           (java.security Security KeyFactory)
           (java.security.spec X509EncodedKeySpec)))

(when (nil? (Security/getProvider "BC"))
  (Security/addProvider (org.bouncycastle.jce.provider.BouncyCastleProvider.)))

(defn read-bytes
  "Read file from path as byte array."
  [^String path]
  (Files/readAllBytes (Paths/get path (into-array String []))))

(defn read-pubkey
  [^String path]
  (.generatePublic (KeyFactory/getInstance "ECDSA" "BC")
                   (X509EncodedKeySpec. (read-bytes path))))
(require '[adhoc.ecdsa-mismatch :as mm])

(mm/read-pubkey "secp256k1.public.der")
;; InvalidKeySpecException java.lang.NullPointerException  org.bouncycastle.jce.provider.JDKKeyFactory$EC.engineGeneratePublic (:-1)

(.printStackTrace *e)
;; java.security.spec.InvalidKeySpecException: java.lang.NullPointerException
;;  at org.bouncycastle.jce.provider.JDKKeyFactory$EC.engineGeneratePublic(Unknown Source)
;;  at java.security.KeyFactory.generatePublic(KeyFactory.java:328)
;;  at adhoc.ecdsa_mismatch$read_pubkey.invokeStatic(ecdsa_mismatch.clj:16)
;;  at adhoc.ecdsa_mismatch$read_pubkey.invoke(ecdsa_mismatch.clj:14)

Additional info

Generating a key with the NIST P-256 curve:

$ openssl ecparam -name prime256v1 -genkey -noout -outform DER | openssl ec -inform DER -pubout -outform DER > prime256v1.public.der

Loading a prime256v1 from disk:

(println (mm/read-pubkey "prime256v1.public.der"))
;; #object[org.bouncycastle.jce.provider.JCEECPublicKey 0x72369051 EC Public Key
;;             X: 5a690a647dc4b7e80f71f15212b08686c1f717ada7198fa8a0b8c93cec16ecb
;;             Y: 30be46137f328766ef8686675f118760ab0c96c52275bf00cf56097333ea6487
;; ]

The contents of the public keys:

$ base64 secp256k1.public.der 
MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEsipNgzBpQ0CLgZNw+LhASmh4KmGXnJsOC2dfzq5cVwMn
HfsfHGphaGvZTNoc/lUVrr+ICFK/2D/9up9hHHHHWg==
$ base64 prime256v1.public.der 
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEBaaQpkfcS36A9x8VISsIaGwfcXracZj6iguMk87B
bsswvkYTfzKHZu+GhmdfEYdgqwyWxSJ1vwDPVglzM+pkhw==
  • Also see [How to create ECDSA keypair (256bit) for bitcoin curve (secp256k1) using spongy castle?](http://stackoverflow.com/q/29778852/608639) and [C# ecdsa signature - Which key specification can i choose?](http://stackoverflow.com/q/19466907/608639) – jww Feb 14 '17 at 19:48

1 Answers1

0

The solution is that Java -- or perhaps this version of BouncyCastle -- does not support the secp256k1 elliptic curve! Using the far more common curve prime256v1 (NIST P-256) in the openssl call produces a key that I can read.

Sample successful output:

#<JCEECPublicKey EC Public Key
            X: 89cfd7dfb455e6ea51e578e9ea3505ba1e44a0a5f126e3b280611cf6bb467653
            Y: 565eb189ef15b8ff1b72824a7f0418a7df205797a86c8f30961e9bf0deaaa0c3
>
  • That is the same curve under another name, and BC should support either one of the identifiers. Could you publish the public keys in the question and answer? And maybe the version of Bouncy? That would allow us to further look into this issue. Thanks for the info, by the way. – Maarten Bodewes Feb 14 '17 at 20:26
  • Sure, added the exact public keys and the BC version. Changed the openssl commands around a bit, to same effect. – Tim has moved to Codidact Feb 15 '17 at 23:57
  • 1
    Also... I was *sure* that those were different curves, but I'm new to EC. Am I wrong that NIST P-256 = `prime256v1`, and that `secp256k1` is different? (Did you misread it as `secp256r1` by any chance? I've just learned that that's a synonym for `prime256v1`...) – Tim has moved to Codidact Feb 16 '17 at 00:02