如何将 .p12 转换为包含未加密 PKCS#1 私钥块的 .pem?
How can I convert a .p12 to a .pem containing an unencrypted PKCS#1 private key block?
我有一个 Certificates.p12
文件,我希望将其转换为 certificates.pem
,其中包含 PKCS#1 格式的未加密私钥。我以前可以通过 运行:
做到这一点
openssl pkcs12 -in Certificates.p12 -out certificates.pem -nodes -clcerts
生成的 certificates.pem
文件有一个 PRIVATE KEY
PEM 块,正如预期的那样。但是,the library I'm using does not understand this PEM block, because it expects it to be a PKCS#1 private key. The ASN.1 structure of a PKCS#1 private key is defined by RFC 3447 为:
RSAPrivateKey ::= SEQUENCE {
version Version,
modulus INTEGER, -- n
publicExponent INTEGER, -- e
privateExponent INTEGER, -- d
prime1 INTEGER, -- p
prime2 INTEGER, -- q
exponent1 INTEGER, -- d mod (p-1)
exponent2 INTEGER, -- d mod (q-1)
coefficient INTEGER, -- (inverse of q) mod p
otherPrimeInfos OtherPrimeInfos OPTIONAL
}
我的 certificates.pem
中的坏私钥块没有这个 PKCS#1 结构!相反,它的 ASN.1 结构如下所示:
$ openssl asn1parse -i -in badprivatekey.pem
0:d=0 hl=4 l=1212 cons: SEQUENCE
4:d=1 hl=2 l= 1 prim: INTEGER :00
7:d=1 hl=2 l= 13 cons: SEQUENCE
9:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption
20:d=2 hl=2 l= 0 prim: NULL
22:d=1 hl=4 l=1190 prim: OCTET STRING [HEX DUMP]:308204A...very long hex...
上面的格式是什么? The documentation for openssl pkcs12
只是含糊地说它的输出是“以 PEM 格式编写的”。我需要更强的保证私钥 PEM 块是 PKCS#1 格式。
奇怪的是 openssl rsa
理解“坏”私钥的奇怪格式,并且可以将其转换为正确的 PKCS#1 结构:
openssl rsa -in badprivatekey.pem -out goodprivatekey.pem
虽然 openssl rsa
理解输入文件,但该工具似乎无法告诉我 为什么 ,即输入文件的格式是什么。
openssl pkcs12
的输出格式是什么?具体它的私钥块是什么格式呢?如何让 openssl pkcs12
输出正确的 PKCS#1 私钥?
哇,那个库假定任何以 PRIVATE KEY
结尾的 PEM 必须是 PKCS1?那是非常错误的。有 几种 xx PRIVATE KEY
格式,只有 一种 是 PKCS1,见下文。
Meta:我认为这是一个骗局,但我找不到,所以无论如何都要回答。
OpenSSL 支持四种不同的 RSA 私钥 PEM 格式:
'traditional' 或 'legacy' 未加密,这是您想要的 PKCS1 格式 (https://www.rfc-editor.org/rfc/rfc8017#appendix-A.1.2),PEM 类型 RSA PRIVATE KEY
(不仅仅是 PRIVATE KEY
)
'traditional' 或 'legacy' 使用 OpenSSL(SSLeay 的)自定义方案在 PEM 级别加密,该方案使用非常差(且无法修复)的 PBKDF;这具有相同的 PEM 类型 RSA PRIVATE KEY
但添加了 headers Proc-type
和 DEK-info
PKCS8 standard/generic 未加密 (https://www.rfc-editor.org/rfc/rfc5208#section-5),PEM 类型 PRIVATE KEY
;这是一个简单的 ASN.1 包装器,包含算法的标识符(即 RSA 的 OID)加上包含 algorithm-dependent 部分的 OCTET STRING,对于 RSA 是 PKCS1
PKCS8 standard/generic 加密 (https://www.rfc-editor.org/rfc/rfc5208#section-6),PEM 类型 ENCRYPTED PRIVATE KEY
;这使用通常默认至少为 PBKDF2-SHA1-2048 的算法对 ASN.1 中的 PKCS8 数据进行加密
因为 PKCS8 更灵活,并且是标准的(并且相当常用,例如 Java),并且具有更好的加密性,因此通常是首选;请参阅 the manpage for the PEM_read/write functions for keys and some but not all other things.
的注释部分
所有读取 PEM 私钥的 OpenSSL 函数都可以读取其中的任何一个(必要时提供正确的密码),但它们写入的内容因函数和范围选项而异。如您所见,pkcs12 (import)
(当前)写入 PKCS8,但 rsa
(始终)写入 traditional/PKCS1.
您的选择是:
使用 rsa
(如您所做),或在 1.1.0 pkey -traditional
中转换为传统
在 1.0.0 之前的版本中使用 pkcs12
,例如 0.9.8,当它编写传统格式时(对于多种算法,而不仅仅是 RSA)。当然,使用过时且不受支持的版本可能会使您面临缺陷甚至漏洞,这些漏洞已在以后的版本中修复。
从(未加密或解密的)PKCS8 中提取 PKCS1 部分。 OpenSSL 对键使用 DER,这意味着 algorithm-dependent blob,即最后一组中最后一个字段的值,始终是数据的连续最后一部分。例如:
# note using -passin on commandline can be insecure (see the man page)
# but is used in these examples for simplicity; for real keys
# often better to omit the option and let the program prompt
$ openssl pkcs12 -in SO47599544.p12 -passin pass:sekrit -nocerts -nodes
MAC verified OK
Bag Attributes
friendlyName: mykey
localKeyID: 54 69 6D 65 20 31 35 31 32 31 37 30 38 39 39 33 33 37
Key Attributes: <No Attributes>
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCnWIGH4p1FHOP2
wtVbxuyvSHpBGd2v+7AyVHG4EJ/9WRoWN4+aGYUOGxzdTyDxk9e7DCTjuY6ciNTh
Ph74LADfQQ0B8yGkRtKer3vO1Dg7+6ErCcIGgsfrhZqpuUfod4nSU/LnHXoAAgN5
07LVvohrJMSRTA55jn356EDv31sz/dew1ThzHjYTShGbXh0/baqLxpmm4e8OixAL
YV1glHnIdr4h6wrwkJ6TtNexc3xTLwtRf9k7pJPvg+viGh7RTqhbUcGSV+dLelNe
653LbElHtAByz4Ti9e4vUKFuzxqsaWaSYGpzxF/pdthQawV/fTa9CjLGJFFrnVqc
KT3TSJ19AgMBAAECggEAOmmubRwxAVrgR9YiW3LIUzbdVbQNqcwU6LyJJVLIRcrA
TFkAiy21QAM+xBFG0oxklSncBpFSslkg1a61aLMTatpuC+wuJgWCp1lhwgRZzLY8
v6UcUOF9nzx3jB7cdsyjEwOymfG0ECSjyfaXSfzD6YJgCsedldijKIRlhlVUpIS4
YvdPPGQMXxLr9K8dkQ9o5yTQCrpey1/dNEo7lS17/uMV++dxmka5J+/dRcm2AAIc
7dk6OX9MpGKPFODUyvFjdrWPR2qK25cmVW6hrhJuaPih+1eSd78UkR7OdoHBQEbJ
5MoXSO0eTV4rhid+dX+ynwXA2OvaZbxcr7rlZXjaAQKBgQDybaKW32RHVmjKQDXC
xyTdQTMJV7JClBKeXjqJxbgKDhKFTiapn7kNVbJ594n7twuxmTxxoN35gamsbe7q
HjEesZZvb2vgLTXnqSvSXcl32CEi554VjlNP6+jZ5JBu/Gw7qObKuWBt+/gkrtCx
d09xQllZlD354RyfS3+9jzdEXQKBgQCwttL+Gw2WEm4dPQrfxbasXKQ5hNSE42j+
i0W26xv8o1lKQFip0A4YWidfI+Cvued944ZqCTvnPv6Z+JQzidHFjg6DXWgs1GK/
olsh5xO0hoxAj1azx+11ZHKSb7Kni+jSJsz40U35mWE805HFijxzzQz45unuPZGr
d8oqXIcroQKBgQCKuU32w7JgWAPy6DdbVBW2Pl70E6jADHdzBDy/JdMgfdj/Sy84
lVuRU96jiJD+50nbwPIjm4gqBJaRQv8aHVjCVaDd94Zla7mS7O1UnbJxz812ac++
SglGjJpcRTyZJfzRTt9yVg3mIe9nHlnxk3J0PyFd70Rfvv9f8BYS5OcdSQKBgBnb
xug0ITrSm5ZftlWkYuS58bYQ/+AqPtTwoFTx9nhzlr9MxyyiK03Y82XypBBSzdMY
FjUyALgH+c2iGF2qTy3vaaRDaNkWgxSzt04wuCt0fNV9pBxOpyrEdheDjMsDqCAI
WXoXdqeNkDMMaopTfiEb4kgR0i1wiP5kWwrz2zvBAoGBAPELu0IH3jtvo849KeXW
O6U1QlxdmWS6h/La1iVRHoE2U3pxAj39IDx4P6GMrgc9VLqRKLTO1Cu9giimO2jH
8iryT5VTlrrINL3M4vXAFjSN/xwVsrLaw/mAQPOKBwNlDwxcCrlxnANnYXdrhk8n
uNmZ2VH8flBFRpSbm9aisgMr
-----END PRIVATE KEY-----
$ openssl pkcs12 -in SO47599544.p12 -passin pass:sekrit -nocerts -nodes \
| sed -e 1,/-BEGIN/d -e /-END/,$d | openssl asn1parse
MAC verified OK
0:d=0 hl=4 l=1214 cons: SEQUENCE
4:d=1 hl=2 l= 1 prim: INTEGER :00
7:d=1 hl=2 l= 13 cons: SEQUENCE
9:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption
20:d=2 hl=2 l= 0 prim: NULL
22:d=1 hl=4 l=1192 prim: OCTET STRING [HEX DUMP]:308204A4[rest snipped]
[that's PKCS8 with algo-dependent part in the OCTET STRING at offset 22]
[with a tag-length header length of 4 (the hl=4)]
您可以使用 asn1parse -strparse
:
提取 PKCS1 部分
$ openssl pkcs12 -in SO47599544.p12 -passin pass:sekrit -nocerts -nodes \
| sed -e 1,/-BEGIN/d -e /-END/,$d \
| openssl asn1parse -strparse 22 -out SO47599544.raw -noout
MAC verified OK
$ openssl asn1parse -in SO47599544.raw -inform der
0:d=0 hl=4 l=1188 cons: SEQUENCE
4:d=1 hl=2 l= 1 prim: INTEGER :00
7:d=1 hl=4 l= 257 prim: INTEGER :[snipped]
268:d=1 hl=2 l= 3 prim: INTEGER :010001
273:d=1 hl=4 l= 256 prim: INTEGER :[snipped]
[rest snipped -- that's your PKCS1 format but in der so convert to pem]
$ (echo -----BEGIN RSA PRIVATE KEY-----; openssl base64 -in SO47599544.raw; \
echo -----END RSA PRIVATE KEY-----) | tee SO47599544.pem
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAp1iBh+KdRRzj9sLVW8bsr0h6QRndr/uwMlRxuBCf/VkaFjeP
mhmFDhsc3U8g8ZPXuwwk47mOnIjU4T4e+CwA30ENAfMhpEbSnq97ztQ4O/uhKwnC
BoLH64WaqblH6HeJ0lPy5x16AAIDedOy1b6IayTEkUwOeY59+ehA799bM/3XsNU4
cx42E0oRm14dP22qi8aZpuHvDosQC2FdYJR5yHa+IesK8JCek7TXsXN8Uy8LUX/Z
O6ST74Pr4hoe0U6oW1HBklfnS3pTXuudy2xJR7QAcs+E4vXuL1Chbs8arGlmkmBq
c8Rf6XbYUGsFf302vQoyxiRRa51anCk900idfQIDAQABAoIBADpprm0cMQFa4EfW
IltyyFM23VW0DanMFOi8iSVSyEXKwExZAIsttUADPsQRRtKMZJUp3AaRUrJZINWu
tWizE2rabgvsLiYFgqdZYcIEWcy2PL+lHFDhfZ88d4we3HbMoxMDspnxtBAko8n2
l0n8w+mCYArHnZXYoyiEZYZVVKSEuGL3TzxkDF8S6/SvHZEPaOck0Aq6Xstf3TRK
O5Ute/7jFfvncZpGuSfv3UXJtgACHO3ZOjl/TKRijxTg1MrxY3a1j0dqituXJlVu
oa4Sbmj4oftXkne/FJEeznaBwUBGyeTKF0jtHk1eK4YnfnV/sp8FwNjr2mW8XK+6
5WV42gECgYEA8m2ilt9kR1ZoykA1wsck3UEzCVeyQpQSnl46icW4Cg4ShU4mqZ+5
DVWyefeJ+7cLsZk8caDd+YGprG3u6h4xHrGWb29r4C0156kr0l3Jd9ghIueeFY5T
T+vo2eSQbvxsO6jmyrlgbfv4JK7QsXdPcUJZWZQ9+eEcn0t/vY83RF0CgYEAsLbS
/hsNlhJuHT0K38W2rFykOYTUhONo/otFtusb/KNZSkBYqdAOGFonXyPgr7nnfeOG
agk75z7+mfiUM4nRxY4Og11oLNRiv6JbIecTtIaMQI9Ws8ftdWRykm+yp4vo0ibM
+NFN+ZlhPNORxYo8c80M+Obp7j2Rq3fKKlyHK6ECgYEAirlN9sOyYFgD8ug3W1QV
tj5e9BOowAx3cwQ8vyXTIH3Y/0svOJVbkVPeo4iQ/udJ28DyI5uIKgSWkUL/Gh1Y
wlWg3feGZWu5kuztVJ2ycc/NdmnPvkoJRoyaXEU8mSX80U7fclYN5iHvZx5Z8ZNy
dD8hXe9EX77/X/AWEuTnHUkCgYAZ28boNCE60puWX7ZVpGLkufG2EP/gKj7U8KBU
8fZ4c5a/TMcsoitN2PNl8qQQUs3TGBY1MgC4B/nNohhdqk8t72mkQ2jZFoMUs7dO
MLgrdHzVfaQcTqcqxHYXg4zLA6ggCFl6F3anjZAzDGqKU34hG+JIEdItcIj+ZFsK
89s7wQKBgQDxC7tCB947b6POPSnl1julNUJcXZlkuofy2tYlUR6BNlN6cQI9/SA8
eD+hjK4HPVS6kSi0ztQrvYIopjtox/Iq8k+VU5a6yDS9zOL1wBY0jf8cFbKy2sP5
gEDzigcDZQ8MXAq5cZwDZ2F3a4ZPJ7jZmdlR/H5QRUaUm5vWorIDKw==
-----END RSA PRIVATE KEY-----
或者您可以将 PKCS8 body 转换为二进制文件并丢弃前 22+4=26 个字节(因为 header len hl=4 来自上面的第一个 asn1parse):
$ openssl pkcs12 -in SO47599544.p12 -passin pass:sekrit -nocerts -nodes \
| sed -e 1,/-BEGIN/d -e /-END/,$d \
| openssl base64 -d | dd bs=1 skip=26 >SO47599544.raw
MAC verified OK
1192+0 records in
1192+0 records out
1192 bytes (1.2 kB) copied, 0.00892462 s, 134 kB/s
[then convert to PEM with echo BEGIN;base64(encode);echo END as above]
PS:如果只读取一次 PKCS12 很重要,例如为了避免重新输入密码,您可以使用 awk like
openssl pkcs12 -in file.p12 | \
awk '/BEGIN PRIVATE/,/END PRIVATE/{t=t [=13=] RS;next}1; \
END{process t as the whole PRIVATE KEY PEM}'
或
openssl pkcs12 -in file.p12 | \
awk '/BEGIN PRIVATE/{f=1;next}/END PRIVATE/{f=0;next}f{t=t [=14=] RS;next}1; \
END{process t as just the base64 body}'
我有一个 Certificates.p12
文件,我希望将其转换为 certificates.pem
,其中包含 PKCS#1 格式的未加密私钥。我以前可以通过 运行:
openssl pkcs12 -in Certificates.p12 -out certificates.pem -nodes -clcerts
生成的 certificates.pem
文件有一个 PRIVATE KEY
PEM 块,正如预期的那样。但是,the library I'm using does not understand this PEM block, because it expects it to be a PKCS#1 private key. The ASN.1 structure of a PKCS#1 private key is defined by RFC 3447 为:
RSAPrivateKey ::= SEQUENCE {
version Version,
modulus INTEGER, -- n
publicExponent INTEGER, -- e
privateExponent INTEGER, -- d
prime1 INTEGER, -- p
prime2 INTEGER, -- q
exponent1 INTEGER, -- d mod (p-1)
exponent2 INTEGER, -- d mod (q-1)
coefficient INTEGER, -- (inverse of q) mod p
otherPrimeInfos OtherPrimeInfos OPTIONAL
}
我的 certificates.pem
中的坏私钥块没有这个 PKCS#1 结构!相反,它的 ASN.1 结构如下所示:
$ openssl asn1parse -i -in badprivatekey.pem
0:d=0 hl=4 l=1212 cons: SEQUENCE
4:d=1 hl=2 l= 1 prim: INTEGER :00
7:d=1 hl=2 l= 13 cons: SEQUENCE
9:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption
20:d=2 hl=2 l= 0 prim: NULL
22:d=1 hl=4 l=1190 prim: OCTET STRING [HEX DUMP]:308204A...very long hex...
上面的格式是什么? The documentation for openssl pkcs12
只是含糊地说它的输出是“以 PEM 格式编写的”。我需要更强的保证私钥 PEM 块是 PKCS#1 格式。
奇怪的是 openssl rsa
理解“坏”私钥的奇怪格式,并且可以将其转换为正确的 PKCS#1 结构:
openssl rsa -in badprivatekey.pem -out goodprivatekey.pem
虽然 openssl rsa
理解输入文件,但该工具似乎无法告诉我 为什么 ,即输入文件的格式是什么。
openssl pkcs12
的输出格式是什么?具体它的私钥块是什么格式呢?如何让 openssl pkcs12
输出正确的 PKCS#1 私钥?
哇,那个库假定任何以 PRIVATE KEY
结尾的 PEM 必须是 PKCS1?那是非常错误的。有 几种 xx PRIVATE KEY
格式,只有 一种 是 PKCS1,见下文。
Meta:我认为这是一个骗局,但我找不到,所以无论如何都要回答。
OpenSSL 支持四种不同的 RSA 私钥 PEM 格式:
'traditional' 或 'legacy' 未加密,这是您想要的 PKCS1 格式 (https://www.rfc-editor.org/rfc/rfc8017#appendix-A.1.2),PEM 类型
RSA PRIVATE KEY
(不仅仅是PRIVATE KEY
)'traditional' 或 'legacy' 使用 OpenSSL(SSLeay 的)自定义方案在 PEM 级别加密,该方案使用非常差(且无法修复)的 PBKDF;这具有相同的 PEM 类型
RSA PRIVATE KEY
但添加了 headersProc-type
和DEK-info
PKCS8 standard/generic 未加密 (https://www.rfc-editor.org/rfc/rfc5208#section-5),PEM 类型
PRIVATE KEY
;这是一个简单的 ASN.1 包装器,包含算法的标识符(即 RSA 的 OID)加上包含 algorithm-dependent 部分的 OCTET STRING,对于 RSA 是 PKCS1PKCS8 standard/generic 加密 (https://www.rfc-editor.org/rfc/rfc5208#section-6),PEM 类型
ENCRYPTED PRIVATE KEY
;这使用通常默认至少为 PBKDF2-SHA1-2048 的算法对 ASN.1 中的 PKCS8 数据进行加密
因为 PKCS8 更灵活,并且是标准的(并且相当常用,例如 Java),并且具有更好的加密性,因此通常是首选;请参阅 the manpage for the PEM_read/write functions for keys and some but not all other things.
的注释部分所有读取 PEM 私钥的 OpenSSL 函数都可以读取其中的任何一个(必要时提供正确的密码),但它们写入的内容因函数和范围选项而异。如您所见,pkcs12 (import)
(当前)写入 PKCS8,但 rsa
(始终)写入 traditional/PKCS1.
您的选择是:
使用
rsa
(如您所做),或在 1.1.0pkey -traditional
中转换为传统在 1.0.0 之前的版本中使用
pkcs12
,例如 0.9.8,当它编写传统格式时(对于多种算法,而不仅仅是 RSA)。当然,使用过时且不受支持的版本可能会使您面临缺陷甚至漏洞,这些漏洞已在以后的版本中修复。从(未加密或解密的)PKCS8 中提取 PKCS1 部分。 OpenSSL 对键使用 DER,这意味着 algorithm-dependent blob,即最后一组中最后一个字段的值,始终是数据的连续最后一部分。例如:
# note using -passin on commandline can be insecure (see the man page)
# but is used in these examples for simplicity; for real keys
# often better to omit the option and let the program prompt
$ openssl pkcs12 -in SO47599544.p12 -passin pass:sekrit -nocerts -nodes
MAC verified OK
Bag Attributes
friendlyName: mykey
localKeyID: 54 69 6D 65 20 31 35 31 32 31 37 30 38 39 39 33 33 37
Key Attributes: <No Attributes>
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCnWIGH4p1FHOP2
wtVbxuyvSHpBGd2v+7AyVHG4EJ/9WRoWN4+aGYUOGxzdTyDxk9e7DCTjuY6ciNTh
Ph74LADfQQ0B8yGkRtKer3vO1Dg7+6ErCcIGgsfrhZqpuUfod4nSU/LnHXoAAgN5
07LVvohrJMSRTA55jn356EDv31sz/dew1ThzHjYTShGbXh0/baqLxpmm4e8OixAL
YV1glHnIdr4h6wrwkJ6TtNexc3xTLwtRf9k7pJPvg+viGh7RTqhbUcGSV+dLelNe
653LbElHtAByz4Ti9e4vUKFuzxqsaWaSYGpzxF/pdthQawV/fTa9CjLGJFFrnVqc
KT3TSJ19AgMBAAECggEAOmmubRwxAVrgR9YiW3LIUzbdVbQNqcwU6LyJJVLIRcrA
TFkAiy21QAM+xBFG0oxklSncBpFSslkg1a61aLMTatpuC+wuJgWCp1lhwgRZzLY8
v6UcUOF9nzx3jB7cdsyjEwOymfG0ECSjyfaXSfzD6YJgCsedldijKIRlhlVUpIS4
YvdPPGQMXxLr9K8dkQ9o5yTQCrpey1/dNEo7lS17/uMV++dxmka5J+/dRcm2AAIc
7dk6OX9MpGKPFODUyvFjdrWPR2qK25cmVW6hrhJuaPih+1eSd78UkR7OdoHBQEbJ
5MoXSO0eTV4rhid+dX+ynwXA2OvaZbxcr7rlZXjaAQKBgQDybaKW32RHVmjKQDXC
xyTdQTMJV7JClBKeXjqJxbgKDhKFTiapn7kNVbJ594n7twuxmTxxoN35gamsbe7q
HjEesZZvb2vgLTXnqSvSXcl32CEi554VjlNP6+jZ5JBu/Gw7qObKuWBt+/gkrtCx
d09xQllZlD354RyfS3+9jzdEXQKBgQCwttL+Gw2WEm4dPQrfxbasXKQ5hNSE42j+
i0W26xv8o1lKQFip0A4YWidfI+Cvued944ZqCTvnPv6Z+JQzidHFjg6DXWgs1GK/
olsh5xO0hoxAj1azx+11ZHKSb7Kni+jSJsz40U35mWE805HFijxzzQz45unuPZGr
d8oqXIcroQKBgQCKuU32w7JgWAPy6DdbVBW2Pl70E6jADHdzBDy/JdMgfdj/Sy84
lVuRU96jiJD+50nbwPIjm4gqBJaRQv8aHVjCVaDd94Zla7mS7O1UnbJxz812ac++
SglGjJpcRTyZJfzRTt9yVg3mIe9nHlnxk3J0PyFd70Rfvv9f8BYS5OcdSQKBgBnb
xug0ITrSm5ZftlWkYuS58bYQ/+AqPtTwoFTx9nhzlr9MxyyiK03Y82XypBBSzdMY
FjUyALgH+c2iGF2qTy3vaaRDaNkWgxSzt04wuCt0fNV9pBxOpyrEdheDjMsDqCAI
WXoXdqeNkDMMaopTfiEb4kgR0i1wiP5kWwrz2zvBAoGBAPELu0IH3jtvo849KeXW
O6U1QlxdmWS6h/La1iVRHoE2U3pxAj39IDx4P6GMrgc9VLqRKLTO1Cu9giimO2jH
8iryT5VTlrrINL3M4vXAFjSN/xwVsrLaw/mAQPOKBwNlDwxcCrlxnANnYXdrhk8n
uNmZ2VH8flBFRpSbm9aisgMr
-----END PRIVATE KEY-----
$ openssl pkcs12 -in SO47599544.p12 -passin pass:sekrit -nocerts -nodes \
| sed -e 1,/-BEGIN/d -e /-END/,$d | openssl asn1parse
MAC verified OK
0:d=0 hl=4 l=1214 cons: SEQUENCE
4:d=1 hl=2 l= 1 prim: INTEGER :00
7:d=1 hl=2 l= 13 cons: SEQUENCE
9:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption
20:d=2 hl=2 l= 0 prim: NULL
22:d=1 hl=4 l=1192 prim: OCTET STRING [HEX DUMP]:308204A4[rest snipped]
[that's PKCS8 with algo-dependent part in the OCTET STRING at offset 22]
[with a tag-length header length of 4 (the hl=4)]
您可以使用 asn1parse -strparse
:
$ openssl pkcs12 -in SO47599544.p12 -passin pass:sekrit -nocerts -nodes \
| sed -e 1,/-BEGIN/d -e /-END/,$d \
| openssl asn1parse -strparse 22 -out SO47599544.raw -noout
MAC verified OK
$ openssl asn1parse -in SO47599544.raw -inform der
0:d=0 hl=4 l=1188 cons: SEQUENCE
4:d=1 hl=2 l= 1 prim: INTEGER :00
7:d=1 hl=4 l= 257 prim: INTEGER :[snipped]
268:d=1 hl=2 l= 3 prim: INTEGER :010001
273:d=1 hl=4 l= 256 prim: INTEGER :[snipped]
[rest snipped -- that's your PKCS1 format but in der so convert to pem]
$ (echo -----BEGIN RSA PRIVATE KEY-----; openssl base64 -in SO47599544.raw; \
echo -----END RSA PRIVATE KEY-----) | tee SO47599544.pem
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAp1iBh+KdRRzj9sLVW8bsr0h6QRndr/uwMlRxuBCf/VkaFjeP
mhmFDhsc3U8g8ZPXuwwk47mOnIjU4T4e+CwA30ENAfMhpEbSnq97ztQ4O/uhKwnC
BoLH64WaqblH6HeJ0lPy5x16AAIDedOy1b6IayTEkUwOeY59+ehA799bM/3XsNU4
cx42E0oRm14dP22qi8aZpuHvDosQC2FdYJR5yHa+IesK8JCek7TXsXN8Uy8LUX/Z
O6ST74Pr4hoe0U6oW1HBklfnS3pTXuudy2xJR7QAcs+E4vXuL1Chbs8arGlmkmBq
c8Rf6XbYUGsFf302vQoyxiRRa51anCk900idfQIDAQABAoIBADpprm0cMQFa4EfW
IltyyFM23VW0DanMFOi8iSVSyEXKwExZAIsttUADPsQRRtKMZJUp3AaRUrJZINWu
tWizE2rabgvsLiYFgqdZYcIEWcy2PL+lHFDhfZ88d4we3HbMoxMDspnxtBAko8n2
l0n8w+mCYArHnZXYoyiEZYZVVKSEuGL3TzxkDF8S6/SvHZEPaOck0Aq6Xstf3TRK
O5Ute/7jFfvncZpGuSfv3UXJtgACHO3ZOjl/TKRijxTg1MrxY3a1j0dqituXJlVu
oa4Sbmj4oftXkne/FJEeznaBwUBGyeTKF0jtHk1eK4YnfnV/sp8FwNjr2mW8XK+6
5WV42gECgYEA8m2ilt9kR1ZoykA1wsck3UEzCVeyQpQSnl46icW4Cg4ShU4mqZ+5
DVWyefeJ+7cLsZk8caDd+YGprG3u6h4xHrGWb29r4C0156kr0l3Jd9ghIueeFY5T
T+vo2eSQbvxsO6jmyrlgbfv4JK7QsXdPcUJZWZQ9+eEcn0t/vY83RF0CgYEAsLbS
/hsNlhJuHT0K38W2rFykOYTUhONo/otFtusb/KNZSkBYqdAOGFonXyPgr7nnfeOG
agk75z7+mfiUM4nRxY4Og11oLNRiv6JbIecTtIaMQI9Ws8ftdWRykm+yp4vo0ibM
+NFN+ZlhPNORxYo8c80M+Obp7j2Rq3fKKlyHK6ECgYEAirlN9sOyYFgD8ug3W1QV
tj5e9BOowAx3cwQ8vyXTIH3Y/0svOJVbkVPeo4iQ/udJ28DyI5uIKgSWkUL/Gh1Y
wlWg3feGZWu5kuztVJ2ycc/NdmnPvkoJRoyaXEU8mSX80U7fclYN5iHvZx5Z8ZNy
dD8hXe9EX77/X/AWEuTnHUkCgYAZ28boNCE60puWX7ZVpGLkufG2EP/gKj7U8KBU
8fZ4c5a/TMcsoitN2PNl8qQQUs3TGBY1MgC4B/nNohhdqk8t72mkQ2jZFoMUs7dO
MLgrdHzVfaQcTqcqxHYXg4zLA6ggCFl6F3anjZAzDGqKU34hG+JIEdItcIj+ZFsK
89s7wQKBgQDxC7tCB947b6POPSnl1julNUJcXZlkuofy2tYlUR6BNlN6cQI9/SA8
eD+hjK4HPVS6kSi0ztQrvYIopjtox/Iq8k+VU5a6yDS9zOL1wBY0jf8cFbKy2sP5
gEDzigcDZQ8MXAq5cZwDZ2F3a4ZPJ7jZmdlR/H5QRUaUm5vWorIDKw==
-----END RSA PRIVATE KEY-----
或者您可以将 PKCS8 body 转换为二进制文件并丢弃前 22+4=26 个字节(因为 header len hl=4 来自上面的第一个 asn1parse):
$ openssl pkcs12 -in SO47599544.p12 -passin pass:sekrit -nocerts -nodes \
| sed -e 1,/-BEGIN/d -e /-END/,$d \
| openssl base64 -d | dd bs=1 skip=26 >SO47599544.raw
MAC verified OK
1192+0 records in
1192+0 records out
1192 bytes (1.2 kB) copied, 0.00892462 s, 134 kB/s
[then convert to PEM with echo BEGIN;base64(encode);echo END as above]
PS:如果只读取一次 PKCS12 很重要,例如为了避免重新输入密码,您可以使用 awk like
openssl pkcs12 -in file.p12 | \
awk '/BEGIN PRIVATE/,/END PRIVATE/{t=t [=13=] RS;next}1; \
END{process t as the whole PRIVATE KEY PEM}'
或
openssl pkcs12 -in file.p12 | \
awk '/BEGIN PRIVATE/{f=1;next}/END PRIVATE/{f=0;next}f{t=t [=14=] RS;next}1; \
END{process t as just the base64 body}'