【问题标题】:What is special for a private key to be PEM-formatted?PEM 格式的私钥有什么特别之处?
【发布时间】:2015-07-18 01:57:24
【问题描述】:

我正在尝试将Google API with a oAuth service account 与 Python 3.4 一起使用。其中一个步骤是generate a JSON Web Token,为此我使用PyJWT

我的生成代码如下:

# opening the certificate downloaded from the Google API console
# it is password protected by the standard password ('notasecret')
p12 = OpenSSL.crypto.load_pkcs12(open('certfromgoogle.p12', 'rb').read(), 'notasecret')

# extracting the private key from the certificate and dumping it to a PEM
# format (FILETYPE_PEM)
private_key = OpenSSL.crypto.dump_privatekey(OpenSSL.crypto.FILETYPE_PEM, p12.get_privatekey())

# at that stage, private_key contains the private key as
# b'-----BEGIN PRIVATE KEY-----\nMIICdg(...)FIyw==\n-----END PRIVATE KEY-----\n'

# trying to get the JWT
encoded = jwt.encode(claim, private_key, algorithm='RS256', headers={"alg": "RS256", "typ": "JWT"})

jwt.encode 的调用因TypeError: Expecting a PEM-formatted key 而崩溃。完整的追溯:

Traceback (most recent call last):
  File "C:/Users/w_000/PycharmProjects/syncmagazines/testcrypto.py", line 20, in <module>
    encoded = jwt.encode(claim, private_key, algorithm='RS256', headers={"alg": "RS256", "typ": "JWT"})
  File "C:\Python34\lib\site-packages\jwt\api.py", line 118, in encode
    key = alg_obj.prepare_key(key)
  File "C:\Python34\lib\site-packages\jwt\algorithms.py", line 170, in prepare_key
    raise TypeError('Expecting a PEM-formatted key.')
TypeError: Expecting a PEM-formatted key.

但是,私钥似乎已正确提取。

为什么这种格式不正确?

【问题讨论】:

  • “对 jwt.encode 的调用崩溃...” - 私钥是否加密?
  • 您使用的是哪个版本的 Python?你能包括回溯吗?
  • @jww:我更新了我的代码以明确它可以以纯文本形式使用
  • @frasertweedale:Pythin 3.4,我用回溯和其他细节重写了我的问题

标签: python openssl public-key-encryption jwt


【解决方案1】:

检查了 PyJWT 源代码后,很明显库希望 PEM 数据是字符串类型,但您提供的是字节字符串(b'...' 文字在您的问题中很明显)。 违规函数是prepare_key,以及acceptable string types的定义。

你必须将私钥数据解码成原生的str类型:

private_key_bytes = OpenSSL.crypto.dump_privatekey(OpenSSL.crypto.FILETYPE_PEM, p12.get_privatekey())
private_key = private_key_bytes.decode('utf-8')

这似乎只有 Python 3 需要,但上面的代码也应该适用于 Python 2。

【讨论】:

  • 谢谢,这正是问题所在。将.decode('utf-8') 添加到private_key=... 行后,我得到了正确的JWT。
【解决方案2】:

PEM 格式的私钥有什么特别之处?

PEM 是一种表示编码。它有熟悉的-----BEGIN XXX----------END XXX-----

我认为 BEGIN PRIVATE KEY 是 PKCS #8 私钥。也许图书馆想要一个带有 BEGIN RSA PRIVATE KEY 的 PKCS #1 私钥。 BEGIN RSA PRIVATE KEY 也称为 传统 密钥编码(相对于 PKCS #8)。

您应该查看相关文档并以正确的格式提供密钥。

要将传统密钥转换为 PKCS #8 密钥,请参阅 pkcs(1) 的 OpenSSL 手册页。 -topk8 很有趣。另见How to convert PKCS#8-formatted PEM private key to the tranditional format?

要将 PKCS #8 密钥转换为传统密钥,请参阅 rsa(1) 的 OpenSSL 手册页。另见Convert PEM traditional private key to PKCS8 private key?

【讨论】:

  • 错误表明所需的格式是 PEM,这是我转储的(代码注释为清楚起见)
  • @WoJ - 您提供了 PKCS #8 PEM 编码密钥。图书馆是否需要 PKCS #1 PEM 编码的密钥? PKCS #1 PEM 被视为 OpenSSL 中的传统密钥。
猜你喜欢
  • 1970-01-01
  • 2023-02-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多