首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何将ECDSA密钥转换为PEM格式

如何将ECDSA密钥转换为PEM格式
EN

Stack Overflow用户
提问于 2018-01-04 18:17:01
回答 2查看 30.5K关注 0票数 11

我有一个的私有原始密钥,带有一个密码“test皮夹”,现在我试图在这个答案之后使用OpenSSL将它转换成PEM格式。

代码语言:javascript
运行
复制
echo "a140bd507a57360e2fa503298c035854f0dcb248bedabbe7a14db3920aaacf57" | xxd -r -p - | openssl ec -inform der -pubin -noout -passin pass:testwallet -text

但是这个错误出现了:

代码语言:javascript
运行
复制
read EC key
unable to load Key
140084694296480:error:0D06B08E:asn1 encoding routines:ASN1_D2I_READ_BIO:not enough data:a_d2i_fp.c:247:

更新:我没有公钥,相反,我想要生成它,这样以后我也可以生成Ethereum地址对应。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-01-04 20:09:19

您声称您的原始密钥是OpenSSL的DER格式,而它不是。此外,您还在复制私钥是公钥,但它不是,并且声称它的密码加密是错误的:公钥永远不会加密,而OpenSSL的“传统的‘aka’旧版算法中的私钥--特定于密码的DER格式(由心电图SEC1定义的)不能加密。( PKCS8格式的OTOH私钥可以在DER或PEM中进行密码加密,但PEM更方便。而FWIW PKCS12格式始终是密码加密的,而且始终是DER.)

ECC (ECDSA、ECDH、ECMQV等)的密钥总是相对于的一些‘曲线’(更准确地说,是在具有识别生成器aka基点的曲线上的素阶子群)。对于比特币,这是secp256k1,但你的问题并不是说它仅限于比特币,这个答案需要对其他使用其他曲线的应用程序进行修改。

--如果您还有公钥(作为未压缩点),您可以简单地使用来自https://bitcoin.stackexchange.com/questions/66594/signing-transaction-with-ssl-private-key-to-pem的解决方案。连接十六进制字符串:

代码语言:javascript
运行
复制
  a pre_string : 30740201010420
  the privkey  : (32 bytes as 64 hexits) 
  a mid_string : a00706052b8104000aa144034200 (identifies secp256k1) 
  the pubkey   : (65 bytes as 130 hexits)

然后要么将十六进制转换为二进制,然后按DER读取,要么将十六进制(可能通过二进制)转换为base64,然后用-----BEGIN/END EC PRIVATE KEY-----行进行包装,使其成为PEM。

--如果您没有公钥,可以稍微修改一下。连接十六进制字符串

代码语言:javascript
运行
复制
302e0201010420 privkey_32bytes_64hexits a00706052b8104000a 

并转换为二进制,然后读入openssl ec -inform d。注OpenSSL将从给定曲线的私钥中派生出公钥,但实际上不会将其存储在PEM输出中,因此无法保证使用OpenSSL以外的软件进行读取。您可能需要使用openssl ec -text [-noout] (对PEM或DER输入都是方便的)来获取公钥值,然后返回并创建更完整的编码,其中包括上面提到的公钥。

补充说:,因为你似乎不理解答案中的单词,所以我会尽可能详细地说明这一点。

a140bd507a57360e2fa503298c035854f0dcb248bedabbe7a14db3920aaacf57是用十六进制表示的原始私钥。secp256k1私有值以二进制形式表示为32个字节;当二进制以十六进制表示时,每个字节采用两个十六进制数字,因此32个字节使用64十六进制数字。所有这些值都是原始私钥。没有由25位或25字节组成的任何部分都有任何有用的含义。不要采取任何25-任何部分的这个价值。

要构造没有公钥的私钥的OpenSSL/SECG表示,将表示私钥的十六进制字符串--所有这些都不需要修改--放在我展示的其他两个十六进制字符串之间,作为第二个选项:

