繁体   English   中英

无法将 OpenSSL 生成的私钥导入 web API crypto.subtle.importKey

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

我正在使用命令openssl ecparam -name secp256r1 -genkey -noout -out k1.pem创建一个私有 EC 密钥。 我正在尝试使用本文档中所述的crypto.subtle.importKey导入它。

即运行 OpenSSL 后我有私钥

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

并从 Chrome 控制台

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

从最后一个命令中得到一个Uncaught (in promise) Error


值得一提的是,当我通过 Clojure 使用 Java 库生成 EC 密钥时,我可以使用相同的 js 代码成功导入它:

(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-----"))))

这是 SEC1 格式的私有 EC 密钥,WebCrypto 不支持。 这里是支持的格式。
WebCrypto 支持的私钥格式是 PKCS#8(顺便说一下,您已经在 WebCrypto 代码中将其用作importKey()调用中的第一个参数),因此可能的解决方法是将密钥转换为这种格式,例如 OpenSSL:

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

这使:

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

两种格式都表示相同的密钥(即封装相同的密钥参数,即相同的原始私钥和相同的原始公钥),可以在 ASN.1 解析器中验证(例如https://lapo.it/asn1js/

使用 PKCS#8 格式的密钥导入成功:

 (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); })();

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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