2015-09-27 100 views
4

我試圖加載使用cryptography模塊的公共密鑰加載RSA公共密鑰,這是關鍵的樣子:如何使用Python的加密模塊

>>> 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)和它的工作,這使得這個還更令人費解:爲什麼它適用於那個鑰匙,而不是我的?

回答

3

長話短說,顯然你的PEM擁有PKCS#1格式(-----BEGIN RSA PUBLIC KEY----------END RSA PUBLIC KEY-----)的頁眉和頁腳,但包含PKCS#8格式的DER序列,因爲load_pem_public_key不能正確反序列化PEM,因爲它需要PKCS#1 DER格式,但接收PKCS#8格式。通過替換頁眉和頁腳以及與PKCS#8格式相對應的頁眉和頁腳來快速修復。

在您的PEM文件替換-----BEGIN RSA PUBLIC KEY----------BEGIN PUBLIC KEY-----,並-----END RSA PUBLIC KEY----------END PUBLIC KEY-----

你的公鑰應該是這樣的:

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

否則cryptography模塊將無法解析它。


編輯

-----BEGIN RSA PUBLIC KEY-----是PKCS#1,-----BEGIN PUBLIC KEY-----是PKCS#8

您可以通過以下步驟檢查您的DER格式:

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 

你會注意到你的public_key_der[0]是另一個DER序列(你可以再次解碼它:public_key_der.decode(public_key_der[0])),並且表示來自PKCS#8 DER格式的AlgorithmIdentifier序列,如果它是PKCS#1 public_key_der[0]應該具有表示模數的INTEGER。

約PKCS#8 VS PKCS#1格式都可以在這裏找到更多的信息:https://tls.mbed.org/kb/cryptography/asn1-key-structures-in-der-and-pem

+0

恩,你確定嗎?因爲那太奇怪了!你能指出任何確認這種行爲的來源嗎? – elias

+0

這不能是原因,我剛剛測試了另一個關鍵(從[這個問題](http://stackoverflow.com/questions/10569189/how-to-read-a-rsa-public-key-in- peg-pkcs1-format) – elias

+1

----- BEGIN RSA PUBLIC KEY -----用於PKCS#1標準,----- BEGIN PUBLIC KEY -----用於PKCS# 8標準,我對您的公鑰進行了解碼,並且它的der序列符合PKCS#8的序列。您可以在這裏找到更多關於DER序列與PKCS#1和PKCS#8不同的信息:https://tls.mbed.org/kb/cryptography/asn1-key-structures-in-der-and-pem。順便說一句,我在發佈之前測試了我的答案,並且它工作正常,你應該至少在放棄之前嘗試。 – godvsdeity

6

您試圖像對待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> 
+0

在這個答案中,我們做的事情與[鏈接到的問題]中的第一個答案基本相同(http://stackoverflow.com/questions/10569189/how-to-read-a-rsa-public-key -in-pem-pkcs1-format)... – larsks

+0

不錯的分手,謝謝! :) – elias