8

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?

Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
romeozor
  • 861
  • 1
  • 11
  • 26

2 Answers2

15

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.

Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
ViniH
  • 756
  • 1
  • 7
  • 12
  • could you explain why sftpClient ssh.net doesnt require the key yet WinScp does. is SSH.Net less secure by default or am i missing something – Seabizkit Oct 23 '17 at 22:20
  • This is for MD5-fingerprint. I guess it wont work for SHA-256 fingerprints. – hightech Aug 27 '20 at 12:58
  • @Seabizkit Because that's how SSH.NET is designed. WinSCP (and most other SSH clients and libraries) by default requires you to check the host key, as that's an integral part of SSH security. SSH.NET does not. That's wrong. You have to implement the `HostKeyReceived` event to achieve the same level of security as WinSCP and other libraries have. – Martin Prikryl May 02 '21 at 11:09
  • @hightech For SHA-256 fingerprint, see my answer. – Martin Prikryl May 04 '21 at 07:19
3

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 want to compare complete host key (in a format you see in OpenSSH known_hosts file), just Base64-encode the e.HostKey:

Convert.ToBase64String(e.HostKey)
Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992