SSH/SFTP Server Fingerprint Hash

Introduction

I came across the need (see Background below for more info) to get the MD5 Hash of an SFTP server to use with a C# app client that uses the WinSCP library. I set the SshHostKeyFingerprint property of a SessionOptions object in a .Net application which we regularly use at work to transfer a report to a client of the company I work for. It had been working well for a long time and I didn’t know they had changed their SFTP server. After I learned that nothing nefarious was going on and the change in fingerprint was to be expected, I started to investigate how to get the new fingerprint in the same format as the old host key was in our App.confing file. I do not know exactly what formats are viable for the SshHostKeyFingerprint, so I wanted to just use the same format that we had.

Configuration Change

The value we were using to put in the SshHostKeyFingerprint was like this and we were storing it in the App.config file for our application.

ssh-rsa 2048 6f:17:16:74:92:a6:83:81:81:bf:3c:cd:fe:55:81:91

Basically, it is the algorithm followed by the number of bits followed by an MD5 hash where each byte in hex is separated by a colon. That was my goal—to generate a new string like that.

My First Clue to a Solution

After searching online how to get the fingerprint of a server, the results showed that I needed to use the ssh-keyscan from the command line. I ran a command like this to get the fingerprint of the server.

ssh-keyscan -p 22 -t rsa 192.168.1.84

The -p argument is the port and the -t argument is the algorithm type and finally the IP address or you can use the host name for the last argument. The output looked like this.

# 192.168.1.84:22 SSH-2.0-OpenSSH_8.1
192.168.1.84 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDroSZXbkMkeSr+gX3LaOvDlv/Hsb56+hIFlehYHpDV/+THtzLDHDfQd6J9NmzncaxkUJECnc8HgnmFdbyJjt/TOqjr5YYg/vkDHvb56NclBr6yiS2V2wVGepEKCTPAguTdIE6A5LxIJSYrZSUrznFhZECqhesvhgI9wjn62vcX8Mdk69/S8SzLYySbuOgThAYDeurAYIhgli+rOPuIAgyLAltTxjXLcuMb9D9P7CTcsp5g5eFxHGI0W05Eg3yJ/8rANxnGzVAxuVqJ7r6Yhb+degF+paD3EboHoZYjudvAFFHA31nRyPEgoRNBgPi+4/Q+4fK0XWZKHX/CgtgnKhGSMt7H7ywEg6ACRm1+MQyC3FbZ/Y3r8nTYbxN03PUXFHqVS/7qxzJB+E+cHCZhHpCsPZ9urmKDqvIu2cR24G4XM5L4jypNeL90j2NlVe0mL1VSS1z13L8WdaTHqfBlSprSYpCNV4Yzm/QBt/njVFUN9X3nwY+w+qM6FoFQCt5ZXjM=

That does not meet my goal, so I wasn’t sure what to do, but I tried doing some more searching online and found that I just needed to hash that fingerprint value. I also learned that the output of the fingerprint from ssh-keyscan is base64 encoded.

Solution

I wrote a quick PowerShell script to get me the MD5 has so that I could replace the bad hash with the new one in the configuration file for the app.

#edit this line for your needs
$ipOrName = '192.168.1.85'

# redirect standard err to null so we get just the output we want
$keyScanOutput = (ssh-keyscan -p 22 -t rsa $ipOrName 2> $null)
#uncomment if you want to see the base64 encoded output from ssh-keyscan
#$keyScanOutput

$segments = ($keyScanOutput -split ' ')
# All I need is the last output value -- the one with the base64 encoded fingerprint of the server
$ssh_rsa = $segments[2]
$bin = [System.Convert]::FromBase64String($ssh_rsa)
$md5 = New-Object -TypeName System.Security.Cryptography.MD5CryptoServiceProvider
$sha256 = New-Object -TypeName System.Security.Cryptography.SHA256CryptoServiceProvider

$md5Checksum = [System.BitConverter]::ToString($md5.ComputeHash($bin))
$md5Checksum.Replace('-', ':').ToLower()

$sha256Checksum = [System.Convert]::ToBase64String($sha256.ComputeHash($bin))
$sha256Checksum

The script ran and the output was like this.

PowerShell output

Now I had both the MD5 hash and as a bonus the SHA256 hash of the fingerprint to use in my configuration.

Confirming the Hashes

I knew that I did not follow the above process the last time I needed to do this, but I could not remember how I got the values I needed. I opened FileZilla because I knew I had seen these values in the UI. After finding a site online reminding me how to get the hashes using FileZilla, I clicked on the lock icon near the bottom right corner of the window and up popped a dialog with the same values I needed to confirm that the PowerShell script worked. Why I couldn’t remember how to get this from FileZilla to begin with, I’ll never know. I believe that running this script to get the hash is worth the effort if you don’t already have FileZilla or other app installed that can return this information. By the way, if you have FileZilla and don’t want to run the script I wrote, if you double-click on the hashed key in the Encryption details window in FileZilla, it will copy it to the clipboard.

Background

My company’s client changed something on their SFTP server, and the fingerprint changed and thus our app that uses the WinSCP library to transfer a monthly report to them failed. The error message that I saw in the log file was:

WinSCP.SessionRemoteException: Host key does not match configured key fingerprint "ssh-rsa 2048 8b:73:73:9a:a9:b2:3a:5c:a4:c5:1d:17:2a:44:5d:b1"!
Host key fingerprint is ssh-rsa 2048 BvpOqCaKsE5kYlX2i1E21+X6OKep1gmWOQKUR3OqUVQ=.
Authentication failed.

Conclusion

After updating the configuration file with the new MD5 hash like the one I showed near the start of the article and running a test, our app started working again as it did before. I hope that this article can get you to a quicker solution to this simple task than it was for me.