I'm currently creating an SSIS package where I need to connect to a secure server to copy some files and I would like to validate the connection via the public key fingerprint the server sends.
I'm not very familiar in this area, can I always expect there to be a fingerprint sent when connecting?
The package previously used WinSCP, and a fingerprint was baked into the code in the format of ssh-dss 1024 [hex representation]
. I assume this format is taken from PuTTY, because that's how I see it while connecting to a new server and it's asking me to verify. WinSCP took this as is and handled the verification.
I'm planning to switch to SSH.NET and its mechanism requires me to check the fingerprint by hand. Can I verify the connection based on just the hex, or do I need to also check the key length and the algorithm used?
The quickest way to obtain it would be to login to your SSH/SFTP server from a locally installed client application, i.e. installed on the same machine as your server. That way, you can be absolutely sure you're safe from man-in-the-middle attacks. Copy that fingerprint and save it where you can easily access it.
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.
Each SFTP host has one unique key used to encrypt the connection. The key has a unique “fingerprint”. The fingerprint can be entered as a series of hexadecimal numbers separated by colons. Contact your SFTP server's administrator to provide the fingerprint of the server.
You can do it just based on the hex - first you'll want to write (or copy/use) a utility method to convert your hex string to a byte array (which will depend on the format of your hex string) - the example below is for converting a string delimited by colon (e.g. "1d:c1:5a:71:c4:8e:a3:ff:01:0a:3b:46:17:6f:e1:52")
public static byte[] ConvertFingerprintToByteArray( String fingerprint )
{
return fingerprint.Split( ':' ).Select( s => Convert.ToByte( s, 16 ) ).ToArray();
}
Then you simply attach to the HostKeyReceived
event of the SftpClient
object.
SftpClient sftpClient = new SftpClient( Hostname, Username, Password );
sftpClient.HostKeyReceived += delegate ( object sender, HostKeyEventArgs e )
{
var b = ConvertFingerprintToByteArray(
"1d:c1:5a:71:c4:8e:a3:ff:01:0a:3b:46:17:6f:e1:52" );
if( e.FingerPrint.SequenceEqual( b ) )
e.CanTrust = true;
else
e.CanTrust = false;
};
If this check fails then SSH.NET will throw an SshConnectionException
– with a message of "Key exchange negotiation failed".
Hope this helps.
The answer by @ViniH was correct once, but it is outdated now. Nowadays, you need to use SHA-256 hashes, not MD5. To compute the SHA-256, you can use System.Security.Cryptography.SHA256Managed
class with HostKeyEventArgs.HostKey
.
Further, you may want to use Convert.ToBase64String
to get the common Base64 representation of the SHA-256 fingerprint
sftpClient.HostKeyReceived += (object sender, HostKeyEventArgs e) =>
{
string sha256Fingerprint =
Convert.ToBase64String(new SHA256Managed().ComputeHash(e.HostKey));
e.CanTrust = (sha256Fingerprint == "1hI1HqP3IzoOWCABHGS7+GsrP2JUVsSs7oskK7HGP1E=");
};
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