I have a ssh-key fingerprint
:
16:27:ac:a5:76:28:2d:36:63:1b:56:4d:eb:df:a6:48
I would like to see the randomart image of this fingerprint. Is there a command that take this fingerprint as input and that output the randomart image?
PS: I'm not asking for the -o VisualHostKey
option coming with the SSH command.
SSH is everywhere in the development or operations world now. For development it's what allows you to push to GitHub. For operations it's what allows you to reasonably securely log into Linux servers.
Use ssh-keygen The -l option lists the fingerprint, and the -f /etc/ssh/ssh_host_rsa_key. pub option gives the location of the public key file of the host. That location is the default for Linux® servers, but you might need to find it in a different location.
Key fingerprints are special checksums generated based on the public SSH key. Run against the same key, ssh-keygen command will always generate the same fingerprint. Because of this property, you can use SSH key fingerprints for three things: Identify SSH key – fingerprint will stay the same even if you rename the file.
No. What you have provided is only the MD5 fingerprint of the key. SSH randomart displays the encryption algorithms and the hashing algorithm, and the visual art created from the fingerprint. OpenSSH does not seem to come with a tool to generate the ASCII visual art from the fingerprint itself, but that fingerprint is generated from a public key that you probably do have access to. If that is the case, you can put that public key in a file and run ssh-keygen -l
on it.
For specific key(s):
ssh-keygen -lvf ~/.ssh/<id_whatever_name>
e.g., For all entries in known_hosts
(Probably not practical but useful for demonstration)
ssh-keygen -lvf ~/.ssh/known_hosts
For the default key:
ssh-keygen -lv
ssh-keygen -l [-v] [-E <fingerprint_hash>] [-f <input_keyfile>]
-l
-v
prints both fingerprint and visual ASCII art of the key-E <hash_algorithm>
sha256
(default)md5
(Older systems only use md5)-f <key file>
authorized_keys
, known_hosts
<key file>
may contain a private or a public ssh key
-y
option
ssh-keygen -yf ~/.ssh/id_asghar
Note:
You can obtain the ssh key of an active SSH server with
ssh-keyscan <host>
ssh-keyscan [-4|-6] [-f -|<file>] [-H] [-p <port>] [-T <timeout>] [-t <key type>] [-v]
-4
-6
-f
<addrlist> <namelist>
pair-f -
-f <file>
file
<host_address>[,<host_address>...] [<host_name>,[<host_name>...]]
1.2.3.6 someother.fqdn,1.2.3.7,1.2.3.8```
-H
ssh
and sshd
-p <port>
-T <timeout>
timeout
seconds before giving up-t
rsa1
(version 1 only)rsa
dsa
ecdsa
ed25519
-v
e.g., Get the fingerprint and ASCII visual art for the RSA key of github.com
% ssh-keygen -lv -E md5 -f <(ssh-keyscan -t rsa github.com)
# github.com:22 SSH-2.0-babeld-7bdc42c4
2048 MD5:16:27:ac:a5:76:28:2d:36:63:1b:56:4d:eb:df:a6:48 github.com (RSA)
+---[RSA 2048]----+
| . |
| + . |
| . B . |
| o * + |
| X * S |
| + O o . . |
| . E . o |
| . . o |
| . . |
+------[MD5]------+
However, if you insist on getting the randomart solely from the fingerprint, you probably have to generate it yourself. As I understand, OpenSSH generates the ASCII visual art from the fingerprint using the Drunken Bishop algorithm. Implementing this algorithm seems to be trivial, and in the case of your host with the MD5 fingerprint of 16:27:ac:a5:76:28:2d:36:63:1b:56:4d:eb:df:a6:48
, the ASCII visual art is:
+---[ n/a ]----+
| . |
| + . |
| . B . |
| o * + |
| X * S |
| + O o . . |
| . E . o |
| . . o |
| . . |
+------[MD5]------+
Here is the script:
#!/usr/bin/env python
# NOTE: Requires Python 3+
# usage: drunken_bishop.py [-h] [--mode {md5,sha256}] fingerprint
#
# Generate randomart from fingerprint
#
# positional arguments:
# fingerprint
#
# optional arguments:
# -h, --help show this help message and exit
# --mode {md5,sha256}, -m {md5,sha256}
import argparse
import base64
try:
import numpy as np
except ImportError as ex:
import sys
print(
str(ex) + '. Make sure that numpy is installed and available.\n',
file=sys.stderr)
sys.exit(1)
def get_steps(bits):
bits_grouped = np.array(bits, dtype=np.int8).reshape((-1, 4, 2))
bits_grouped_reordered = np.flip(bits_grouped, axis=1)
return bits_grouped_reordered.reshape((-1, 2))
def drunken_bishop(steps):
field = np.zeros((9, 17), dtype=np.int8)
start_position = (4, 8)
def walk(start_position):
def get_step_direction(b):
direction_map = {
(0, 0): (-1, -1),
(0, 1): (-1, 1),
(1, 0): (1, -1),
(1, 1): (1, 1)
}
return direction_map[tuple(b)]
def adjust_for_walls(pos, field_dims):
return np.maximum(np.minimum(pos, field_dims), (0, 0))
pos = np.array(start_position)
for step in steps:
field[tuple(pos)] += 1
pos += get_step_direction(step)
pos = adjust_for_walls(pos, field.shape)
return tuple(pos)
end_position = walk(start_position)
field[start_position] = 15
field[end_position] = 16
return field
def print_randomart(atrium, hash_mode):
# Symbols for the number of times a position is visited by the bishop
values = {
0: ' ', # Initial value
1: '.', 2: 'o', 3: '+', 4: '=', 5: '*', 6: 'B', 7: 'O', 8: 'X',
9: '@', 10: '%', 11: '&', 12: '#', 13: '/', 14: '^',
15: 'S', # Start position
16: 'E' # End position
}
print('+---[ n/a ]----+')
for row in atrium:
symbolic_row = [values[visit_count] for visit_count in row]
print('|{}|'.format(''.join(symbolic_row)))
if hash_mode == 'md5':
print('+------[MD5]------+')
elif hash_mode == 'sha256':
print('+----[SHA256]-----+')
else:
raise RuntimeError('Unsupported hashing mode: {}'.format(hash_mode))
def get_bits(fingerprint, hash_mode):
def get_md5_bits(fingerprint):
return np.array([list('{:08b}'.format(int(i, 16)))
for i in fingerprint.split(':')])
def get_sha256_bits(fingerprint):
missing_padding = 4 - (len(fingerprint) % 4)
fingerprint += '=' * missing_padding
return np.array([list('{:08b}'.format(i))
for i in base64.b64decode(fingerprint)])
if hash_mode == 'md5':
return get_md5_bits(fingerprint)
elif hash_mode == 'sha256':
return get_sha256_bits(fingerprint)
raise RuntimeError('Unsupported hashing mode: {}'.format(hash_mode))
def get_argparser():
parser = argparse.ArgumentParser(
description='Generate randomart from fingerprint')
parser.add_argument(
'--mode', '-m', choices=['md5', 'sha256'], default='sha256')
parser.add_argument('fingerprint', type=str)
return parser
def main():
parser = get_argparser()
args = parser.parse_args()
bits = get_bits(args.fingerprint, args.mode)
steps = get_steps(bits)
atrium = drunken_bishop(steps)
print_randomart(atrium, args.mode)
if __name__ == '__main__':
main()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With