Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Extract modulus n, private exponent and public exponent in Python cryptography library

I am using Python cryptography library and I need to encrypt something with RSA. It all works great, except one thing.

When I generate keys I need to get modulus n, public exponent and private exponent in hexadecimal form so that I can save them to a file in custom format. It's not for a real world usage, I am doing it for a class assignment.

I searched whole cryptography documentation regarding RSA and cannot find any method like get_modulus_or_exponents() or anything that would even hint on something like that.

The only way I can think of getting those numbers is to serialize keys, then subprocess the openssl command and read it in a form like this:

Modulus (2048 bit):
    00:98:10:23:16:ff:b6:f4:26:a2:42:a6:19:23:0e:
    0f:27:4a:b9:43:3d:a0:4b:b9:1b:1a:57:92:dd:a8:
    bc:5d:b8:6e:e6:7f:0f:2e:89:a5:77:16:d1:cf:44:
    [...]
    f3:0d:5b:90:6b:de:59:58:c9:f4:26:4a:61:b4:52:
    21:1d
Exponent: 65537 (0x10001)

parse it, and extract needed information.

Is there any better way (preferably using cryptography's tools) than this workaround (have I missed something in docs?) or cryptography really doesn't allow any other way to get needed information?

EDIT: This is code I use to generate keys and encrypt, basically same as docs example:

from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.asymmetric import rsa

private_key = rsa.generate_private_key(public_exponent=65537,
                                           key_size=self.key_size * 8,
                                           backend=default_backend()
                                           )
public_key = private_key.public_key()
ciphertext = public_key.encrypt(message, padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA1()),algorithm=hashes.SHA1(),label=None))
like image 314
dosvarog Avatar asked Apr 07 '16 12:04

dosvarog


1 Answers

You can access using public_numbers() and private_numbers()

 public_key.public_numbers()
 private_key.private_numbers()

A good way to see what is available is to use dir:

In [13]: [a for a in dir(public_key) if not a.startswith("_")]
Out[13]: ['encrypt', 'key_size', 'public_bytes', 'public_numbers', 'verifier']

In [14]: [a for a in dir(private_key) if not a.startswith("_")]
Out[14]: 
['decrypt',
 'key_size',
 'private_bytes',
 'private_numbers',
 'public_key',
 'signer']


In [15]: [a for a in dir(private_key.private_numbers()) if not a.startswith("_")]
Out[15]: ['d', 'dmp1', 'dmq1', 'iqmp', 'p', 'private_key', 'public_numbers', 'q']

In [16]: [a for a in dir(public_key.public_numbers()) if not a.startswith("_")]
Out[16]: ['e', 'n', 'public_key']

In [17]: [a for a in dir(private_key.private_numbers().public_numbers) if not a.startswith("_")]
Out[17]: ['e', 'n', 'public_key']

You see you can actually access all the attributes just using the private key.

like image 64
Padraic Cunningham Avatar answered Sep 28 '22 00:09

Padraic Cunningham