代码语言:javascript
运行
复制
 302e0201010420 a140bd507a57360e2fa503298c035854f0dcb248bedabbe7a14db3920aaacf57 a00706052b8104000a 

然后将这个组合的十六进制字符串转换为二进制,并将结果读入openssl ec -inform d中。

代码语言:javascript
运行
复制
$ echo 302e0201010420 a140bd507a57360e2fa503298c035854f0dcb248bedabbe7a14db3920aaacf57 a00706052b8104000a | xxd -r -p >48101258.1
$ openssl ec -inform d <48101258.1
read EC key
writing EC key
-----BEGIN EC PRIVATE KEY-----
MC4CAQEEIKFAvVB6VzYOL6UDKYwDWFTw3LJIvtq756FNs5IKqs9XoAcGBSuBBAAK
-----END EC PRIVATE KEY-----

结果是PEM格式--但是PEM格式不包括公钥,这是您所需要的。若要查看字段(包括派生公钥),请添加-text;若要只查看字段而不查看-noout输出,请添加-noout

代码语言:javascript
运行
复制
$ openssl ec -inform d <48101258.1 -text -noout
read EC key
Private-Key: (256 bit)
priv:
    a1:40:bd:50:7a:57:36:0e:2f:a5:03:29:8c:03:58:
    54:f0:dc:b2:48:be:da:bb:e7:a1:4d:b3:92:0a:aa:
    cf:57
pub:
    04:20:ea:6d:8c:e7:bc:bb:48:33:69:b2:91:1c:75:
    e5:60:2a:34:28:be:44:96:e9:7f:14:ad:52:fd:4a:
    6a:a0:e3:60:83:9c:6e:db:32:2a:22:55:7c:70:1e:
    d0:fa:1e:06:cf:57:4f:be:17:bd:6a:85:51:69:c5:
    65:96:72:cf:a9
ASN1 OID: secp256k1

现在,如果您想要一个PEM格式的密钥,包括公钥,请同时使用私钥的十六进制字符串(所有64位数字)和新显示的公钥十六进制值,并将它们插入到我的第一个选项中。还请注意,ECC公钥是一个曲线点,可以是两种形式,压缩或未压缩;此处生成的表单是未压缩的。如果你需要压缩,我稍后再加。未压缩形式的secp256k1点为65个字节,以十六进制表示为130个十六进制数字。(其中openssl ec将15字节中的4行格式化为5字节。)

代码语言:javascript
运行
复制
$ echo 30740201010420 a140bd507a57360e2fa503298c035854f0dcb248bedabbe7a14db3920aaacf57 a00706052b8104000aa144034200 \
> 04:20:ea:6d:8c:e7:bc:bb:48:33:69:b2:91:1c:75: e5:60:2a:34:28:be:44:96:e9:7f:14:ad:52:fd:4a: \
> 6a:a0:e3:60:83:9c:6e:db:32:2a:22:55:7c:70:1e: d0:fa:1e:06:cf:57:4f:be:17:bd:6a:85:51:69:c5: \
> 65:96:72:cf:a9 | xxd -r -p >48101258.2
$ # note xxd -r -p ignores the colons; other hex programs may need them removed instead
$ openssl ec -inform d <48101258.2
read EC key
writing EC key
-----BEGIN EC PRIVATE KEY-----
MHQCAQEEIKFAvVB6VzYOL6UDKYwDWFTw3LJIvtq756FNs5IKqs9XoAcGBSuBBAAK
oUQDQgAEIOptjOe8u0gzabKRHHXlYCo0KL5Elul/FK1S/UpqoONgg5xu2zIqIlV8
cB7Q+h4Gz1dPvhe9aoVRacVllnLPqQ==
-----END EC PRIVATE KEY-----

为DavidS添加2019-02 :如K06a的答复中正确显示的

  • 中间字符串的第一部分(或我的专用选项的整个后缀) a00706052b8104000a是一个上下文标记和长度a007,用于包含2b8104000a (即1.3.132.0.10是secp256k1和length 0605 )的OID标记和长度0605
  • 我的中间字符串a144034200的其余部分是一个上下文标记和长度,包含BITSTRING的标记长度和未使用的位头,BITSTRING是作为未压缩点的原始公钥。

