如何使用Python的加密模块加载RSA公钥

时间:2015-09-27 02:45:08

标签: python cryptography

我正在尝试使用cryptography模块加载公钥,这就是密钥的样子:

>>> print(pubkey)
-----BEGIN RSA PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+6gvHdCUCjnc4hSMwbdIIspk4
69pVAzjjb8tDJsCH/QpiK9vXe4nDZ7p9kiw2ACw0fkWaPnApKBwXNB9Nd9Sf+XFt
cIzdqKKBcAqZZCu2pA729amNRug9DoZdkstaBG+VfTxXhdzQRSTxxqJQWgdV8ejK
kt4D1M6pAiTkAyD0eQIDAQAB
-----END RSA PUBLIC KEY-----

我正在尝试使用load_pem_public_key()方法加载它:

>>> from cryptography.hazmat.backends import default_backend
>>> from cryptography.hazmat.primitives.serialization import load_pem_public_key
>>> load_pem_public_key(pubkey, default_backend())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/elias/.virtualenvs/ckpypkg/local/lib/python2.7/site-packages/cryptography/hazmat/primitives/serialization.py", line 24, in load_pem_public_key
    return backend.load_pem_public_key(data)
  File "/home/elias/.virtualenvs/ckpypkg/local/lib/python2.7/site-packages/cryptography/hazmat/backends/multibackend.py", line 285, in load_pem_public_key
    return b.load_pem_public_key(data)
  File "/home/elias/.virtualenvs/ckpypkg/local/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/backend.py", line 1376, in load_pem_public_key
    self._handle_key_loading_error()
  File "/home/elias/.virtualenvs/ckpypkg/local/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/backend.py", line 1595, in _handle_key_loading_error
    raise ValueError("Could not unserialize key data.")
ValueError: Could not unserialize key data.

我做错了吗?这把钥匙有问题吗?为什么它不能被反序列化?

OpenSSL版本:

$ openssl version
OpenSSL 1.0.1f 6 Jan 2014

更新:我刚刚使用不同的密钥(来自this other SO question的同一个密码)测试了相同的代码并且它工作正常,这使得这更令人费解:为什么它适用于该密钥而不是我的?

2 个答案:

答案 0 :(得分:7)

您正在尝试将密钥视为PEM编码的RSA密钥,但实际上您拥有的是使用PKCS#1格式的公钥。 -----BEGIN RSA PUBLIC KEY----------END RSA PUBLIC KEY-----之间的数据实际上只是base-64编码的DER数据。可能有一个库函数来实现(我开始查看cryptography文档,我的眼睛开始釉面),但以下将起作用...

我们从您的关键数据开始:

>>> print pubkey
-----BEGIN RSA PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+6gvHdCUCjnc4hSMwbdIIspk4
69pVAzjjb8tDJsCH/QpiK9vXe4nDZ7p9kiw2ACw0fkWaPnApKBwXNB9Nd9Sf+XFt
cIzdqKKBcAqZZCu2pA729amNRug9DoZdkstaBG+VfTxXhdzQRSTxxqJQWgdV8ejK
kt4D1M6pAiTkAyD0eQIDAQAB
-----END RSA PUBLIC KEY-----

我们放弃BEGINEND行:

>>> b64data = '\n'.join(pubkey.splitlines()[1:-1])
>>> print b64data
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+6gvHdCUCjnc4hSMwbdIIspk4
69pVAzjjb8tDJsCH/QpiK9vXe4nDZ7p9kiw2ACw0fkWaPnApKBwXNB9Nd9Sf+XFt
cIzdqKKBcAqZZCu2pA729amNRug9DoZdkstaBG+VfTxXhdzQRSTxxqJQWgdV8ejK
kt4D1M6pAiTkAyD0eQIDAQAB

然后我们base64解码数据:

>>> derdata = base64.b64decode(b64data)

现在我们有DER编码的公钥,所以我们可以将其提供给 load_der_public_key

>>> from cryptography.hazmat.backends import default_backend
>>> from cryptography.hazmat.primitives.serialization import load_der_public_key
>>> key = load_der_public_key(derdata, default_backend())
>>> print key
<cryptography.hazmat.backends.openssl.rsa._RSAPublicKey object at 0x7fe590ea6d10>

答案 1 :(得分:4)

长话短说,显然您的PEM具有PKCS#1格式(-----BEGIN RSA PUBLIC KEY----------END RSA PUBLIC KEY-----)的页眉和页脚,但包含PKCS#8格式的DER序列,因为{{1无法正确地反序列化pem,因为它需要PKCS#1 DER格式,但是接收PKCS#8格式。通过将页眉和页脚替换为与PKCS#8格式相对应的页眉和页脚来快速修复。

在您的pem文件中,将load_pem_public_key替换为-----BEGIN RSA PUBLIC KEY-----,将-----BEGIN PUBLIC KEY-----替换为-----END RSA PUBLIC KEY-----

您的公钥应如下所示:

-----END PUBLIC KEY-----

否则cryptography模块将无法解析它。

修改

-----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+6gvHdCUCjnc4hSMwbdIIspk4 69pVAzjjb8tDJsCH/QpiK9vXe4nDZ7p9kiw2ACw0fkWaPnApKBwXNB9Nd9Sf+XFt cIzdqKKBcAqZZCu2pA729amNRug9DoZdkstaBG+VfTxXhdzQRSTxxqJQWgdV8ejK kt4D1M6pAiTkAyD0eQIDAQAB -----END PUBLIC KEY----- 适用于PKCS#1,-----BEGIN RSA PUBLIC KEY-----适用于PKCS#8

您可以通过执行以下操作来查看您的DER格式:

-----BEGIN PUBLIC KEY-----

您会注意到您的from Crypto.Util.asn1 import DerSequence public_key_der = DerSequence() public_key_der.decode('MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+6gvHdCUCjnc4hSMwbdIIspk469pVAzjjb8tDJsCH/QpiK9vXe4nDZ7p9kiw2ACw0fkWaPnApKBwXNB9Nd9Sf+XFtcIzdqKKBcAqZZCu2pA729amNRug9DoZdkstaBG+VfTxXhdzQRSTxxqJQWgdV8ejKkt4D1M6pAiTkAyD0eQIDAQAB'.decode('base64')); for k,v in enumerate(public_key_der): print k, v 是另一个DER序列(您实际上可以再次解码它:public_key_der[0]),并表示来自PKCS#8 DER格式的AlgorithmIdentifier序列,如果它是PKCS#1 public_key_der.decode(public_key_der[0])应该有一个表示模数的INTEGER。

有关PKCS#8 vs PKCS#1格式的更多信息,请访问:https://tls.mbed.org/kb/cryptography/asn1-key-structures-in-der-and-pem