Python导入PEM编码的ECC私钥失败
Python import of ECC private key in PEM encoding fails
我是 运行 Python 版本 3.8.2 并使用 pycryptodome 版本 3.9.9 以 PEM 编码导入 ECC 私钥,以便稍后签署一些数据。
以下 EC 私钥是一个示例密钥,我将其用于多个跨平台项目[例如Java, PHP, NodeJs] 它可以正常工作(它是 NIST P-256 / secp256r1-key)密钥:
ecprivatekey.pem:
-----BEGIN EC PRIVATE KEY-----
MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCAU2f8tzo99Z1HoxJlY
96yXUhFY5vppVjw1iPKRfk1wHA==
-----END EC PRIVATE KEY-----
在 Python 中使用此密钥失败:
Invalid DER encoding inside the PEM file
我看到使用 ASN1-dumper:
0 65: SEQUENCE {
2 1: INTEGER 0
5 19: SEQUENCE {
7 7: OBJECT IDENTIFIER ecPublicKey (1 2 840 10045 2 1)
16 8: OBJECT IDENTIFIER prime256v1 (1 2 840 10045 3 1 7)
: }
26 39: OCTET STRING, encapsulates {
28 37: SEQUENCE {
30 1: INTEGER 1
33 32: OCTET STRING
: 14 D9 FF 2D CE 8F 7D 67 51 E8 C4 99 58 F7 AC 97
: 52 11 58 E6 FA 69 56 3C 35 88 F2 91 7E 4D 70 1C
: }
: }
: }
现在我正在使用 OpenSSL 将此 PEM 文件转换为 DER 文件,并将结果编码为 Base64 以便在 Python:
中使用
openssl ec -in ecprivatekey.pem -outform DER -out ecprivatekey.der
openssl enc -base64 -in ecprivatekey.der -out ecprivatekey.der.base64
这是结果:
MDECAQEEIBTZ/y3Oj31nUejEmVj3rJdSEVjm+mlWPDWI8pF+TXAcoAoGCCqGSM49AwEH
运行 我的 import it 导入密钥成功:
EccKey(curve='NIST P-256', point_x=93061505133516819612094413624227760091937004899246228970231210633982641184160, point_y=83370390147869481338300161558578623699120044123289243047585106101294907287413, d=9431423964991629169983079041344798030398447908105071875075159616703093895196)
最后一步是将 DER 编码文件“重新转换”为 PEM 编码文件:
openssl ec -inform DER -in ecprivatekey.der -outform PEM -out ecprivatekey2.pem
这些是转换和 ASN1 转储的结果:
-----BEGIN EC PRIVATE KEY-----
MDECAQEEIBTZ/y3Oj31nUejEmVj3rJdSEVjm+mlWPDWI8pF+TXAcoAoGCCqGSM49
AwEH
-----END EC PRIVATE KEY-----
0 49: SEQUENCE {
2 1: INTEGER 1
5 32: OCTET STRING
: 14 D9 FF 2D CE 8F 7D 67 51 E8 C4 99 58 F7 AC 97
: 52 11 58 E6 FA 69 56 3C 35 88 F2 91 7E 4D 70 1C
39 10: [0] {
41 8: OBJECT IDENTIFIER prime256v1 (1 2 840 10045 3 1 7)
: }
: }
可以导入重新转换的密钥:
EccKey(curve='NIST P-256', point_x=93061505133516819612094413624227760091937004899246228970231210633982641184160, point_y=83370390147869481338300161558578623699120044123289243047585106101294907287413, d=9431423964991629169983079041344798030398447908105071875075159616703093895196)
所以我的问题是: 我的 EC 私钥有什么“错误”,因此它在 Java / PHP / NodeJs-Crypto / 中运行WebCrypto 但不在 Python 中?或者更好:如何在不进行任何进一步(外部)转换的情况下将现有的 EC 私钥导入 Python?
这是我导入测试程序的完整源代码:
from Crypto.PublicKey import ECC
import base64
print("Python import EC private key\n")
# trying to import the original EC private key
ecPrivateKeyPem = """-----BEGIN EC PRIVATE KEY-----
MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCAU2f8tzo99Z1HoxJlY
96yXUhFY5vppVjw1iPKRfk1wHA==
-----END EC PRIVATE KEY-----
"""
try:
ecPrivateKey = ECC.import_key(ecPrivateKeyPem)
print(ecPrivateKey)
except ValueError as e:
print(e)
#error: Invalid DER encoding inside the PEM file
# import of the DER encoded EC private key runs:
ecPrivateKeyDerBase64 = """MDECAQEEIBTZ/y3Oj31nUejEmVj3rJdSEVjm+mlWPDWI8pF+TXAcoAoGCCqGSM49AwEH"""
ecPrivateKeyDer = base64.decodebytes(ecPrivateKeyDerBase64.encode("ascii"))
try:
ecPrivateKey = ECC.import_key(ecPrivateKeyDer)
print("\necPrivateKeyDer")
print(ecPrivateKey)
except ValueError as e:
print(e)
ecPrivateKeyPem2 = """-----BEGIN EC PRIVATE KEY-----
MDECAQEEIBTZ/y3Oj31nUejEmVj3rJdSEVjm+mlWPDWI8pF+TXAcoAoGCCqGSM49
AwEH
-----END EC PRIVATE KEY-----
"""
try:
ecPrivateKey2 = ECC.import_key(ecPrivateKeyPem2)
print("\necPrivateKeyPem2")
print(ecPrivateKey2)
except ValueError as e:
print(e)
无法导入我的 EC 私钥的原因很简单 - 我的 EC 密钥包含(仅)私钥而不是 public 密钥。这对于 Java / PHP / NodeJs-Crypto / WebCrypto 似乎没问题(它们在后台“导出” public 密钥)但在 Python.
当我尝试在 Dart 中导入我的 EC 私钥时(使用 PointyCastle & Basics_Utils),我 运行 遇到了同样的问题,之后我用 OpenSSL 生成了一个完整的新密钥对, PKCS#8 编码的密钥具有以下结构(末尾的附加 BIT STRING 是 public 密钥):
0 135: SEQUENCE {
3 1: INTEGER 0
6 19: SEQUENCE {
8 7: OBJECT IDENTIFIER ecPublicKey (1 2 840 10045 2 1)
17 8: OBJECT IDENTIFIER prime256v1 (1 2 840 10045 3 1 7)
: }
27 109: OCTET STRING, encapsulates {
29 107: SEQUENCE {
31 1: INTEGER 1
34 32: OCTET STRING
: 72 23 ED FE 0B A5 CF 0E FF 5D ED 76 60 EB BF BC
: B5 20 21 46 7E EE 01 A8 E5 59 26 53 40 7E 81 45
68 68: [1] {
70 66: BIT STRING
: 04 31 91 E7 B7 50 F5 B5 D7 4B 34 69 44 1D 71 2D
: 13 0E 4A FC 6E 50 1E 48 1A 2E 2F 88 57 CE 28 89
: 5F 93 1E FF C3 A8 6C 58 0D 7D 85 E4 93 A4 7F 2B
: F7 EA 26 12 7F 99 5F 20 2E EA F5 E9 78 60 B9 E5
: C0
: }
: }
: }
: }
我是 运行 Python 版本 3.8.2 并使用 pycryptodome 版本 3.9.9 以 PEM 编码导入 ECC 私钥,以便稍后签署一些数据。
以下 EC 私钥是一个示例密钥,我将其用于多个跨平台项目[例如Java, PHP, NodeJs] 它可以正常工作(它是 NIST P-256 / secp256r1-key)密钥:
ecprivatekey.pem:
-----BEGIN EC PRIVATE KEY-----
MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCAU2f8tzo99Z1HoxJlY
96yXUhFY5vppVjw1iPKRfk1wHA==
-----END EC PRIVATE KEY-----
在 Python 中使用此密钥失败:
Invalid DER encoding inside the PEM file
我看到使用 ASN1-dumper:
0 65: SEQUENCE {
2 1: INTEGER 0
5 19: SEQUENCE {
7 7: OBJECT IDENTIFIER ecPublicKey (1 2 840 10045 2 1)
16 8: OBJECT IDENTIFIER prime256v1 (1 2 840 10045 3 1 7)
: }
26 39: OCTET STRING, encapsulates {
28 37: SEQUENCE {
30 1: INTEGER 1
33 32: OCTET STRING
: 14 D9 FF 2D CE 8F 7D 67 51 E8 C4 99 58 F7 AC 97
: 52 11 58 E6 FA 69 56 3C 35 88 F2 91 7E 4D 70 1C
: }
: }
: }
现在我正在使用 OpenSSL 将此 PEM 文件转换为 DER 文件,并将结果编码为 Base64 以便在 Python:
中使用openssl ec -in ecprivatekey.pem -outform DER -out ecprivatekey.der
openssl enc -base64 -in ecprivatekey.der -out ecprivatekey.der.base64
这是结果:
MDECAQEEIBTZ/y3Oj31nUejEmVj3rJdSEVjm+mlWPDWI8pF+TXAcoAoGCCqGSM49AwEH
运行 我的 import it 导入密钥成功:
EccKey(curve='NIST P-256', point_x=93061505133516819612094413624227760091937004899246228970231210633982641184160, point_y=83370390147869481338300161558578623699120044123289243047585106101294907287413, d=9431423964991629169983079041344798030398447908105071875075159616703093895196)
最后一步是将 DER 编码文件“重新转换”为 PEM 编码文件:
openssl ec -inform DER -in ecprivatekey.der -outform PEM -out ecprivatekey2.pem
这些是转换和 ASN1 转储的结果:
-----BEGIN EC PRIVATE KEY-----
MDECAQEEIBTZ/y3Oj31nUejEmVj3rJdSEVjm+mlWPDWI8pF+TXAcoAoGCCqGSM49
AwEH
-----END EC PRIVATE KEY-----
0 49: SEQUENCE {
2 1: INTEGER 1
5 32: OCTET STRING
: 14 D9 FF 2D CE 8F 7D 67 51 E8 C4 99 58 F7 AC 97
: 52 11 58 E6 FA 69 56 3C 35 88 F2 91 7E 4D 70 1C
39 10: [0] {
41 8: OBJECT IDENTIFIER prime256v1 (1 2 840 10045 3 1 7)
: }
: }
可以导入重新转换的密钥:
EccKey(curve='NIST P-256', point_x=93061505133516819612094413624227760091937004899246228970231210633982641184160, point_y=83370390147869481338300161558578623699120044123289243047585106101294907287413, d=9431423964991629169983079041344798030398447908105071875075159616703093895196)
所以我的问题是: 我的 EC 私钥有什么“错误”,因此它在 Java / PHP / NodeJs-Crypto / 中运行WebCrypto 但不在 Python 中?或者更好:如何在不进行任何进一步(外部)转换的情况下将现有的 EC 私钥导入 Python?
这是我导入测试程序的完整源代码:
from Crypto.PublicKey import ECC
import base64
print("Python import EC private key\n")
# trying to import the original EC private key
ecPrivateKeyPem = """-----BEGIN EC PRIVATE KEY-----
MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCAU2f8tzo99Z1HoxJlY
96yXUhFY5vppVjw1iPKRfk1wHA==
-----END EC PRIVATE KEY-----
"""
try:
ecPrivateKey = ECC.import_key(ecPrivateKeyPem)
print(ecPrivateKey)
except ValueError as e:
print(e)
#error: Invalid DER encoding inside the PEM file
# import of the DER encoded EC private key runs:
ecPrivateKeyDerBase64 = """MDECAQEEIBTZ/y3Oj31nUejEmVj3rJdSEVjm+mlWPDWI8pF+TXAcoAoGCCqGSM49AwEH"""
ecPrivateKeyDer = base64.decodebytes(ecPrivateKeyDerBase64.encode("ascii"))
try:
ecPrivateKey = ECC.import_key(ecPrivateKeyDer)
print("\necPrivateKeyDer")
print(ecPrivateKey)
except ValueError as e:
print(e)
ecPrivateKeyPem2 = """-----BEGIN EC PRIVATE KEY-----
MDECAQEEIBTZ/y3Oj31nUejEmVj3rJdSEVjm+mlWPDWI8pF+TXAcoAoGCCqGSM49
AwEH
-----END EC PRIVATE KEY-----
"""
try:
ecPrivateKey2 = ECC.import_key(ecPrivateKeyPem2)
print("\necPrivateKeyPem2")
print(ecPrivateKey2)
except ValueError as e:
print(e)
无法导入我的 EC 私钥的原因很简单 - 我的 EC 密钥包含(仅)私钥而不是 public 密钥。这对于 Java / PHP / NodeJs-Crypto / WebCrypto 似乎没问题(它们在后台“导出” public 密钥)但在 Python.
当我尝试在 Dart 中导入我的 EC 私钥时(使用 PointyCastle & Basics_Utils),我 运行 遇到了同样的问题,之后我用 OpenSSL 生成了一个完整的新密钥对, PKCS#8 编码的密钥具有以下结构(末尾的附加 BIT STRING 是 public 密钥):
0 135: SEQUENCE {
3 1: INTEGER 0
6 19: SEQUENCE {
8 7: OBJECT IDENTIFIER ecPublicKey (1 2 840 10045 2 1)
17 8: OBJECT IDENTIFIER prime256v1 (1 2 840 10045 3 1 7)
: }
27 109: OCTET STRING, encapsulates {
29 107: SEQUENCE {
31 1: INTEGER 1
34 32: OCTET STRING
: 72 23 ED FE 0B A5 CF 0E FF 5D ED 76 60 EB BF BC
: B5 20 21 46 7E EE 01 A8 E5 59 26 53 40 7E 81 45
68 68: [1] {
70 66: BIT STRING
: 04 31 91 E7 B7 50 F5 B5 D7 4B 34 69 44 1D 71 2D
: 13 0E 4A FC 6E 50 1E 48 1A 2E 2F 88 57 CE 28 89
: 5F 93 1E FF C3 A8 6C 58 0D 7D 85 E4 93 A4 7F 2B
: F7 EA 26 12 7F 99 5F 20 2E EA F5 E9 78 60 B9 E5
: C0
: }
: }
: }
: }