SSH key fingerprints: what they are and how to check one

A fingerprint is a short hash that identifies a public key. Compare fingerprints to confirm that the key on GitHub is the one on your laptop, or that a server is the real one.

updated

Quick answer. Run ssh-keygen -lf on a public key file. The output is the key size, the SHA256 fingerprint, the comment and the type. Add -E md5 for the older MD5 form.

$ ssh-keygen -lf ~/.ssh/id_ed25519.pub
256 SHA256:I2McFhOvOOgBGIf3aLmk0z7TTKxZoLZ32hK6Bxbk7Tw [email protected] (ED25519)

Check a public key now

Check a public key's fingerprint

What a fingerprint is

Public keys are too long to compare by eye, so OpenSSH hashes them. Since OpenSSH 6.8 the default is SHA-256 in base64:

256 SHA256:Fq4Ye5MxY2nI7cW8c9Bx3ZsH2WgW2yK7r1o5ZQ3hK9U you@laptop (ED25519)

That is the size in bits, the fingerprint, the comment and the type. A fingerprint comes from the public key only, so it is safe to share.

Fingerprints answer two everyday questions:

  • Which of my keys is this? GitHub, GitLab and ssh-add -l list keys by fingerprint, so you can match an entry to a file on your disk and remove the right one.
  • Am I talking to the real server? On first contact ssh shows the server's host key fingerprint. Comparing it with a value you got another way is what stops a man-in-the-middle.

The hash covers the key's binary encoding, not the comment, so renaming a file or editing its comment does not change the fingerprint. Neither does changing the passphrase.

SHA256 vs MD5 fingerprints

Some older tools show the legacy MD5 format, such as MD5:3b:2c:8f:.... Get it with -E md5.

$ ssh-keygen -E md5 -lf ~/.ssh/id_ed25519.pub
256 MD5:b5:23:6d:0b:dc:ac:67:62:85:a1:dd:80:15:4c:52:2c [email protected] (ED25519)
SHA256MD5
Looks likeSHA256:I2McFhOv..., 43 base64 characters16 hex pairs separated by colons
Default in OpenSSHSince 6.8 (2015)Before 6.8
Where you still see itEverywhere currentOld servers, some appliances and older web consoles

Both identify the same key; they are just different hashes of it, so you cannot convert one into the other. Compute the form the other side shows. Older OpenSSH printed MD5 fingerprints without the MD5: prefix.

Checking fingerprints with ssh-keygen

Your own key

ssh-keygen -lf ~/.ssh/id_ed25519.pub

Pointing -f at the private key works too: a matching pair prints the same fingerprint.

The legacy MD5 format

ssh-keygen -E md5 -lf ~/.ssh/id_ed25519.pub

The randomart picture

ssh-keygen -lvf ~/.ssh/id_ed25519.pub

Every key in authorized_keys

ssh-keygen -lf ~/.ssh/authorized_keys

One line per key: the quickest way to see who can log in before you revoke one.

Keys loaded in ssh-agent

ssh-add -l
ssh-add -l -E md5

Every host in known_hosts

ssh-keygen -lf ~/.ssh/known_hosts

A key you received as text

Pipe it in with -f -, for example a colleague's key before you add it to a server:

echo 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA... bob@laptop' | ssh-keygen -lf -

Verifying a server's host key

The first time you connect to a server, ssh shows its host key fingerprint and asks whether to trust it:

The authenticity of host 'example.com (203.0.113.10)' can't be established.
ED25519 key fingerprint is SHA256:Fq4Ye5MxY2nI7cW8c9Bx3ZsH2WgW2yK7r1o5ZQ3hK9U.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])?

Typing yes without checking is how man-in-the-middle attacks succeed. Compare it with the value from the server's console or your provider's panel:

ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub

Run it on the server through a channel you already trust: the provider's web console, a KVM, or an existing session. To list every host key type at once:

for f in /etc/ssh/ssh_host_*_key.pub; do ssh-keygen -lf "$f"; done

Cloud servers built with cloud-init also print their host key fingerprints to the boot console log, which most providers let you read in the web panel before you connect for the first time.

You can paste the expected fingerprint at the prompt and ssh compares them. GitHub's Ed25519 host key is SHA256:+DiY3wvvV6TuJJhbpZisF/zLDA0zPMSvHdkr4UvCOqU; the others are listed in SSH key for GitHub.

ssh-keyscan reads a host key without logging in, but is only as trustworthy as the network:

ssh-keyscan -t ed25519 example.com | ssh-keygen -lf -

For fleets where checking by hand is impractical, StrictHostKeyChecking accept-new in ~/.ssh/config accepts keys of new hosts automatically but still refuses changed keys. It trusts the first connection blindly, so use it only on networks you control. SSH host certificates, signed with ssh-keygen -s -h, remove the question entirely.

known_hosts: where accepted keys live

When you answer yes, ssh appends the host's key to ~/.ssh/known_hosts and prints Warning: Permanently added 'example.com' (ED25519) to the list of known hosts. Each line holds host names or addresses, the key type and the key:

example.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICjC3B8SRdvp0H36PKIVoOSLOR8PA2GXw+6tRPH+FQ0z
[example.com]:2222 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHk...
|1|R0JGhBG4GK12kjyx8DLsGdYJMyo=|IZiy4Emfl0LePJey1mkH+kmU5PE= ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIM2...

The third line is hashed: the host name is stored as a salted hash, so the file does not reveal where you connect. Debian and Ubuntu hash new entries by default (HashKnownHosts yes). You cannot read those names, but ssh-keygen can still find them:

