如何在PyCrypto中使用加密的RSA私钥?

7 投票
2 回答
29100 浏览
提问于 2025-04-18 07:29

我正在使用OpenSSL生成一个密钥,并且是通过标准输入提供密码的:

openssl genpkey -algorithm RSA -out private-key.pem -outform PEM -pass stdin -des3 -pkeyopt rsa_keygen_bits:4096

生成的密钥看起来像这样:

-----BEGIN ENCRYPTED PRIVATE KEY-----
XXX...
-----END ENCRYPTED PRIVATE KEY-----

我的Python代码是这样的:

from Crypto.PublicKey import RSA
# ...
f = open('private-key.pem', 'r')
r = RSA.importKey(f.read(),  passphrase='some-pass')
f.close()

但是我遇到了一个异常:

  File "/usr/lib/python2.7/dist-packages/Crypto/PublicKey/RSA.py", line 665, in importKey
    return self._importKeyDER(der)
  File "/usr/lib/python2.7/dist-packages/Crypto/PublicKey/RSA.py", line 588, in _importKeyDER
    raise ValueError("RSA key format is not supported")
ValueError: RSA key format is not supported

这是怎么回事呢?

有没有办法生成一个加密的RSA密钥,存储在文件中,然后再用PyCrypto来使用它?用OpenSSL可以做到吗?支持哪些格式呢?

导入公钥是没问题的,但它并没有加密。

2 个回答

2

给那些想解决这个问题但又不想安装已经很久没更新的PyCrypto的朋友们一个快速更新。你可以安全地用pycryptodome来替代它(https://github.com/Legrandin/pycryptodome)。这个库不仅可以直接替代pycrypto,还可以作为一个替代库使用(叫做pycryptodomex)。

5

假设 #1

看了源代码后,我觉得我找到了谜底。对于用密码加密的PEM密钥,导入的方式是先把PEM解密成DER格式,然后再调用importKeyDER函数。如果提供的密码不正确,生成的DER格式也会不正确,这样就会出现你所遇到的异常。为了确认这一点,我做了两个简单的测试:

>>> from Crypto.PublicKey import RSA
>>> f = open('<some-path>/private-key.pem','r')
>>> r=RSA.importKey(f.read(),passphrase='foo')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python2.7/dist-packages/Crypto/PublicKey/RSA.py", line 665, in importKey
    return self._importKeyDER(der)
  File "/usr/local/lib/python2.7/dist-packages/Crypto/PublicKey/RSA.py", line 588, in    _importKeyDER
    raise ValueError("RSA key format is not supported")
ValueError: RSA key format is not supported
>>> f = open('<some-path>/private-key.pem','r')
>>> r=RSA.importKey(f.read(),passphrase='<valid-pass-phrase>')
>>> r
<_RSAobj @0xb7237b2c n(4096),e,d,p,q,u,private>

在从作者那里收到PEM后,我意识到假设 #1在他的情况下并不成立。不过我还是想把它保留在这里,作为导入失败的一个可能原因,让其他用户知道。

假设 #2 - 这是作者的情况。

RSA.py会在PEM文件中查找以下内容,以确定PEM使用了什么样的加密:

 Proc-Type: 4,ENCRYPTED

当使用“openssl genrsa ...”命令生成密钥时,这个字符串会清晰地出现在PEM中,但如果使用“openssl genpkey ...”,则“Proc-Type”就不会出现。

如果找不到“Proc-Type”,RSA.py甚至不会尝试解密PEM:

  # The encrypted PEM format
  if lines[1].startswith(b('Proc-Type:4,ENCRYPTED')):
     DEK = lines[2].split(b(':'))
     ....

所以,我目前的结论是,使用“openssl genpkey”生成的密钥不被PyCrypto v 2.6.1支持。

重要更新

在PyCrypto的最新版本2.7a1中是可以工作的。你可以从这里下载: http://ftp.dlitz.net/pub/dlitz/crypto/pycrypto/pycrypto-2.7a1.tar.gz

>>> f = open('key.pem','r')
>>> r = RSA.importKey(f.read(),  passphrase='123456')
>>> r
<_RSAobj @0xb6f342ec n(2048),e,d,p,q,u,private>

撰写回答