128

When connecting to a new/unknown server (with recent OpenSSH), for example:

ssh example.com

You get the fingerprint like below:

The authenticity of host 'example.org (192.0.2.42)' can't be established.
RSA key fingerprint is SHA256:7KMZvJiITZ+HbOyqjNPV5AeC5As2GSZES5baxy1NIe4.
Are you sure you want to continue connecting (yes/no)?

However, fingerprints are usually given for the server in this form:

f6:fc:1c:03:17:5f:67:4f:1f:0b:50:5a:9f:f9:30:e5

How can I check the authenticity (without bugging the server admins to provide an SHA256 fingerprint)?

162

Previously the fingerprint was given as a hexed md5 hash. Starting with OpenSSH 6.8 the fingerprint is now displayed as base64 SHA256 (by default). You can't compare these directly.

They also added a new configuration option FingerprintHash. You can put

FingerprintHash md5

in your ~/.ssh/config to revert to the old (less secure) default or just use this option for single use:

ssh -o FingerprintHash=md5 example.org

which would give the fingerprint as

MD5:f6:fc:1c:03:17:5f:67:4f:1f:0b:50:5a:9f:f9:30:e5

Hopefully server admins provide both types of fingerprints in the near future.

EDIT:

As given in the Arch Linux forums, there is also a third option:

Host example.org
    FingerprintHash md5

EDIT:

You can generate the hash of an arbitrary key as given on the OpenSSH Cookbook:

Retrieve the key:

  • download the key with ssh-keyscan example.org > key.pub
  • or: find the keys on the server in /etc/ssh

Generate the hash:

  • make sure you have only one line/type, so either delete all others in key.pub or run ssh-keyscan -t rsa example.org > key.pub
  • ssh-keygen -l -f key.pub (default hash, depending on OpenSSH version)
  • ssh-keygen -l -f key.pub -E md5 (md5 on current OpenSSH)
  • awk '{print $2}' ssh_host_rsa_key.pub | base64 -d | sha256sum -b | awk '{print $1}' | xxd -r -p | base64 (sha256 on old OpenSSH)
  • (You might need to start the line with awk '{print $3}' for newer versions of ssh-keyscan because the format changed)
| improve this answer | |
  • 4
    do you happen to know how I can get the sha256 fingerprint on the server in case I have access there? ssh-keygen -lf on the server only gives me the md5 print, and for the life of me I can't find how to get the sha256 one either in the man pages or the www so far... – codeling Nov 12 '15 at 21:09
  • 6
    I added a snipped from the OpenSSH Cookbook using sha256sum to the answer. – JonnyJD Nov 13 '15 at 0:33
  • 2
    thank you, you're the only one to give an answer that has actual value. – Florian Heigl Apr 12 '16 at 12:39
  • 3
    sha256sum -b | awk '{print $1}' | xxd -r -p can be replaced by openssl sha256 -binary not requiring vim installed. Resulting commandline would be: awk '{print $2}' ~/.ssh/id_rsa.pub | base64 -d | openssl sha256 -binary | base64 – Alexander Tumin May 28 '19 at 13:29
  • 2
    @JonathanCross Note that base64 utility would produce padded output (i.e. possibly ending with one or two equals signs), while openssh client does not pad base64 in it's log. – Alexander Tumin May 28 '19 at 13:31
28

Just created small bash script which will print table with fingerprints for all key ciphers allowed on server (according to /etc/ssh/sshd_config) in both SSH-256 and MD5 algo. Here is an example output:

 +---------+---------+-----------------------------------------------------+
 | Cipher  | Algo    | Fingerprint                                         |
 +---------+---------+-----------------------------------------------------+
 | RSA     | MD5     | MD5:15:66:80:fd:79:d8:c0:92:e8:39:4a:bc:4e:c4:00:15 |
 | RSA     | SHA-256 | SHA256:G+rKuLGk+8Z1oxUV3cox0baNsH0qGQWm/saWPr4qZMM  |
 +---------+---------+-----------------------------------------------------+
 | ECDSA   | MD5     | MD5:f5:90:5c:03:2e:38:1b:c9:86:bd:86:47:5d:22:79:17 |
 | ECDSA   | SHA-256 | SHA256:GGmuOzsG4EGeRV9KD1WK7tRf3nIc40k/5jRgbTZDpTo  |
 +---------+---------+-----------------------------------------------------+
 | ED25519 | MD5     | MD5:d1:5a:04:56:37:f4:75:19:22:e6:e5:d7:41:fd:79:fa |
 | ED25519 | SHA-256 | SHA256:QVdqYeVzvsP4n5yjuN3D2fu8hDhskOxQCQAV5f9QK7w  |
 +---------+---------+-----------------------------------------------------+

 +---[RSA 2048]----+ +---[RSA 2048]----+ +---[ECDSA 256]---+ +---[ECDSA 256]---+ +--[ED25519 256]--+ +--[ED25519 256]--+
 |.oE.   +.++      | |        .o+=     | |      ... Eoo    | |  .. o.o..      .| |        ooo++o.+*| |   .o++o. +oo    |
 |  .   o +oo.     | |        .o= =    | |     +.=.=.o .   | | . .o *..      ..| |       . oo.+o.o=| |      ...o.+     |
 |   + . . o.=     | |       ... X +   | |    . X.o.*      | |o o  ++o      .. | |        . o. ...+| |       ..oo.o .  |
 |    = +  .+ o    | |      ..  = + o  | |     + = o o     | |.+  .o.o     .o  | |         +    ..o| |        =oo .+   |
 |   o o .S  .     | |     . .S  o o   | |    . = S   .    | |...  oo.S  .E* * | |        S      ..| |       .SO .  .  |
 |    +            | |    . E. =o..    | |     o           | | .. o.  . o *.O o| |              .  | |        o B .o.. |
 |   o             | | .o. *.o. *.     | |                 | |   ...   . o * * | |               . | |         E *..=.o|
 |    .            | | oo=...  +.      | |                 | |    +.      o + o| |                E| |          . +.+B+|
 |                 | |o+=.o....o+o     | |                 | |   .o+         . | |                 | |           o.ooOX|
 +------[MD5]------+ +----[SHA256]-----+ +------[MD5]------+ +----[SHA256]-----+ +------[MD5]------+ +----[SHA256]-----+