$ ssh-keygen -F example.com
# Host example.com found: line 3
|1|R0JGhBG4GK12kjyx8DLsGdYJMyo=|IZiy4Emfl0LePJey1mkH+kmU5PE= ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIM2...

A server reachable on a non-standard port is stored as [host]:port, so look it up and remove it the same way, in quotes: ssh-keygen -R "[example.com]:2222".

"REMOTE HOST IDENTIFICATION HAS CHANGED"

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the ED25519 key sent by the remote host is
SHA256:hJ3Q0d9fGv0mXbJqfKpXb1wV7m9cS2rYtLz8Nq4uE6A.
Please contact your system administrator.
Add correct host key in /home/you/.ssh/known_hosts to get rid of this message.
Offending ED25519 key in /home/you/.ssh/known_hosts:12
Host key for example.com has changed and you have requested strict checking.
Host key verification failed.

The server's key differs from the one in ~/.ssh/known_hosts. That is expected after a reinstall, and it is also what interception looks like. Verify the new fingerprint, then remove the old entry:

ssh-keygen -R example.com

ssh-keygen -F example.com shows what you have stored for a host, even when known_hosts is hashed. The known_hosts:12 in the message is the line number, so deleting that line in an editor works as well. Reconnect and the usual first-connection prompt appears.

A cloud server that got a new public IP address, or a new server reusing an old address, triggers the same warning, or a milder one that the key for the host differs from the key for the IP address. Remove the stale entries for both the name and the address.

Randomart and VisualHostKey

The randomart is a drawing of the fingerprint, printed by ssh-keygen when it creates a key and on request with -lv:

+--[ED25519 256]--+
|...   +.         |
|o+.    +         |
|=..+  o .        |
| +*o.+ o         |
| **+o * S        |
|+=oE+o o .       |
|oo=Bo            |
| o*++.           |
| .+++.           |
+----[SHA256]-----+

It makes a changed key easier to spot at a glance than a string of base64. VisualHostKey yes in ~/.ssh/config shows a server's picture on every connection. It is a recognition aid, not a substitute for comparing the fingerprint on first contact.

Publishing fingerprints in DNS (SSHFP)

A server's administrator can publish host key fingerprints as SSHFP records in DNS. ssh-keygen prints them:

$ ssh-keygen -r example.com -f /etc/ssh/ssh_host_ed25519_key.pub
example.com IN SSHFP 4 1 76e2aa78a96ac1a632da16c0c13940615b42225f
example.com IN SSHFP 4 2 23631c1613af38e8011887f768b9a4d33ed34cac59a0b677da12ba0716e4ed3c

With VerifyHostKeyDNS yes, the client checks the key against those records. It is only trustworthy when the zone is signed with DNSSEC and your resolver validates it; otherwise ssh still asks.

Matching keys on GitHub, GitLab and cloud panels

GitHub (Settings, SSH and GPG keys) and GitLab (Preferences, SSH Keys) list each key's SHA256 fingerprint. Run ssh-keygen -lf on your .pub files, or use the checker above, and delete keys you no longer recognise.

Cloud consoles are less uniform. AWS, for example, shows SHA256 for Ed25519 key pairs but its own MD5 or SHA-1 digests for RSA key pairs, computed differently from ssh-keygen -l. If a provider's value does not match either form, check its documentation for how it computes fingerprints before suspecting the key.

Troubleshooting

"is not a public key file"

ssh-keygen could not parse the input. Common causes: the key was wrapped onto several lines when copied, the file is in another format such as PuTTY's .ppk or RFC 4716 (convert it with ssh-keygen -i -f), or it is a certificate or private key in a format ssh-keygen does not read.

"Host key verification failed" with no other message

You answered no at the prompt, or ssh ran without a terminal (from a script, cron or CI) and could not ask. Connect once interactively to accept the key after checking it, or add the verified line to known_hosts before the job runs.

The fingerprint in GitHub does not match my file

You are probably looking at a different key. List every key you have with for f in ~/.ssh/*.pub; do ssh-keygen -lf "$f"; done and compare again. Keys you cannot match to a file should be deleted from the account.

FAQ

Is it safe to share an SSH key fingerprint?

Yes. A fingerprint is a hash of the public key, which is public anyway. It cannot be turned back into either key. Sharing it is exactly how you let someone check that they have the right key.

Why is my fingerprint different from the one shown on a website?

Usually the hash differs, not the key: one side shows SHA256 and the other MD5. Run ssh-keygen -E md5 -lf key.pub to get the MD5 form. If both use the same hash and still differ, it is a different key.

Does the fingerprint change if I change the passphrase or comment?

No. The fingerprint is computed from the public key alone. A new passphrase, a new comment or a new file name leave it unchanged; only a new key changes it.

Can I get the fingerprint from the private key?

Yes. ssh-keygen -lf ~/.ssh/id_ed25519 works on the private key file too, without the passphrase, because OpenSSH stores the public key unencrypted inside it. A matching pair prints the same fingerprint.

What does the number at the start of ssh-keygen -l output mean?

It is the key size in bits: 256 for Ed25519 and ECDSA P-256, 2048 to 4096 for RSA. The key type follows in brackets at the end of the line.

Should I type yes when connecting to a server the first time?

Only after checking the fingerprint against one you got another way, such as the provider's console, the administrator, or the published fingerprints of GitHub and similar services. Once accepted, ssh stores the key and checks it on every later connection.