14

I have not found a way to load an RSA private key from a PEM file to use it in python-crypto (signature).

python-openssl can load a PEM file but the PKey object can't be used to retrieved key information (p, q, ...) to use with Crypto.PublicKey.construct().

math
  • 2,811
  • 3
  • 24
  • 29
  • In July 2014, the [PEM Pack](http://www.cryptopp.com/wiki/PEM_Pack) was added to the Crypto++ library. The PEM Pack is a partial implementation of message encryption which allows you to read and write PEM encoded keys and parameters, including encrypted private keys. The additional files include support for RSA, DSA, EC, ECDSA keys and Diffie-Hellman parameters. Its an add-on to the library, and not part of the library proper. You download a ZIP and add five source files to the library. Then you build the library (Crypto++ automatically picks them up). – jww Aug 24 '14 at 22:27
  • Related: [Load PEM encoded private RSA key in Crypto++](http://stackoverflow.com/questions/9815001/load-pem-encoded-private-rsa-key-in-crypto?rq=1) – jww Aug 24 '14 at 22:28

2 Answers2

15

I recommend M2Crypto instead of python-crypto. You will need M2Crypto to parse PEM anyway and its EVP api frees your code from depending on a particular algorithm.

private = """
-----BEGIN RSA PRIVATE KEY-----
MIIBOwIBAAJBANQNY7RD9BarYRsmMazM1hd7a+u3QeMPFZQ7Ic+BmmeWHvvVP4Yj
yu1t6vAut7mKkaDeKbT3yiGVUgAEUaWMXqECAwEAAQJAIHCz8h37N4ScZHThYJgt
oIYHKpZsg/oIyRaKw54GKxZq5f7YivcWoZ8j7IQ65lHVH3gmaqKOvqdAVVt5imKZ
KQIhAPPsr9i3FxU+Mac0pvQKhFVJUzAFfKiG3ulVUdHgAaw/AiEA3ozHKzfZWKxH
gs8v8ZQ/FnfI7DwYYhJC0YsXb6NSvR8CIHymwLo73mTxsogjBQqDcVrwLL3GoAyz
V6jf+/8HvXMbAiEAj1b3FVQEboOQD6WoyJ1mQO9n/xf50HjYhqRitOnp6ZsCIQDS
AvkvYKc6LG8IANmVv93g1dyKZvU/OQkAZepqHZB2MQ==
-----END RSA PRIVATE KEY-----
"""    
message = "python-crypto sucks"

# Grab RSA parameters e, n
from M2Crypto import RSA, BIO
bio = BIO.MemoryBuffer(private)
rsa = RSA.load_key_bio(bio)
n, e = rsa.n, rsa.e

# In Python-crypto:
import Crypto.PublicKey.RSA
pycrypto_key = Crypto.PublicKey.RSA.construct((n, e))

# Use EVP api to sign message
from M2Crypto import EVP
key = EVP.load_key_string(private)
# if you need a different digest than the default 'sha1':
key.reset_context(md='sha256')
key.sign_init()
key.sign_update(message)
signature = key.sign_final()

# Use EVP api to verify signature
public = """
-----BEGIN PUBLIC KEY-----
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANQNY7RD9BarYRsmMazM1hd7a+u3QeMP
FZQ7Ic+BmmeWHvvVP4Yjyu1t6vAut7mKkaDeKbT3yiGVUgAEUaWMXqECAwEAAQ==
-----END PUBLIC KEY-----
""" 
from M2Crypto import BIO, RSA, EVP
bio = BIO.MemoryBuffer(public)
rsa = RSA.load_pub_key_bio(bio)
pubkey = EVP.PKey()
pubkey.assign_rsa(rsa)
pubkey.reset_context(md="sha256")
pubkey.verify_init()
pubkey.verify_update(message)
assert pubkey.verify_final(signature) == 1

See http://svn.osafoundation.org/m2crypto/trunk/tests/test_rsa.py, but I prefer using the algorithm-independent EVP API http://svn.osafoundation.org/m2crypto/trunk/tests/test_evp.py.

How do you verify an RSA SHA1 signature in Python? addresses a similar issue.

Community
  • 1
  • 1
joeforker
  • 40,459
  • 37
  • 151
  • 246
  • This doesn't work for me. I get 'assert isinstance(n, long)' on the 'pycrypto_key = Crypto.PublicKey.RSA.construct((n, e))' line. n and e are strings - not long. Any ideas? – bbrame Oct 29 '14 at 19:31
7

is this (close to) what you tried doing?

public_key_filename = 'public_key.pem'
rsa = M2Crypto.RSA.load_pub_key(pk)

That should work. The issue might be with openssl too, does it work when you just use openssl (not in Python)?

Link to Me Too Crypto

Kit
  • 30,365
  • 39
  • 105
  • 149
Jason Coon
  • 17,601
  • 10
  • 42
  • 50
  • This can't possibly work since load_pub_key() expects a file resource. Load the data into a BIO using M2Crypto.BIO.MemoryBuffer(public_key_pem), and load a public key using M2Crypto.RSA.load_pub_key_bio(bio). – Dustin Oprea Aug 11 '14 at 15:27