5

In the past when using PyCrypto I was able to do the following to generate a fingerprint of a RSA public key:

rsa_cipher = PKCS1_v1_5.new(RSA.importKey(pub_rsa_key))
hashlib.sha1(rsa_cipher._key.exportKey("DER")).hexdigest()

How can I achieve the same without PyCrypto?


EDIT

What I provide in pub_rsa_key is a content of a .perm file, i.e.:

-----BEGIN PUBLIC KEY-----
MII...AB
-----END PUBLIC KEY-----

PyCrypto is deemed unsafe and is not maintained anymore so I switched to Python's Cryptography but it seems that it does not have an adequate feature.

  • Is there similar functionality that I missed in the Pythons Cryptography API?
  • Is PyCryptoDome possible is a worthy (stable and safe) replacement for PyCrypto to use to implement this functionality?
  • If none of the above is it possible to export that key in a DER format by a self written function?

Any documentation or search terms to perform the export would be helpful.


EDIT 2
Maarten Bodewes' comments (thank you) took me to a place that seems to be the thing I was looking for. But the results of the DER export differ:

# Python 3.7 using Cryptography
from cryptography.hazmat.primitives import serialization

with open('pub_key.perm', 'rb') as key_file: 
    public_key = serialization.load_pem_public_key(key_file.read(), backend=default_backend())

pub_der = public_key.public_bytes(encoding=serialization.Encoding.DER, format=serialization.PublicFormat.PKCS1)

print(sha1(pub_der).hexdigest())
# gives "d291c142648b7........c2f4676f4213203c4bd"

where

# Python 2.7 using PyCrypto
from Crypto.Cipher import PKCS1_v1_5
from Crypto.PublicKey import RSA

with open('pub_key.perm', 'r') as key_file:
    public_key = RSA.importKey(key_file.read())

pub_der = public_key.exportKey('DER')  # this assumes PKCS1 by default per the __doc__

print(sha1(pub_der).hexdigest())
# gives "bb070664079f5........64c97fcadbad847cce9"

This is an effort to move from Py2 to Py3 - please notice that the two examples use different Python versions. Could encoding be an issue here?

McAbra
  • 2,382
  • 2
  • 21
  • 29
  • Thank you, I hope I provided enough (or at least some) valuable information now. – McAbra Feb 05 '19 at 16:01
  • 1
    OK, cool, it's a good question as it is formatted now. I performed some formatting to bundle the actual questions together and such. Feel free to unroll if you do not agree. Sorry about the first snarky remark; it did feel like we had to dupe an existing free library for no particular reason. – Maarten Bodewes Feb 05 '19 at 16:24
  • I'd say [loading the public key using the Cryptography API](https://cryptography.io/en/latest/hazmat/primitives/asymmetric/rsa/#key-loading) and then serializing it to DER (right below that) in memory so you can hash the key would make most sense. It uses OpenSSL as back end, and PEM is the prime format of OpenSSL (so compatablity issues are not likely). – Maarten Bodewes Feb 05 '19 at 16:32
  • Uh, you'd use [`load_pem_public_key`](https://cryptography.io/en/latest/hazmat/primitives/asymmetric/serialization/#cryptography.hazmat.primitives.serialization.load_pem_public_key) instead, of course :) – Maarten Bodewes Feb 05 '19 at 16:39
  • 1
    Your public key has a SubjectPublicKeyInfo format or X509 format, not a PKCS#1 format; actually, the PKCS#1 form is *inside* the SubjectPublicKeyInfo. PEM uses "BEGIN **RSA** PUBLIC KEY" between the dashes for PKCS#1 format (as PKSC#1 doesn't specify the algorithm, while SubjectPublicKeyInfo does). – Maarten Bodewes Feb 05 '19 at 22:08
  • That did it, `public_key.public_bytes(encoding=serialization.Encoding.DER, format=serialization.PublicFormat.SubjectPublicKeyInfo)` when applying sha1 on it I got the exact result I needed. Thank you, would you like to post an answer for future reference? – McAbra Feb 05 '19 at 22:17
  • Ah, you've got the code and the info is in the comments, feel free to post one yourself. It's getting rather late here. – Maarten Bodewes Feb 05 '19 at 22:31

1 Answers1

3

To answer my question (which was resolved with the help provided in the comments, thanks again).

To achieve what I was able to do with PyCrypto:

# Python 2.7 using PyCrypto
from Crypto.Cipher import PKCS1_v1_5
from Crypto.PublicKey import RSA

with open('pub_key.perm', 'r') as key_file:
    public_key = RSA.importKey(key_file.read())

pub_der = public_key.exportKey('DER')  # this assumes PKCS1 by default per the __doc__

print(sha1(pub_der).hexdigest())
# gives "bb070664079f5........64c97fcadbad847cce9"

with Cryptography, one can do the following:

# Python 3.7 using Cryptography
from cryptography.hazmat.primitives import serialization

with open('pub_key.perm', 'rb') as key_file: 
    public_key = serialization.load_pem_public_key(key_file.read(), backend=default_backend())

pub_der = public_key.public_bytes(
    encoding=serialization.Encoding.DER,
    format=serialization.PublicFormat.SubjectPublicKeyInfo,
)

print(sha1(pub_der).hexdigest())
# gives "bb070664079f5........64c97fcadbad847cce9"
McAbra
  • 2,382
  • 2
  • 21
  • 29