Is there a way to programmatically obtain a SSH server key fingerprint without authenticating to it?
I'm trying ssh -v user@host false 2>&1 | grep "Server host key"
, but this hangs waiting for a password if key based auth is not setup.
You could do this by combining ssh-keyscan
and ssh-keygen
:
$ file=$(mktemp)
$ ssh-keyscan host > $file 2> /dev/null
$ ssh-keygen -l -f $file
521 de:ad:be:ef:de:ad:be:ef:de:ad:be:ef:de:ad:be:ef host (ECDSA)
4096 8b:ad:f0:0d:8b:ad:f0:0d:8b:ad:f0:0d:8b:ad:f0:0d host (RSA)
$ rm $file
Edit: since OpenSSH 7.2 this oneliner works:
ssh-keyscan host | ssh-keygen -lf -
(credits to @mykhal)
ssh-keyscan host | ssh-keygen -lf -
ssh-keygen -l -f -
does work much as expected in ssh-keygen 7.2 and above. It produces some comment lines to STDERR that can be filtered out, as mentioned in the answer by Anthony Geoghegan or ssh-keyscan host 2>/dev/null | ssh-keygen -l -f -
Commented
Nov 16, 2016 at 16:17
2048 SHA256:gYz11pP/v/SMzUD58jrZ+m1EFC1pvyMxvIrg4PYlvDY
) If you want it in the old format, supply -E md5
and you'll see something like 2048 MD5:0b:f5:49:d2:69:a5:49:2c:d9:45:75:87:4d:a0:7d:33
.
Commented
Aug 21, 2018 at 0:30
I recently had to do this myself so I thought I’d add an answer which shows how this can be done (with versions of OpenSSH 7.2 or newer) in one line using process substitution:
ssh-keygen -lf <(ssh-keyscan localhost 2>/dev/null)
(replace localhost
with the hostname here)
The following text explains how these commands work and highlights some of the differences in behaviour between older and newer versions of the OpenSSH utilities.
The ssh-keyscan
command was developed so that users can obtain public host
keys without needing to authenticate to the SSH server. From its man page:
ssh-keyscan
is a utility for gathering the public ssh host keys of a number of hosts. It was designed to aid in building and verifyingssh_known_hosts
files.
The type of key to be fetched is specified using the -t
option.
rsa1
(obsolete SSH Protocol version 1)rsa
dsa
ecdsa
(recent versions of OpenSSH)ed25519
(recent versions of OpenSSH)In modern OpenSSH releases, the default key types to be fetched are rsa
(since version 5.1), ecdsa
(since version 6.0), and ed25519
(since version
6.7).
With older versions of ssh-keyscan
(before OpenSSH version 5.1), the
default key type was the out-dated rsa1
(SSH Protocol 1) so the key types
would need to be explicitly specified:
ssh-keyscan -t rsa,dsa hostname
ssh-keyscan
prints the host key of the SSH server in Base64-encoded
format. To convert this to a fingerprint hash, the ssh-keygen
utility can be
used with its -l
option to print the fingerprint of the specified public
key.
If using Bash, Zsh (or the Korn shell), process substitution can be used for a handy one-liner:
ssh-keygen -lf <(ssh-keyscan hostname 2>/dev/null)
Note: With versions of OpenSSH before 7.2, the functions used by
ssh-keygen
to read files, did not handle named pipes (FIFOs) very well so
this method wouldn’t work, thus requiring the use of temporary files.
Recent versions of ssh-keygen
print SHA256 fingerprint hashes of the keys.
To get MD5 hashes of the server key fingerprints (the old behaviour), the -E
option can be used to specify the hash algorithm:
ssh-keygen -E md5 -lf <(ssh-keyscan hostname 2>/dev/null)
If using a POSIX shell (such as dash
) which doesn’t feature process substitution,
the other solutions using temporary files will work. However, with newer versions
of OpenSSH (since 7.2), a simple pipeline can be used since ssh-keygen
will
accept -
as a filename for the standard input stream, allowing a one-line
pipeline command.
ssh-keyscan hostname 2>/dev/null | ssh-keygen -E md5 -lf -
ssh-keygen
from older versions of OpenSSH have a problem reading from the FIFO / named pipe. I'll look into this (and update my answer) when I get some free time.
Commented
Oct 18, 2016 at 9:51
printf
statements in the do_fingerprint()
function, I found that with versions of OpenSSH before 7.2, the functions used by ssh-keygen
to read files, did not handle named pipes (FIFOs) very well so the process substitution method would not work.
Commented
Oct 18, 2016 at 13:35
The simple answer when you already have access to the server is:
ssh-keygen -lf /etc/ssh/ssh_host_rsa_key.pub
Now, you might not be using the RSA key: if when connecting, ssh
tells you
ECDSA key fingerprint is SHA256: XXXXX
You need to use /etc/ssh/ssh_host_ecdsa_key.pub
instead. (notice _ecdsa_).
A more universal command that lists all keys can thus be constructed (source):
for f in /etc/ssh/ssh_host_*_key.pub; do ssh-keygen -lf "$f"; done
You could write down the list when setting the server up, for future reference. Another option is to store them in DNS records (Archive):
<hostname> IN SSHFP <key-type> <hash-type> <fingerprint>
(ssh-keygen
can print this line for you if you give it the hostname: ssh-keygen -r hostname -f /etc/ssh/ssh_host_ecdsa_key.pub
)ssh -o VerifyHostKeyDNS=yes user@hostname
or enable it by default by adding VerifyHostKeyDNS=yes
to the client config.From the ssh-keygen (1) manpage:
-l
Show fingerprint of specified public key file. For RSA and DSA keys ssh-keygen tries to find the matching public key file and prints its fingerprint. If combined with -v, a visual ASCII art representation of the key is supplied with the fingerprint.
-f
filename
Specifies the filename of the key file.
-r
hostname
Print the SSHFP fingerprint resource record named hostname for the specified public key file.
-E
fingerprint_hash
Specifies the hash algorithm used when displaying key fingerprints. Valid options are: “md5” and “sha256”. The default is “sha256”.
You may want to use the last option -E md5
when connecting from older ssh clients that default to printing the md5 key. Alternatively, from these clients, let ssh print the SHA256 with ssh -o FingerprintHash=sha256 host
localhost
. On the other hand, if you have multiple different users trying to access the server, the remote commands can be used to check if they agree on the transmitted host key, which could be useful, without ever logging into the server.
sha256sum /etc/ssh/ssh_host_*_key.pub
?
nmap
provides this ability by using the ssh-hostkey
script.
To return the key's hexadecimal fingerprint:
$ nmap [SERVER] --script ssh-hostkey
To return the key's content:
$ nmap [SERVER] --script ssh-hostkey --script-args ssh_hostkey=full
To return the key's visual bubble
$ nmap [SERVER] --script ssh-hostkey --script-args ssh_hostkey='visual bubble'
To return all of the above:
$ nmap [SERVER] --script ssh-hostkey --script-args ssh_hostkey=all
Source: nmap docs
-p
option which can specify a port, e.g. -p 22000
. It's also possible to use the -vv
option to increase the verbosity (amount of information given)
Commented
Jan 29, 2015 at 11:52
ssh_hostkey=sha256
to show the current openssh standard fingerprint ;)
filezilla displays keys hashed with md5 in hexadecimal format.
to find this on your ubuntu linux machine use this command:
ssh-keygen -l -E md5 -f <(ssh-keyscan localhost 2>/dev/null)
note: replace "localhost" with the ip of the machine you wish to check.
localhost
127.0.0.1
or domain.tld
. Check the fingerprint for the URL you are concerned with~!
Commented
Mar 19, 2020 at 22:16
Here is a shell script (mainly Bourne shell but using local
keyword, which is available in most modern /bin/sh
) I've written to do this. Use it like ssh-hostkey hostname
. It will show both the sha256 and md5 format fingerprints for all hostkeys for the given hostname or IP address. You can also manually specify "md5
" or "sha256
" as the second argument to only show that particular format.
It uses a temporary file instead of piping to make it compatible with older OpenSSH packages (as described in other answers). The temporary file uses /dev/shm
(shared memory) if available.
#!/bin/sh
usage () {
printf '%s\n' "Usage: ssh-hostkey HOSTNAME [FPRINTHASH]"
}
ssh_hostkey () {
local host="$1"
local fprinthash="$2"
local tmp=
case "$host" in
-h|--help|'')
usage >&2
return 1
;;
esac
case "$fprinthash" in
md5|sha256|'') true;;
*)
usage >&2
printf '%s\n' "Fingerprint hash may be 'md5' or 'sha256'" >&2
return 2
;;
esac
if test -d /dev/shm
then tmp="$(mktemp -d -p /dev/shm)"
else tmp="$(mktemp -d)"
fi
trap 'trap - INT TERM EXIT; rm -rf "$tmp"' INT TERM EXIT
ssh-keyscan "$host" > "$tmp/f" 2> /dev/null
case "$fprinthash" in
sha256|'') ssh-keygen -l -f "$tmp/f" 2> /dev/null;;
esac
case "$fprinthash" in
md5|'') ssh-keygen -l -E md5 -f "$tmp/f" 2> /dev/null;;
esac
trap - INT TERM EXIT
rm -rf "$tmp" > /dev/null 2>&1
}
ssh_hostkey "$@"
/dev/shm
which I never knew was so convenient to do. Thanks for sharing!
For my own server I use this:
ssh-keygen -l -E md5 -f <(cat /etc/ssh/ssh_host_*_key.pub)
ssh-keygen -l -E sha256 -f <(cat /etc/ssh/ssh_host_*_key.pub)
As I received is not a public key file
with the accepted answer, I used this instead:
timeout 1 ssh -q -o BatchMode=yes -o StrictHostKeyChecking=no -o UserKnownHostsFile=/tmp/sshkey.tmp <hostname>; cat /tmp/sshkey.tmp && rm /tmp/sshkey.tmp
ssh-keygen -lf /path/to/key.pub