I'm working with a service that uses raw RSA with a private key to sign a payload. The data is effectively produced using:
openssl rsautl -inkey private_key.pem -raw -sign
(Also, the result of encrypting with the private key)
Unfortunately, in Pycrypto the corresponding .verify()
method only takes an argument to verify the data against to return true or false.
In openssl, this could be achieved with one of the following:
# Private key based
openssl rsautl -inkey private_key.pem -raw -verify
# Public key based
openssl rsautl -inkey public_key.pem -pubin -raw -verify
How can I achieve the same functionality in Pycrypto?
(I understand the risks of raw RSA. A custom padding mechanism has been implemented to mitigate some of those risks. Unfortunately, it's not possible to change the current implementation)
Delving into the .verify()
method, one can find how Pycrypto builds the verification signature before comparing it to the given required signature.
It essentially uses Python's pow()
method with the key's public (e) and the key's modulus (n). You will first need to pack the secret message into a (long) integer and then convert the result back to bytes. Fortunately, Pycrypto provides everything you need.
from Crypto.PublicKey import RSA
from Crypto.Util import number
key = RSA.importKey(private_key_str, key_password_str)
# The message must be packed as a long first.
secret_message_long = number.bytes_to_long(secret_message_bytes)
# The magic!
verify_long = pow(encrypted_session_key_long, key.e, key.n)
# and back to bytes
verify_bytes = number.long_to_bytes(result_long)
# Convert message back to a str (Unicode str in Py2).
# Replace 'utf-8' with the correct encoding for *your* message!!!!!
verify_str = verify_bytes.decode('utf-8')