要执行secp256r1 (又名P-256 )或prime256v1,您需要将AlgId.OID更改为1.2.840.10045.3.1.7 (编码为a00a 0608 2a8648ce3d030107 )。p256r1的私钥和公钥值与p256k1的大小相同,但AlgId更长,因此还需要更改外部序列的长度。

代码语言:javascript
运行
复制
30770201010420 privatekey32bytes # note 77 
a00a06082a8648ce3d030107 a144034200 publicpoint65bytes 
票数 32
EN

Stack Overflow用户

发布于 2018-03-10 20:39:37

椭圆曲线私钥格式

代码语言:javascript
运行
复制
ECPrivateKey ::= SEQUENCE {
 version        INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
 privateKey     OCTET STRING,
 parameters [0] ECParameters {{ NamedCurve }} OPTIONAL,
 publicKey  [1] BIT STRING OPTIONAL
}

所以publicKeyOPTIONAL,理论上是可以忽略的。

下面是我的DER secp256k1私钥的示例:

代码语言:javascript
运行
复制
30740201 01042092 E768CB72 0DC16924 27D156DB 39630748 0D1507B9 A4958450
2574B9A0 922F4BA0 0706052B 8104000A A1440342 00041954 9737B704 D1789A57
82E3430E 8259F904 71326081 054854D2 A5D096F9 686D05B0 30D98BA3 C60C056E
204CEF61 C0AC5B53 A9A6B9A0 5AFF9DA2 6CA4B65B 2E84

试图分解:

代码语言:javascript
运行
复制
$ openssl asn1parse -inform DER -in <(echo "30740201 01042092 E768CB72 0DC16924 27D156DB 39630748 0D1507B9 A4958450 2574B9A0 922F4BA0 0706052B 8104000A A1440342 00041954 9737B704 D1789A57 82E3430E 8259F904 71326081 054854D2 A5D096F9 686D05B0 30D98BA3 C60C056E 204CEF61 C0AC5B53 A9A6B9A0 5AFF9DA2 6CA4B65B 2E84" | xxd -r -p)

ASN.1解析结果:

代码语言:javascript
运行
复制
 0:d=0  hl=2 l= 116 cons: SEQUENCE          
 2:d=1  hl=2 l=   1 prim: INTEGER           :01
 5:d=1  hl=2 l=  32 prim: OCTET STRING      [HEX DUMP]:92E768CB720DC1692427D156DB396307480D1507B9A49584502574B9A0922F4B
39:d=1  hl=2 l=   7 cons: cont [ 0 ]        
41:d=2  hl=2 l=   5 prim: OBJECT            :secp256k1
48:d=1  hl=2 l=  68 cons: cont [ 1 ]        
50:d=2  hl=2 l=  66 prim: BIT STRING  

