Reputation: 479
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.
Upvotes: 12
Views: 9330
Reputation: 1065
No. SSH randomart displays the encryption algorithms and the hashing algorithm, and the visual art created from the fingerprint. What you have provided is only the fingerprint of the key, but not the encryption algorithm, nor the hashing algorithm of the fingerprint. As far as I can tell, OpenSSH does not come with a tool to generate the ASCII visual art from the fingerprint itself; however, 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>
Command Synopsis:
ssh-keyscan [-4|-6] [-f -|<file>] [-H] [-p <port>] [-T <timeout>] [-t <key type>] [-v]
-4
- Only connect to IPv4 hosts
-6
- Only connect to IPv6 hosts
-f
- Read hostnames or
<addrlist> <namelist>
pair-f -
- Read from stdin
-f <file>
- Read from
file
- Format
<host_address>[,<host_address>...] [<host_name>,[<host_name>...]]
- One entry per line
- e.g.,
1.2.3.4,1.2.3.5 hostname.some.domain,some.fqdn,1.2.3.4,1.2.3.5 1.2.3.6 someother.fqdn,1.2.3.7,1.2.3.8
-H
- Hash hostnames in the output
- A security option
- Hashes can be used by
ssh
andsshd
-p <port>
- Port the ssh server is listening on
- Default: 22
-T <timeout>
- Wait for
timeout
seconds before giving up- Default: 5
-t
- Type(s) of key to get from the ssh server.
- Multiple types separated with comma
- Default: display all available keys
- Valid options:
rsa1
(version 1 only)rsa
dsa
ecdsa
ed25519
- Man page: https://linux.die.net/man/1/ssh-keyscan
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, excluding the unprovided encryption algorithm, 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
def simulate_bishop_stumbles(steps):
field = [[0] * 17 for _ in range(9)]
start_position = (4, 8)
direction_map = {
"00": (-1, -1),
"01": (-1, 1),
"10": (1, -1),
"11": (1, 1),
}
def clip_at_walls(x, y):
return min(max(x, 0), 8), min(max(y, 0), 16)
pos = start_position
for step in steps:
x, y = pos
field[x][y] += 1
dx, dy = direction_map[step]
pos = clip_at_walls(x + dx, y + dy)
x, y = start_position
field[x][y] = 15
x, y = pos
field[x][y] = 16
return field
def get_steps(fingerprint_bytes):
return [
"{:02b}".format(b >> s & 3) for b in fingerprint_bytes for s in (0, 2, 4, 6)
]
def print_randomart(atrium, hash_mode):
# Symbols for the number of times a position is visited by the bishop
# White space means that the position was never visited
# S and E are the start and end positions
value_symbols = " .o+=*BOX@%&#/^SE"
print("+---[ n/a ]----+")
for row in atrium:
symbolic_row = [value_symbols[visits] for visits in row]
print("|" + "".join(symbolic_row) + "|")
print("+" + ("[" + hash_mode.upper() + "]").center(17, "-") + "+")
def get_bytes(fingerprint, hash_mode):
if hash_mode == "md5":
return [int(i, 16) for i in fingerprint.split(":")]
elif hash_mode == "sha256":
missing_padding = 4 - (len(fingerprint) % 4)
fingerprint += "=" * missing_padding
return base64.b64decode(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 drunken_bishop(fingerprint, hash_mode):
fingerprint_bytes = get_bytes(fingerprint, hash_mode)
steps = get_steps(fingerprint_bytes)
atrium_state = simulate_bishop_stumbles(steps)
print_randomart(atrium_state, hash_mode)
if __name__ == "__main__":
parser = get_argparser()
args = parser.parse_args()
drunken_bishop(args.fingerprint, args.mode)
Upvotes: 19