banner

SSH Key Fingerprints

Published 

Photo Credits: Unsplash

Introduction

I recently tried to match my local SSH key pairs with SSH keys I had registered on my Github account. Github displays the fingerprint of each uploaded key (see header image), so naturally, I tried to fingerprint my locally-stored keys for comparison. It was not as straightforward as I thought (though it could have been - see the final section of this article for the easy, "right" way of doing this).

Here's what I learned about the SSH key fingerprinting process:

Generating a Fingerprint from an SSH Pubkey

To generate an SSH key fingerprint, run the following command(s):

KEYFILE=/tmp/tmpkey.pub # replace with your own
grep -oE 'AAAA\S+' $KEYFILE | base64 -d | sha256sum | cut -d ' ' -f 1 | xxd -r -p | base64

Brief Explanation

  1. Get the key "blob"
  2. Decode from base64 and hash the raw bytes
  3. Convert the hex-encoded hash into a base64-encoded hash

Detailed Explanation

grep -oE 'AAAA\S+' $KEYFILE | base64 -d

The 'middle part' of an SSH public key file contains base64-encoded data.

  • The exact layout of the encoded data varies by key type
  • All key types start with a 'key type' string, where the string representation (and all data type representations) should comply with RFC 4251, Section 5
  • Per RFC 4251, strings start with a UINT32 (4-byte integer) that specifies how long the string will be
    • That's why we can reliably grep for 4x 'A' characters - the first three bytes of the encoded data are effectively guaranteed to be null.
  • Once the key type is known, the key is parsed according to its format. For example, the ssh-ed25519 format is defined here; 'ssh-rsa' and some other common types are defined in Section 6.6 of RFC 4253
  • For further reading

sha256sum | cut -d ' ' -f 1

  • Regardless of key type and encoded-data layout, SSH fingerprints are based on the hash of all bits in the 'base64' section
  • sha256sum outputs the hash plus a trailing filename and newline, hence the cut command
    • Sidenote: a (rejected) proposal to add a hash-only output format to sha256sum

xxd -r -p | base64

  • Just like an encryption key, a sha256 hash is a series of bits, not human-readable characters. Hashes tend to be displayed as either hex or base64-encoded strings for human consumption.
  • sha256sum outputs a hex-encoded string; SSH fingerprints are typically displayed as base64-encoded strings

The 'Right' Way

ssh-keygen outputs a key's fingerprint when first generated; It can also output the fingerprint of an existing public key file with ssh-keygen -lf PATH_TO_KEYFILE. (I was unaware of this when first going down the rabbit-hole from which this post was created.)