SSH Fingerprint and Hostkey with Paramiko in Python

Following on from SSH and SFTP with Paramiko & Python, I recently had the need to gain a remote SSH server’s fingerprint and hostkey for verification purposes. This is achievable through setting up a socket, and then applying paramiko.Transport over our established socket. First, we include the various bits and pieces we’ll need:

import socket
import paramiko
import hashlib
import base64

Next, we establish a socket connection ‘mySocket’ to “localhost” on port 22 – our dummy SSH server. We then use paramiko.Transport to gain access to paramiko’s core SSH protocol options on the socket.

mySocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
mySocket.connect(("localhost", 22))
myTransport = paramiko.Transport(mySocket)
myTransport.start_client()

To get the remote hostkey, we call myTransport.get_remote_server_key():

sshKey = myTransport.get_remote_server_key()

At this point sshKey.__str__() contains the binary representation of the hostkey. Calling print sshKey.__str__() will output said binary data to our terminal.

We can then immediately close both the paramiko transport and the socket, as sshKey contains the information we need.

myTransport.close()
mySocket.close()

For a printable (base64 encoded) representation:

printableKey = '%s %s' %(sshKey.get_name(), base64.encodestring(sshKey.__str__()).replace('\n', ''))
print printableKey

In my case, this returns:

>>> print printableKey
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA0JCrB2J5YWa3m6buNqQ5/Scd/X9xs0gvDVZhokPZtFdtMgYnZhpAge3WZyFZxnt8ToE8K8d+haEQW5PaZykqD61Ur7gzW3KSZkA9L1q3IqIFLkUcI/Db82j5+rZ0w8W8oARfoOb4aR9Q+N4FbnMxO4FUzlCD1LpDA2XMnoOyDrr7WzYoopJencPuCCLm56+40QuHRoEI3gkUg34Utq8pV9vOqEBNMK21LEeG82CIIPB1nASNsaTfbAj1K9RBKrlobLiLFVPagxJY+Vd5lUPY/0RGgRBRofy7hRA4JUTPTqhkTg582Kw1GRNRDCf2AMIuPZLe3qqPWmJZ8fV897U2QQ==

To gain the host fingerprint, which is an MD5 hash of the key:

sshFingerprint = hashlib.md5(sshKey.__str__()).hexdigest()

This returns a 32 byte MD5 representation:

>>> print sshFingerprint
5203d8c22dec1016514334668f4d42f9

Lastly, to convert that to the colon separated fingerprint that we’re familiar with:

printableFingerprint = ':'.join(a+b for a,b in zip(sshFingerprint[::2], sshFingerprint[1::2]))
>>> print printableFingerprint
52:03:d8:c2:2d:ec:10:16:51:43:34:66:8f:4d:42:f9

To put it all together:

import socket
import paramiko
import hashlib
import base64
import sys

if len(sys.argv) != 3:
	print "Usage: %s <ip> <port>" % sys.argv[0]
	quit()

try:
	mySocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
	mySocket.connect((sys.argv[1], int(sys.argv[2])))
except socket.error:
	print "Error opening socket"
	quit()

try:
	myTransport = paramiko.Transport(mySocket)
	myTransport.start_client()
	sshKey = myTransport.get_remote_server_key()
except paramiko.SSHException:
	print "SSH error"
	quit()

myTransport.close()
mySocket.close()


printableType = sshKey.get_name()
printableKey = base64.encodestring(sshKey.__str__()).replace('\n', '')
sshFingerprint = hashlib.md5(sshKey.__str__()).hexdigest()
printableFingerprint = ':'.join(a+b for a,b in zip(sshFingerprint[::2], sshFingerprint[1::2]))
print "HostKey Type: %s, Key: %s (Fingerprint: %s)" %(printableType, printableKey, printableFingerprint)

Which is run as follows:

root@w:~/tmp# ./pyHostKey.py localhost 22
HostKey Type: ssh-rsa, Key: AAAAB3NzaC1yc2EAAAABIwAAAQEA0JCrB2J5YWa3m6buNqQ5/Scd/X9xs0gvDVZhokPZtFdtMgYnZhpAge3WZyFZxnt8ToE8K8d+haEQW5PaZykqD61Ur7gzW3KSZkA9L1q3IqIFLkUcI/Db82j5+rZ0w8W8oARfoOb4aR9Q+N4FbnMxO4FUzlCD1LpDA2XMnoOyDrr7WzYoopJencPuCCLm56+40QuHRoEI3gkUg34Utq8pV9vOqEBNMK21LEeG82CIIPB1nASNsaTfbAj1K9RBKrlobLiLFVPagxJY+Vd5lUPY/0RGgRBRofy7hRA4JUTPTqhkTg582Kw1GRNRDCf2AMIuPZLe3qqPWmJZ8fV897U2QQ== (Fingerprint: 52:03:d8:c2:2d:ec:10:16:51:43:34:66:8f:4d:42:f9)

Tags: , , , , , , ,

Leave a Reply