That's a rather bad expression for shell scripts, as it depends on a shell supporting it, which POSIX shell doesn't.
– Andreas WieseOct 28 '16 at 9:22

1

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 -
– Cedric KnightNov 16 '16 at 16:17

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 hostname 2>/dev/null)

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.

Fetch public host keys

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 verifying
ssh_known_hosts files.

Key type

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

Get fingerprint hashes of Base64 keys

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.

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.

Hashing algorithms

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)

Using a pipeline

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.

Nice and thorough answer, this is certainly better than having a temporary file! May I suggest you provide a TL;DR in the beginning with the process substitution version, to make impatient folks find it faster? :)
– goncaloppMar 9 '16 at 21:07

3

Does not seem to work on Ubuntu 14.04 LTS; I get an error "/dev/fd/63 is not a public key file". The subprocess does work.
– MelleOct 18 '16 at 7:26

@melleb I found the same thing on an 12.04 system that I have access to. I suspect that 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.
– Anthony GeogheganOct 18 '16 at 9:51

3

@melleb After spending my luch-time downloading various source code releases and inserting debugging 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.
– Anthony GeogheganOct 18 '16 at 13:35

This works, but if using it to verify a fingerprint, users should be aware that there's a race condition: the fingerprint you are checking with this command isn't necessarily that of the key you fetch, unless you dump the key before calling ssh-keygen on it.
– CodeGnomeAug 31 '18 at 17:11

Do these examples assume that SSH is always running on port 22 ? What if ssh listens on a non-standard port ?
– Martin VegterDec 1 '14 at 21:33

3

@MartinVegter (paraphrasing Guarin42, who couldn't comment:) nmap has the -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)
– goncaloppJan 29 '15 at 11:52

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.