In yesterday's article, The SSH Public Key format, I gave a simple breakdown of the SSH Public key format.

Today's goal is to re-create the a public key fingerprint (RFC 4716).

I've done this myself with ssh-fingerprint.js and you can see it live in action with this nifty online demo:

SSH Public Key Format

The important part that we need to readdress is that a key looks like this:

id_rsa.pub:

ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCba21UHE+VbDTpmYYFZUOV+OQ8AngOCdjROsPC0KiEfMvEaEM3NQl58u6QL7G7QsErKViiNPm9OTFo6HF5JijfWzK7haHFuRMEsgI4VwIYyhvqlJDfw/wt0AiVvSmoMfEQn1p1aiaO4V/RJSE3Vw/uz2bxiT22uSkSqOyShyfYE6dMHnuoBkzr4jvSifT+INmbv6Nyo4+AAMCZtYeHLrsFeSTjLL9jMPjI4ZkVdlw2n3Xn9NbltF3/8Ao8dQfElqw+LIQWqU0oFHYNIP4ttfl5ObMKHaKSvBMyNruZR0El/ZsrcHLkAHRCLj07KRQJ81l5CUTPtQ02P1Eamz/nT4I3 root@localhost

It's it's got three obvious parts:

  1. type name (i.e. ssh-rsa)
  2. base64-encoded ssh public key (i.e. AAAAB3Nz...nT4I3)
  3. optional comment (i.e. root@localhost)

Fingerprinting

The data we need for fingerprinting is the entire2nd section. It's the base64-encoded public key in the special SSH format.

The fingerprint is simply the sha256 sum of the whole blob, essentialy this:

'SHA256:' + base64-encode( sha256( base64-decode( encoded-ssh-pubklic-key ) ) )

Or, if you prefer to break it down into two steps:

key-blob = base64-decode( pub.split(' ')[1] )

'SHA256:' + base64-encode( sha256( key-blob ) )

The end result looks like this:

SHA256:yCB62vBVsOwqksgYwy/WDbaMF2PhPijAwcrlzmrxfko

Note: The trailing = are stripped off. If that weren't the case you would see SHA256:yCB62vBVsOwqksgYwy/WDbaMF2PhPijAwcrlzmrxfko=, which is incorrect.

Older versions of ssh used MD5 for the fingerprint and would output the value in hex, like this:

ea:b2:71:65:c0:5d:be:15:eb:bb:45:ad:b9:86:d4:ec

We don't use md5 anymore because... reasons.

(you can google to learn about it, but the topic is so old now that I'm not going to bother with it)

Anyway, the switch to base64 kept the printable character width about the same even though the new hash is much longer.

Output formats

When you run ssh-keygen you'll get the abbreviated fingerprint, which still includes the comment of the key.

The key fingerprint is:
SHA256:yCB62vBVsOwqksgYwy/WDbaMF2PhPijAwcrlzmrxfko root@localhost

But if you run ssh-keygen -lf ~/.ssh/id_rsa.pub you'll actually get the key's bit size and type as well:

2048 SHA256:yCB62vBVsOwqksgYwy/WDbaMF2PhPijAwcrlzmrxfko root@localhost (RSA)

If you specifically need to mimic the output formats of ssh-keygen, you'll want to go back and give The SSH Public Key format a read as well. It explains how to break the blob into its various pieces. With EC keys you actually get the size of the key in the type name, so this is really only important for RSA, although you could probably make reasonable-enough guesses.

Demo Time

If you missed it before, here's the link to the online demo:


By AJ ONeal

If you loved this and want more like it, sign up!


Did I make your day?
Buy me a coffeeBuy me a coffee  

(you can learn about the bigger picture I'm working towards on my patreon page )