Script will run also on servers with SSH version below 6.8 (before -E md5 option was added).

Edit: Updated versions for even more recent versions of SSH which switched default ciphers now with ASCII images support.

#!/bin/bash
# server_ssh_fingerprints
#
# Version 0.2
#
# 2016 Kepi <kepi@igloonet.cz
# MIT License
#
# Print fingerprint matrix for all allowed Host Keys
# with all allowed ciphers and MD5 and SHA-256 algos
#
# Changelog:
#
# 2018-03-11 (0.2):
# - Support for newer versions of OpenSSH
# - Added visual keys for all algos too - only in recent OpenSSH versions

# standard sshd config path
SSHD_CONFIG=/etc/ssh/sshd_config

# helper functions
function tablize {
    awk '{printf(" | %-7s | %-7s | %-51s |\n", $1, $2, $3)}'
}
LINE=" +---------+---------+-----------------------------------------------------+"

# header
echo "$LINE"
echo "Cipher" "Algo" "Fingerprint" | tablize
echo "$LINE"

declare -A ALGOS
declare -a ASCII

# fingerprints
while read -r host_key; do
    cipher=$(echo "$host_key" | sed -r 's/^.*ssh_host_([^_]+)_key\.pub$/\1/'| tr 'a-z' 'A-Z')
    if [[ -f "$host_key" ]]; then
        if ssh-keygen -E md5 -l -f "$host_key" &>/dev/null; then
        IFS=$'\n'

        for algo in md5 sha256; do
            n=0
            for line in $(ssh-keygen -E $algo -lv -f "$host_key"); do
                n=$(( n + 1))
                if [[ $n -eq 1 ]]; then
                    ALGOS[$algo]=$(echo "$line" | awk '{print $2}')
                else
                    ASCII[$n]="${ASCII[$n]} ${line}"
                fi
            done
        done
        else
            ALGOS[md5]=$(ssh-keygen -l -f "$host_key" | awk '{print $2}')
            ALGOS[sha256]=$(awk '{print $2}' "$host_key" | base64 -d | sha256sum -b | awk '{print $1}' | xxd -r -p | base64)
        fi

        echo "$cipher" MD5 "${ALGOS[md5]}" | tablize
        echo "$cipher" SHA-256 "${ALGOS[sha256]}" | tablize
        echo "$LINE"
    fi
 done < <(awk '/^HostKey/ {sub(/^HostKey\s+/,"");print $0".pub"};' $SSHD_CONFIG)

echo
for line in "${ASCII[@]}"; do
    echo "$line"
done

This is just pretty print using information from JonnyJD's answer. Thanks.

| improve this answer | |
  • 2
    I made it more robust and improved functionality slightly; version 0.3 (with changelog) here: github.com/unixnut/scripts/blob/master/ssh_fprint Thanks for writing this, it is awesome! – Alastair Irvine Apr 29 '18 at 14:57
  • @kepi thanks for your script, I used it a couple of times in the past but it's not working anymore so I did my own version and I posted it as a new answer (check it out, probably below...). – loco.loop Mar 14 at 22:02
7

it turns out ssh-keygen (sometime after version 6.6; presumably 6.8) has a -E md5 option which will cause it to print out the fingerprint as an md5 fingerprint. So, if you can independently grab the public key file of the server, you can feed it to ssh-keygen -E md5 -l -f ssh_host_rsa_key.pub and get your familiar fingerprint.

| improve this answer | |
  • 2
    all of that is already in the previous answer well formatted. – Jakuje Jan 8 '16 at 16:25
3

The following one-liner works (at least) on Ubuntu 16.04,18.04 / Centos >= 7