详细信息(请参阅https://bitcoin.stackexchange.com/a/66622/22979):

代码语言:javascript
运行
复制
30 - ASN.1
74 - Length of all following bytes (116 bytes)

  02 - Type (integer)
  01 - Length of integer (1 byte)
  01 - Value of integer (1)

  04 - Type (octet string)
  20 - Length of string (32 bytes)
  92E768CB720DC1692427D156DB396307480D1507B9A49584502574B9A0922F4B - Private Key

  A0 - Tag 0
  07 - Length of tag (7 bytes)
  06 - Type (Object ID)
  05 - Length of the Object ID (5 bytes)
  2b 81 04 00 0a - The object ID of the curve secp256k1

  A1 - Tag 1
  44 - Length of tag (68 bytes)
  03 - Type – Bit string
  42 - Length of the bit string (66 bytes)
  00 - ???
  04 - Uncompressed Public Key
  19549737B704D1789A5782E3430E8259F90471326081054854D2A5D096F9686D - Public Key X coord
  05B030D98BA3C60C056E204CEF61C0AC5B53A9A6B9A05AFF9DA26CA4B65B2E84 - Public Key Y coord

我删除了公钥对象,并将ASN.1长度从116个字节(0x74)固定为46个字节(0x2e):

代码语言:javascript
运行
复制
$ openssl asn1parse -inform DER -in <(echo "302E020101042092E768CB720DC1692427D156DB396307480D1507B9A49584502574B9A0922F4BA00706052B8104000A" | xxd -r -p)

得到的结果:

代码语言:javascript
运行
复制
 0:d=0  hl=2 l=  46 cons: SEQUENCE          
 2:d=1  hl=2 l=   1 prim: INTEGER           :01
 5:d=1  hl=2 l=  32 prim: OCTET STRING      [HEX DUMP]:92E768CB720DC1692427D156DB396307480D1507B9A49584502574B9A0922F4B
39:d=1  hl=2 l=   7 cons: cont [ 0 ]        
41:d=2  hl=2 l=   5 prim: OBJECT            :secp256k1

试图获取公钥:

代码语言:javascript
运行
复制
$ openssl ec -inform DER -in <(echo "302E020101042092E768CB720DC1692427D156DB396307480D1507B9A49584502574B9A0922F4BA00706052B8104000A" | xxd -r -p)

结果:

代码语言:javascript
运行
复制
read EC key
writing EC key
-----BEGIN EC PRIVATE KEY-----
MC4CAQEEIJLnaMtyDcFpJCfRVts5YwdIDRUHuaSVhFAldLmgki9LoAcGBSuBBAAK
-----END EC PRIVATE KEY-----

再试一次:

代码语言:javascript
运行
复制
$ openssl ec -inform DER -text -in <(echo "302E020101042092E768CB720DC1692427D156DB396307480D1507B9A49584502574B9A0922F4BA00706052B8104000A" | xxd -r -p)

结果:

代码语言:javascript
运行
复制
read EC key
Segmentation fault: 11

我使用了OSX系统openssl --看起来像是LibreSSL 2.2.7

补充说:向LibreSSL报告了一个bug:https://github.com/libressl-portable/portable/issues/395 UPDATE: In最新macOS 10.15.1预装的openssl (LibreSSL 2.8.3)修复了这个错误。

然后我安装了最新的openssl:brew install openssl

代码语言:javascript
运行
复制
/usr/local/Cellar/openssl/1.0.2n/bin/openssl ec -inform DER -text -noout -in <(echo "302E020101042092E768CB720DC1692427D156DB396307480D1507B9A49584502574B9A0922F4BA00706052B8104000A" | xxd -r -p)

并得到:

代码语言:javascript
运行
复制
read EC key
Private-Key: (256 bit)
priv:
    00:92:e7:68:cb:72:0d:c1:69:24:27:d1:56:db:39:
    63:07:48:0d:15:07:b9:a4:95:84:50:25:74:b9:a0:
    92:2f:4b
pub: 
    04:19:54:97:37:b7:04:d1:78:9a:57:82:e3:43:0e:
    82:59:f9:04:71:32:60:81:05:48:54:d2:a5:d0:96:
    f9:68:6d:05:b0:30:d9:8b:a3:c6:0c:05:6e:20:4c:
    ef:61:c0:ac:5b:53:a9:a6:b9:a0:5a:ff:9d:a2:6c:
    a4:b6:5b:2e:84
ASN1 OID: secp256k1

最后解决办法:

代码语言:javascript
运行
复制
$ /usr/local/Cellar/openssl/1.0.2n/bin/openssl ec -inform DER -text -noout -in <(cat <(echo -n "302e0201010420") <(echo -n "***") <(echo -n "a00706052b8104000a") | xxd -r -p) 2>/dev/null | tail -6 | head -5 | sed 's/[ :]//g' | tr -d '\n' && echo

用十六进制私钥替换***

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48101258

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档