22

I'm trying to understand the steps to take an OpenSSH public key like so:

ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAqmEmDTNBC6O8HGCdu0MZ9zLCivDsYSttrrmlq87/YsEBpvwUTiF3UEQuFLaq5Gm+dtgxJewg/UwsZrDFxzpQhCHB6VmqrbKN2hEIkk/HJvCnAmR1ehXv8n2BWw3Jlw7Z+VgWwXAH50f2HWYqTaE4qP4Dxc4RlElxgNmlDPGXw/dYBvChYBG/RvIiTz1L+pYzPD4JR54IMmTOwjcGIJl7nk1VjKvl3D8Wgp6qejv4MfZ7Htdc99SUKcKWAeHYsjPXosSk3GlwKiS/sZi51Yca394GE7T4hZu6HTaXeZoD8+IZ7AijYn89H7EPjuu0iCAa/cjVzBsFHGszQYG+U5KfIw==

And then to convert it into an standard fingerprint like so:

2048 49:d3:cb:f6:00:d2:93:43:a6:27:07:ca:12:fd:5d:98 id_rsa.pub (RSA)

I have attempted to dive into the OpenSSH source to understand this, but it is over my head. My first guess was to do a simple MD5 on the key text, but the result does not match the above output.

tshepang
  • 12,111
  • 21
  • 91
  • 136
Michael Gorsuch
  • 837
  • 1
  • 6
  • 14
  • The finger print isn't a direct hash of the key. You can delve into the openssh source, for ssh-keygen in particular, which has the fingerprint extraction code. Some minor details here: http://www.lysium.de/blog/index.php?/archives/186-How-to-get-ssh-server-fingerprint-information.html – Marc B Jul 13 '11 at 17:14

2 Answers2

48

It is the MD5 sum of the base64-encoded key:

import base64
import hashlib

def lineToFingerprint(line):
    key = base64.b64decode(line.strip().split()[1].encode('ascii'))
    fp_plain = hashlib.md5(key).hexdigest()
    return ':'.join(a+b for a,b in zip(fp_plain[::2], fp_plain[1::2]))
tshepang
  • 12,111
  • 21
  • 91
  • 136
phihag
  • 278,196
  • 72
  • 453
  • 469
  • 1
    Thanks, this was useful. I replaced `line.partition('ssh-rsa ')[2]` with `line.split()[2]` to handle optional OpenSSH annotations like: `ssh-rsa .....key... JohnDoe@his_laptop` that must be removed. – Adrián Oct 04 '13 at 18:09
  • @Adrián You're totally right, fixed. I assume you mean `split()[1]`. – phihag Oct 04 '13 at 21:38
  • The function in this solution is equivalent to running `openssl x509 -noout -fingerprint -md5 -inform pem -in key.crt` on a crt or pem file. – squarespiral Mar 22 '20 at 11:42
5

https://github.com/ojarva/sshpubkeys

pip install sshpubkeys

Usage:

import sshpubkeys
key = sshpubkeys.SSHKey("ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAqmEmDTNBC6O8H" +
    "GCdu0MZ9zLCivDsYSttrrmlq87/YsEBpvwUTiF3UEQuFLaq5Gm+dtgxJewg/UwsZrDFxz" +
    "pQhCHB6VmqrbKN2hEIkk/HJvCnAmR1ehXv8n2BWw3Jlw7Z+VgWwXAH50f2HWYqTaE4qP4" +
    "Dxc4RlElxgNmlDPGXw/dYBvChYBG/RvIiTz1L+pYzPD4JR54IMmTOwjcGIJl7nk1VjKvl" +
    "3D8Wgp6qejv4MfZ7Htdc99SUKcKWAeHYsjPXosSk3GlwKiS/sZi51Yca394GE7T4hZu6H" +
    "TaXeZoD8+IZ7AijYn89H7EPjuu0iCAa/cjVzBsFHGszQYG+U5KfIw== user@host")
print(key.bits)   # 2048
print(key.hash()) # '49:d3:cb:f6:00:d2:93:43:a6:27:07:ca:12:fd:5d:98'
Mihai Ftr.
  • 51
  • 1
  • 2
  • 7
    What's interesting is that `sshpubkeys` actually refers to the other answer on this question for its implementation: https://github.com/ojarva/python-sshpubkeys/blob/master/sshpubkeys/keys.py#L126 – andreyrd May 27 '17 at 00:33
  • warnings.warn("hash() is deprecated. Use hash_md5(), hash_sha256() or hash_sha512() instead.") – CS QGB Jan 03 '23 at 11:36