diff --git a/README.md b/README.md index 242c6dc6a..d67895d7d 100755 --- a/README.md +++ b/README.md @@ -149,30 +149,13 @@ using (var client = new SftpClient(connectionInfo)) Establish a SSH connection using user name and password, and reject the connection if the fingerprint of the server does not match the expected fingerprint: ```cs -byte[] expectedFingerPrint = new byte[] { - 0x66, 0x31, 0xaf, 0x00, 0x54, 0xb9, 0x87, 0x31, - 0xff, 0x58, 0x1c, 0x31, 0xb1, 0xa2, 0x4c, 0x6b - }; +string expectedFingerPrint = "LKOy5LvmtEe17S4lyxVXqvs7uPMy+yF79MQpHeCs/Qo"; using (var client = new SshClient("sftp.foo.com", "guest", "pwd")) { client.HostKeyReceived += (sender, e) => { - if (expectedFingerPrint.Length == e.FingerPrint.Length) - { - for (var i = 0; i < expectedFingerPrint.Length; i++) - { - if (expectedFingerPrint[i] != e.FingerPrint[i]) - { - e.CanTrust = false; - break; - } - } - } - else - { - e.CanTrust = false; - } + e.CanTrust = expectedFingerPrint.Equals(e.FingerPrintSHA256); }; client.Connect(); } diff --git a/src/Renci.SshNet.Tests/Classes/Common/HostKeyEventArgsTest.cs b/src/Renci.SshNet.Tests/Classes/Common/HostKeyEventArgsTest.cs index 93055c6e0..516e3623f 100644 --- a/src/Renci.SshNet.Tests/Classes/Common/HostKeyEventArgsTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Common/HostKeyEventArgsTest.cs @@ -2,6 +2,8 @@ using Renci.SshNet.Common; using Renci.SshNet.Security; using Renci.SshNet.Tests.Common; +using System.Linq; +using System.Reflection; namespace Renci.SshNet.Tests.Classes.Common { @@ -10,7 +12,6 @@ namespace Renci.SshNet.Tests.Classes.Common ///to contain all HostKeyEventArgsTest Unit Tests /// [TestClass] - [Ignore] // placeholder for actual test public class HostKeyEventArgsTest : TestBase { /// @@ -19,9 +20,52 @@ public class HostKeyEventArgsTest : TestBase [TestMethod] public void HostKeyEventArgsConstructorTest() { - KeyHostAlgorithm host = null; // TODO: Initialize to an appropriate value - HostKeyEventArgs target = new HostKeyEventArgs(host); - Assert.Inconclusive("TODO: Implement code to verify target"); + HostKeyEventArgs target = new HostKeyEventArgs(GetKeyHostAlgorithm()); + Assert.IsTrue(target.CanTrust); + Assert.IsTrue(new byte[] { + 0x00, 0x00, 0x00, 0x07, 0x73, 0x73, 0x68, 0x2d, 0x72, 0x73, 0x61, 0x00, 0x00, 0x00, 0x01, 0x23, + 0x00, 0x00, 0x01, 0x01, 0x00, 0xb9, 0x3b, 0x57, 0x9f, 0xe0, 0x5a, 0xb5, 0x7d, 0x68, 0x26, 0xeb, + 0xe1, 0xa9, 0xf2, 0x59, 0xc3, 0x98, 0xdc, 0xfe, 0x97, 0x08, 0xc4, 0x95, 0x0f, 0x9a, 0xea, 0x05, + 0x08, 0x7d, 0xfe, 0x6d, 0x77, 0xca, 0x04, 0x9f, 0xfd, 0xe2, 0x2c, 0x4d, 0x11, 0x3c, 0xd9, 0x05, + 0xab, 0x32, 0xbd, 0x3f, 0xe8, 0xcd, 0xba, 0x00, 0x6c, 0x21, 0xb7, 0xa9, 0xc2, 0x4e, 0x63, 0x17, + 0xf6, 0x04, 0x47, 0x93, 0x00, 0x85, 0xde, 0xd6, 0x32, 0xc0, 0xa1, 0x37, 0x75, 0x18, 0xa0, 0xb0, + 0x32, 0xf6, 0x4e, 0xca, 0x39, 0xec, 0x3c, 0xdf, 0x79, 0xfe, 0x50, 0xa1, 0xc1, 0xf7, 0x67, 0x05, + 0xb3, 0x33, 0xa5, 0x96, 0x13, 0x19, 0xfa, 0x14, 0xca, 0x55, 0xe6, 0x7b, 0xf9, 0xb3, 0x8e, 0x32, + 0xee, 0xfc, 0x9d, 0x2a, 0x5e, 0x04, 0x79, 0x97, 0x29, 0x3d, 0x1c, 0x54, 0xfe, 0xc7, 0x96, 0x04, + 0xb5, 0x19, 0x7c, 0x55, 0x21, 0xe2, 0x0e, 0x42, 0xca, 0x4d, 0x9d, 0xfb, 0x77, 0x08, 0x6c, 0xaa, + 0x07, 0x2c, 0xf8, 0xf9, 0x1f, 0xbd, 0x83, 0x14, 0x2b, 0xe0, 0xbc, 0x7a, 0xf9, 0xdf, 0x13, 0x4b, + 0x60, 0x5a, 0x02, 0x99, 0x93, 0x41, 0x1a, 0xb6, 0x5f, 0x3b, 0x9c, 0xb5, 0xb2, 0x55, 0x70, 0x78, + 0x2f, 0x38, 0x52, 0x0e, 0xd1, 0x8a, 0x2c, 0x23, 0xc0, 0x3a, 0x0a, 0xd7, 0xed, 0xf6, 0x1f, 0xa6, + 0x50, 0xf0, 0x27, 0x65, 0x8a, 0xd4, 0xde, 0xa7, 0x1b, 0x41, 0x67, 0xc5, 0x6d, 0x47, 0x84, 0x37, + 0x92, 0x2b, 0xb7, 0xb6, 0x4d, 0xb0, 0x1a, 0xda, 0xf6, 0x50, 0x82, 0xf1, 0x57, 0x31, 0x69, 0xce, + 0xe0, 0xef, 0xcd, 0x64, 0xaa, 0x78, 0x08, 0xea, 0x4e, 0x45, 0xec, 0xa5, 0x89, 0x68, 0x5d, 0xb4, + 0xa0, 0x23, 0xaf, 0xff, 0x9c, 0x0f, 0x8c, 0x83, 0x7c, 0xf8, 0xe1, 0x8e, 0x32, 0x8e, 0x61, 0xfc, + 0x5b, 0xbd, 0xd4, 0x46, 0xe1 + }.SequenceEqual(target.HostKey)); + Assert.AreEqual("ssh-rsa", target.HostKeyName); + Assert.AreEqual(2048, target.KeyLength); + } + + /// + ///A test for MD5 calculation in HostKeyEventArgs Constructor + /// + [TestMethod] + public void HostKeyEventArgsConstructorTest_VerifyMD5() + { + HostKeyEventArgs target = new HostKeyEventArgs(GetKeyHostAlgorithm()); + Assert.IsTrue(new byte[] { + 0x92, 0xea, 0x54, 0xa1, 0x01, 0xf9, 0x95, 0x9c, 0x71, 0xd9, 0xbb, 0x51, 0xb2, 0x55, 0xf8, 0xd9 + }.SequenceEqual(target.FingerPrint)); + } + + /// + ///A test for SHA256 calculation in HostKeyEventArgs Constructor + /// + [TestMethod] + public void HostKeyEventArgsConstructorTest_VerifySHA256() + { + HostKeyEventArgs target = new HostKeyEventArgs(GetKeyHostAlgorithm()); + Assert.AreEqual("93LkmoWksp9ytNVZIPXi9KJU1uvlC9clZ/CkUHf6uEE", target.FingerPrintSHA256); } /// @@ -30,14 +74,24 @@ public void HostKeyEventArgsConstructorTest() [TestMethod] public void CanTrustTest() { - KeyHostAlgorithm host = null; // TODO: Initialize to an appropriate value - HostKeyEventArgs target = new HostKeyEventArgs(host); // TODO: Initialize to an appropriate value - bool expected = false; // TODO: Initialize to an appropriate value + HostKeyEventArgs target = new HostKeyEventArgs(GetKeyHostAlgorithm()); + bool expected = false; bool actual; target.CanTrust = expected; actual = target.CanTrust; Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); } + + private static KeyHostAlgorithm GetKeyHostAlgorithm() + { + var executingAssembly = Assembly.GetExecutingAssembly(); + + using (var s = executingAssembly.GetManifestResourceStream(string.Format("Renci.SshNet.Tests.Data.{0}", "Key.RSA.txt"))) + { + var privateKey = new PrivateKeyFile(s); + return (KeyHostAlgorithm)privateKey.HostKey; + } + } + } } diff --git a/src/Renci.SshNet/Common/HostKeyEventArgs.cs b/src/Renci.SshNet/Common/HostKeyEventArgs.cs index 7f0d6befc..8c1185192 100644 --- a/src/Renci.SshNet/Common/HostKeyEventArgs.cs +++ b/src/Renci.SshNet/Common/HostKeyEventArgs.cs @@ -28,10 +28,21 @@ public class HostKeyEventArgs : EventArgs public string HostKeyName{ get; private set; } /// - /// Gets the finger print. + /// Gets the MD5 fingerprint. /// + /// + /// MD5 fingerprint as byte array. + /// public byte[] FingerPrint { get; private set; } + /// + /// Gets the SHA256 fingerprint. + /// + /// + /// Base64 encoded SHA256 fingerprint with padding (equals sign) removed. + /// + public string FingerPrintSHA256 { get; private set; } + /// /// Gets the length of the key in bits. /// @@ -58,6 +69,11 @@ public HostKeyEventArgs(KeyHostAlgorithm host) { FingerPrint = md5.ComputeHash(host.Data); } + + using (var sha256 = CryptoAbstraction.CreateSHA256()) + { + FingerPrintSHA256 = Convert.ToBase64String(sha256.ComputeHash(host.Data)).Replace("=", ""); + } } } }