简体   繁体   中英

Unable to import OpenSSL generated private key into web API crypto.subtle.importKey

I'm creating a private EC key using the command openssl ecparam -name secp256r1 -genkey -noout -out k1.pem . I'm trying to import it using crypto.subtle.importKey as described in this documentation .

Ie after running OpenSSL I have the private key

-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIOuQ2Du5Q3bE0wzYwqImGjbb6zASbof36MVeRQMTfOA5oAoGCCqGSM49
AwEHoUQDQgAErSz9FIO1sLPciJjHbj/EduYNClaeCBhQuU5ZPh24YRvHG5FXLNiV
1dPIB02KyKXiYjvLro586uYDkYzaPkzbOw==
-----END EC PRIVATE KEY-----

and from Chrome console

let binary = atob("MHcCAQEEIOuQ2Du5Q3bE0wzYwqImGjbb6zASbof36MVeRQMTfOA5oAoGCCqGSM49AwEHoUQDQgAErSz9FIO1sLPciJjHbj/EduYNClaeCBhQuU5ZPh24YRvHG5FXLNiV1dPIB02KyKXiYjvLro586uYDkYzaPkzbOw==")
let der = str2ab(binary)
let key = crypto.subtle.importKey(
    'pkcs8',
    der,
    {
      name: 'ECDSA',
      namedCurve: 'P-256',
    },
    false,
    ['sign']
  );

getting a Uncaught (in promise) Error from the last command.


It's worth mentioning that when I use Java libraries through Clojure to generate the EC key I can import it successfully using the same js code:

(ns vouch.crypto
  (:import (java.security KeyPairGenerator SecureRandom KeyPair)
           (org.bouncycastle.jce ECNamedCurveTable)
           (java.util Base64)))

(defn generate-ec-key-pair
  "Generate an Elliptic Curve Key Pair"
  ^KeyPair []
  (let [ec-spec (ECNamedCurveTable/getParameterSpec "secp256r1")
        ^KeyPairGenerator generator (KeyPairGenerator/getInstance "ECDSA" "BC")]
    (.initialize generator ec-spec (SecureRandom.))
    (.generateKeyPair generator)))

(defn bytes->hex
  "Convert a seq of bytes into a hex encoded string."
  ^String [^bytes bytes]
  (apply str (for [b bytes] (format "%02x" b))))

(defn- base64-encode
  ^String [^bytes bytes-to-encode]
  (-> (Base64/getEncoder)
      (.encode bytes-to-encode)
      (String. StandardCharsets/UTF_8)))

(comment
  (let [key-pair           (vouch.crypto/generate-ec-key-pair)
        private-key        (.getPrivate key-pair)
        private-key-base64 (-> private-key .getEncoded vouch.crypto/base64-encode)]
    (println (str "-----BEGIN EC PRIVATE KEY-----\n" private-key-base64 "\n-----END EC PRIVATE KEY-----"))))

This is a private EC key in SEC1 format, which is not supported by WebCrypto, s. here for the supported formats.
A format supported by WebCrypto for private keys is PKCS#8 (which, by the way, you have already used in your WebCrypto code as the 1st parameter in the importKey() call), so a possible fix would be to convert the key to this format, eg with OpenSSL:

openssl pkcs8 -topk8 -nocrypt -in <path to input-sec1-pem> -out <path to output-pkcs8-pem>

which gives:

-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg65DYO7lDdsTTDNjC
oiYaNtvrMBJuh/foxV5FAxN84DmhRANCAAStLP0Ug7Wws9yImMduP8R25g0KVp4I
GFC5Tlk+HbhhG8cbkVcs2JXV08gHTYrIpeJiO8uujnzq5gORjNo+TNs7
-----END PRIVATE KEY-----

Both formats represent the same key (ie encapsulate the same key parameters, ie the same raw private key and the same raw public key) as can be verified in an ASN.1 parser (eg https://lapo.it/asn1js/ )

With the key in PKCS#8 format the import is successful:

 (async () => { function b642ab(base64_string){ return Uint8Array.from(window.atob(base64_string), c => c.charCodeAt(0)); } let der = b642ab("MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg65DYO7lDdsTTDNjCoiYaNtvrMBJuh/foxV5FAxN84DmhRANCAAStLP0Ug7Wws9yImMduP8R25g0KVp4IGFC5Tlk+HbhhG8cbkVcs2JXV08gHTYrIpeJiO8uujnzq5gORjNo+TNs7") let key = await crypto.subtle.importKey( 'pkcs8', der, { name: 'ECDSA', namedCurve: 'P-256', }, false, ['sign'] ); console.log(key); })();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM