相关文章推荐
爱热闹的竹笋  ·  HTTP 状态码 | 菜鸟教程·  2 年前    · 
怕老婆的泡面  ·  DB2.Database - ...·  2 年前    · 
焦虑的骆驼  ·  QLlistwidget 自定义item ...·  2 年前    · 
Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

I am generating a key with OpenSSL, providing the password from stdin:

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

The key then looks like:

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

My Python code looks like:

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

but I am getting an exception:

  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

What's wrong?

Is it possible to generate an encrypted RSA key, store it in a file and later use it with PyCrypto? Is it possible to do it with OpenSSL? What formats are supported?

Importing the public key works fine, however it is not encrypted.

interesting, judging from the stack trace it's trying to import it in binary DER format, not in PEM.Are you sure that you provide the correct file? – Oleg Gryb May 24, 2014 at 19:42

Hypothesis #1

After looking to the source code, I think, I solved the mystery. The way how import works for PEM keys encrypted with a password is that the PEM gets decrypted to DER and after that importKeyDER function is called. If provided password is not correct, the format of generated DER representation will not be correct too and you would get an exception that you've provided. To confirm that, I ran two quick tests below:

>>> 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>')
<_RSAobj @0xb7237b2c n(4096),e,d,p,q,u,private>

After receiving the PEM from the author, I've realized that Hypothesis #1 is not valid for his case. I still want to keep it here as one possible reason of import failure, so other users are aware.

Hypothesis #2 - this is the author's case.

RSA.py looks for the following in PEM file to determine what kind of encryption was applied to PEM:

 Proc-Type: 4,ENCRYPTED

When key is generated using "openssl genrsa ..." command, this string is present in PEM in clear, however when "opensl genpkey ..." is used the "Proc-Type" is not present.

RSA.py doesn't even try to decrypt the PEM if the "Proc-Type" is not found:

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

So, my conclusion at this time is that keys generated by "openssl genpkey" are not supported by PyCrypto v 2.6.1.

Important Update

It does work in PyCrypto's latest version 2.7a1. You can download it from here: 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')
<_RSAobj @0xb6f342ec n(2048),e,d,p,q,u,private>
                Can you please try with this key? : pastebin.com/tcKJjdmw The password is '123456'. It works for me with the command: openssl rsa -inform PEM -outform PEM -in private-key.pem -pubout , but not with PyCrypto.
– stf
                May 25, 2014 at 15:32
                Checked RSA.py one more time and found that it looks for "Proc-Type: 4,ENCRYPTED". If it doesn't find it, it's not even going to treat PEM as encrypted. This is what my openssl generated: "-----BEGIN RSA PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: DES-EDE3-CBC,AC78286040A62849". It looks like the newer version of openssl uses a newer format. Try the old way of generating RSA keys: "openssl genrsa -des3 -out privkey.pem 2048"
– Oleg Gryb
                May 25, 2014 at 16:42
                BTW, even older versions of openssl support both formats with and without "Proc-Type", so it's PyCrypto problem.
– Oleg Gryb
                May 25, 2014 at 16:46

A quick update for those who seek to solve this problem without installing an experimental release of long-abandoned PyCrypto. The library can be safely replaced by pycryptodome (https://github.com/Legrandin/pycryptodome) - it can provide both a drop-in replacement for pycrypto, and it can be used as an alternative library as well (pycryptodomex).

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.