PEM 编码中 ECC 私钥的 Python 导入失败

问题描述

我正在运行 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

运行我的导入它会成功导入密钥:

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',d=9431423964991629169983079041344798030398447908105071875075159616703093895196)

所以我的问题是:我的 EC 私钥有什么“错误”,以至于它在 Java/PHP/NodeJs-Crypto/WebCrypto 中运行但不在 Python 中运行?或者更好:如何在没有任何进一步(外部)转换的情况下在 Python 中导入我现有的 EC 私钥

这是我的导入测试程序的完整源代码

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)

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)