(Tested with servers: openssh 3.9 - openssh 7.4)

ssh-keygen -l -E md5 -f <(ssh-keyscan -t rsa 192.168.2.1) \
| awk '{print $2}' | cut -d":" -f 2-

Output:

# 192.168.2.1:22 SSH-2.0-OpenSSH_5.3
65:2c:c4:03:03:2f:6d:c0:c0:09:79:e7:33:c4:f1:78
| improve this answer | |
1

tried to modify to get also random art into table:

# standard sshd config path
SSHD_CONFIG=/etc/ssh/sshd_config

# helper functions
function tablize {
        awk '{printf("| %-7s | %-51s |\n", $1, $3)}'
}
LINE="+---------+-----------------------------------------------------+"

# header
echo $LINE
echo "Cipher" "Fingerprint" "Fingerprint" | tablize
echo $LINE

# fingerprints
for host_key in $(awk '/^HostKey/ {sub(/^HostKey\s+/,"");print $0".pub"};' $SSHD_CONFIG); do
        cipher=$(echo $host_key | sed -r 's/^.*ssh_host_([^_]+)_key\.pub$/\1/'| tr '[a-z]' '[A-Z]')
        if [[ -f "$host_key" ]]; then
                md5=$(ssh-keygen -l -f $host_key -E md5 | awk '{print $2}')
                sha256=$(ssh-keygen -l -f $host_key | awk '{print $2}')
                art_sha256=$(ssh-keygen -lv -f $host_key | grep -v -w "256 SHA256" | grep -v -w "1024 SHA256" | grep -v -w "2048 SHA256")
                art_md5=$(ssh-keygen -lv -f $host_key -E md5 | grep -v "256 MD5" | grep -v "1024 MD5" | grep -v "2048 MD5")

                echo $cipher MD5 $md5 | tablize
                echo $cipher SHA-256 $sha256 | tablize
                echo $art_sha256 | tablize
                echo $art_md5 | tablize
                echo $LINE
        fi
done

... but I'm not a programmer actually and the script does not work as expected. Would appreciate if anyone can help to fix (also cleanup). There would be nice to have sha256 and md5 random art images side by side to use space more efficiently. I modified also md5 and sha256 commands as the original ones did not work for me (probably too new system) - only sha256 appreared into table with "=" sign in the end which was not part of actual fingerprint and could not remove it.

(sorry I could not comment as I registered recently)

| improve this answer | |
  • If you have a new question, please ask it by clicking the Ask Question button. Include a link to this question if it helps provide context. – Donald Duck Jul 3 '17 at 0:18
  • Well - as you see - it is a not new question but actually admitting that proposed script did not work as expected and a new and still not yet complete version has been proposed. I could modify existing script so it works as expected but I tried to add the random art and this part id not complete. Actually there is one proposal how to compare certain public key and offered key but this variant is not MITM-proof: ssh-keyscan -t ecdsa xxx.xxx.xxx.xxx | ssh-keygen -lv -f - && ssh -X -o VisualHostKey=yes -i ~/.ssh/key user@xxx.xxx.xxx.xxx – zeroconf Jul 3 '17 at 17:36
  • I didn't see your comments but today got same idea, so my answer is now updated with working version for more recent OpenSSH versions, ASCII art included. – Kepi Mar 11 '18 at 19:55
1

I liked Kepi's idea but unfortunately that's not working for me anymore so I reviews the Script and made it work, also I simplified it and removed the ASCII art as I don't need that.

To run my script directly run:

curl -sS https://raw.githubusercontent.com/caballerofelipe/scripts/master/ssh/ssh_fingerprint.sh | bash

Here's my script (might change in the future in GitHub):

#!/bin/bash

# To run this file directly from a computer without downloading run this:
# curl -sS https://raw.githubusercontent.com/caballerofelipe/scripts/master/ssh/ssh_fingerprint.sh | bash

# Used to show SSH fingerprints
# Inspired by this post: http://superuser.com/a/1030779/369045

# standard sshd config path
SSH_DIR=/etc/ssh/

# Helper functions
function tablize {
    printf "| %-7s | %-7s | %-47s |\n" $1 $2 $3
}
LINE="+---------+---------+-------------------------------------------------+"

# Header
echo $LINE
tablize "Cipher" "Algo" "Fingerprint"
echo $LINE

# Fingerprints
for i in $(ls $SSH_DIR/*.pub); do
    md5_result=$(ssh-keygen -l -f $i -E md5)
    sha256_result=$(ssh-keygen -l -f $i -E sha256)
    cipher=$(echo $md5_result | sed 's/.*(//' | sed 's/)[^)]*//')
    md5=$(echo $md5_result | awk '{print $2}' | sed 's/^[^:]*://g')
    sha256=$(echo $sha256_result | awk '{print $2}' | sed 's/^[^:]*://g')
    tablize $cipher MD5 $md5
    tablize $cipher SHA-256 $sha256
    echo $LINE
done
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.