Wojciech Nagórski 2 rokov pred
rodič
commit
18e6673031

+ 2 - 1
src/Renci.SshNet.Benchmarks/Security/Cryptography/Ciphers/RsaCipherBenchmarks.cs

@@ -21,7 +21,8 @@ namespace Renci.SshNet.Benchmarks.Security.Cryptography.Ciphers
 
             using (var s = typeof(RsaCipherBenchmarks).Assembly.GetManifestResourceStream("Renci.SshNet.Benchmarks.Data.Key.RSA.txt"))
             {
-                _privateKey = (RsaKey)((KeyHostAlgorithm) new PrivateKeyFile(s).HostKey).Key;
+                
+                _privateKey = (RsaKey)new PrivateKeyFile(s).Key;
                 
                 // The implementations of RsaCipher.Encrypt/Decrypt differ based on whether the supplied RsaKey has private key information
                 // or only public. So we extract out the public key information to a separate variable.

+ 1 - 1
src/Renci.SshNet.Benchmarks/Security/Cryptography/ED25519DigitalSignatureBenchmarks.cs

@@ -21,7 +21,7 @@ namespace Renci.SshNet.Benchmarks.Security.Cryptography
 
             using (var s = typeof(ED25519DigitalSignatureBenchmarks).Assembly.GetManifestResourceStream("Renci.SshNet.Benchmarks.Data.Key.OPENSSH.ED25519.txt"))
             {
-                _key = (ED25519Key) ((KeyHostAlgorithm) new PrivateKeyFile(s).HostKey).Key;
+                _key = (ED25519Key) new PrivateKeyFile(s).Key;
             }
             _signature = new ED25519DigitalSignature(_key).Sign(_data);
         }

+ 2 - 1
src/Renci.SshNet.Tests/Classes/BaseClientTest_Connect_OnConnectedThrowsException.cs

@@ -1,4 +1,5 @@
 using System;
+using System.Linq;
 using System.Reflection;
 using System.Threading;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
@@ -140,7 +141,7 @@ namespace Renci.SshNet.Tests.Classes
             using (var s = executingAssembly.GetManifestResourceStream(string.Format("Renci.SshNet.Tests.Data.{0}", "Key.RSA.txt")))
             {
                 var privateKey = new PrivateKeyFile(s);
-                return (KeyHostAlgorithm) privateKey.HostKey;
+                return (KeyHostAlgorithm) privateKey.HostKeyAlgorithms.First();
             }
         }
 

+ 1 - 1
src/Renci.SshNet.Tests/Classes/Common/HostKeyEventArgsTest.cs

@@ -89,7 +89,7 @@ namespace Renci.SshNet.Tests.Classes.Common
             using (var s = executingAssembly.GetManifestResourceStream(string.Format("Renci.SshNet.Tests.Data.{0}", "Key.RSA.txt")))
             {
                 var privateKey = new PrivateKeyFile(s);
-                return (KeyHostAlgorithm)privateKey.HostKey;
+                return (KeyHostAlgorithm)privateKey.HostKeyAlgorithms.First();
             }
         }
 

+ 2 - 1
src/Renci.SshNet.Tests/Classes/NetConfClientTest_Connect_NetConfSessionConnectFailure.cs

@@ -1,4 +1,5 @@
 using System;
+using System.Linq;
 using System.Reflection;
 using System.Threading;
 
@@ -113,7 +114,7 @@ namespace Renci.SshNet.Tests.Classes
             using (var s = executingAssembly.GetManifestResourceStream(string.Format("Renci.SshNet.Tests.Data.{0}", "Key.RSA.txt")))
             {
                 var privateKey = new PrivateKeyFile(s);
-                return (KeyHostAlgorithm)privateKey.HostKey;
+                return (KeyHostAlgorithm)privateKey.HostKeyAlgorithms.First();
             }
         }
     }

+ 9 - 12
src/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs

@@ -1,9 +1,7 @@
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 using Renci.SshNet.Common;
-using Renci.SshNet.Security;
 using Renci.SshNet.Tests.Common;
 using System;
-using System.Collections.Generic;
 using System.IO;
 using System.Linq;
 
@@ -412,7 +410,7 @@ namespace Renci.SshNet.Tests.Classes
             using (var stream = GetData("Key.RSA.Encrypted.Aes.128.CBC.12345.txt"))
             {
                 var privateKeyFile = new PrivateKeyFile(stream, "12345");
-                Assert.IsNotNull(privateKeyFile.HostKey);
+                TestRsaKeyFile(privateKeyFile);
             }
         }
 
@@ -430,7 +428,7 @@ namespace Renci.SshNet.Tests.Classes
             using (var fs = File.Open(_temporaryFile, FileMode.Open, FileAccess.Read, FileShare.Read))
             {
                 var privateKeyFile = new PrivateKeyFile(_temporaryFile, "12345");
-                Assert.IsNotNull(privateKeyFile.HostKey);
+                TestRsaKeyFile(privateKeyFile);
 
                 fs.Close();
             }
@@ -498,7 +496,7 @@ namespace Renci.SshNet.Tests.Classes
             }
 
             var privateKeyFile = new PrivateKeyFile(_temporaryFile, "12345");
-            Assert.IsNotNull(privateKeyFile.HostKey);
+            TestRsaKeyFile(privateKeyFile);
         }
 
         /// <summary>
@@ -510,7 +508,7 @@ namespace Renci.SshNet.Tests.Classes
             using (var stream = GetData("Key.RSA.txt"))
             {
                 var privateKeyFile = new PrivateKeyFile(stream);
-                Assert.IsNotNull(privateKeyFile.HostKey);
+                TestRsaKeyFile(privateKeyFile);
             }
         }
 
@@ -526,7 +524,7 @@ namespace Renci.SshNet.Tests.Classes
             using (var fs = File.Open(_temporaryFile, FileMode.Open, FileAccess.Read, FileShare.Read))
             {
                 var privateKeyFile = new PrivateKeyFile(_temporaryFile);
-                Assert.IsNotNull(privateKeyFile.HostKey);
+                TestRsaKeyFile(privateKeyFile);
 
                 fs.Close();
             }
@@ -544,7 +542,7 @@ namespace Renci.SshNet.Tests.Classes
             using (var fs = File.Open(_temporaryFile, FileMode.Open, FileAccess.Read, FileShare.Read))
             {
                 var privateKeyFile = new PrivateKeyFile(_temporaryFile, "12345");
-                Assert.IsNotNull(privateKeyFile.HostKey);
+                TestRsaKeyFile(privateKeyFile);
 
                 fs.Close();
             }
@@ -684,15 +682,14 @@ namespace Renci.SshNet.Tests.Classes
 
         private static void TestRsaKeyFile(PrivateKeyFile rsaPrivateKeyFile)
         {
-            Assert.AreEqual(3, rsaPrivateKeyFile.HostAlgorithms.Count);
+            Assert.IsNotNull(rsaPrivateKeyFile.HostKeyAlgorithms);
+            Assert.AreEqual(3, rsaPrivateKeyFile.HostKeyAlgorithms.Count);
 
-            List<KeyHostAlgorithm> algorithms = rsaPrivateKeyFile.HostAlgorithms.Cast<KeyHostAlgorithm>().ToList();
+            var algorithms = rsaPrivateKeyFile.HostKeyAlgorithms.ToList();
 
             Assert.AreEqual("rsa-sha2-512", algorithms[0].Name);
             Assert.AreEqual("rsa-sha2-256", algorithms[1].Name);
             Assert.AreEqual("ssh-rsa", algorithms[2].Name);
-
-            Assert.AreSame(algorithms[0], rsaPrivateKeyFile.HostKey);
         }
     }
 }

+ 1 - 1
src/Renci.SshNet.Tests/Classes/Security/Cryptography/RsaDigitalSignatureTest.cs

@@ -164,7 +164,7 @@ namespace Renci.SshNet.Tests.Classes.Security.Cryptography
         {
             using (var stream = GetData("Key.RSA.txt"))
             {
-                return (RsaKey) ((KeyHostAlgorithm) new PrivateKeyFile(stream).HostKey).Key;
+                return (RsaKey) new PrivateKeyFile(stream).Key;
             }
         }
 

+ 2 - 2
src/Renci.SshNet.Tests/Classes/Security/KeyAlgorithmTest.cs

@@ -1,4 +1,4 @@
-using System.Security.Cryptography;
+using System.Security.Cryptography;
 using System.Text;
 
 using Microsoft.VisualStudio.TestTools.UnitTesting;
@@ -176,7 +176,7 @@ namespace Renci.SshNet.Tests.Classes.Security
         {
             using (var stream = GetData("Key.RSA.txt"))
             {
-                return (RsaKey) ((KeyHostAlgorithm) new PrivateKeyFile(stream).HostKey).Key;
+                return (RsaKey) new PrivateKeyFile(stream).Key;
             }
         }
 

+ 2 - 1
src/Renci.SshNet.Tests/Classes/SftpClientTest_Connect_SftpSessionConnectFailure.cs

@@ -1,4 +1,5 @@
 using System;
+using System.Linq;
 using System.Reflection;
 using System.Threading;
 
@@ -122,7 +123,7 @@ namespace Renci.SshNet.Tests.Classes
             using (var s = executingAssembly.GetManifestResourceStream(string.Format("Renci.SshNet.Tests.Data.{0}", "Key.RSA.txt")))
             {
                 var privateKey = new PrivateKeyFile(s);
-                return (KeyHostAlgorithm)privateKey.HostKey;
+                return (KeyHostAlgorithm)privateKey.HostKeyAlgorithms.First();
             }
         }
     }

+ 0 - 21
src/Renci.SshNet/IHostAlgorithmsProvider.cs

@@ -1,21 +0,0 @@
-using System.Collections.Generic;
-
-using Renci.SshNet.Security;
-
-namespace Renci.SshNet
-{
-    /// <summary>
-    /// Represents a collection of host algorithms.
-    /// </summary>
-    public interface IHostAlgorithmsProvider
-    {
-        /// <summary>
-        /// The host algorithms provided by this <see cref="IHostAlgorithmsProvider"/>.
-        /// </summary>
-        /// <remarks>
-        /// In situations where there is a preferred order of usage of the host algorithms,
-        /// the collection should be ordered from most preferred to least.
-        /// </remarks>
-        IReadOnlyCollection<HostAlgorithm> HostAlgorithms { get; }
-    }
-}

+ 8 - 13
src/Renci.SshNet/IPrivateKeySource.cs

@@ -1,5 +1,4 @@
-using System;
-using System.ComponentModel;
+using System.Collections.Generic;
 
 using Renci.SshNet.Security;
 
@@ -8,19 +7,15 @@ namespace Renci.SshNet
     /// <summary>
     /// Represents private key source interface.
     /// </summary>
-    /// <remarks>
-    /// This interface has been replaced by <see cref="IHostAlgorithmsProvider"/>
-    /// and is obsolete.
-    /// </remarks>
-    [Obsolete($"Use {nameof(IHostAlgorithmsProvider)} instead. " +
-        $"{nameof(IPrivateKeySource)} may be removed in a future release. " +
-        $"See https://github.com/sshnet/SSH.NET/issues/1174 for details.")]
-    [EditorBrowsable(EditorBrowsableState.Never)]
-    public interface IPrivateKeySource : IHostAlgorithmsProvider
+    public interface IPrivateKeySource
     {
         /// <summary>
-        /// Gets the host key.
+        /// Gets the host keys algorithms.
         /// </summary>
-        HostAlgorithm HostKey { get; }
+        /// <remarks>
+        /// In situations where there is a preferred order of usage of the host algorithms,
+        /// the collection should be ordered from most preferred to least.
+        /// </remarks>
+        IReadOnlyCollection<HostAlgorithm> HostKeyAlgorithms { get; }
     }
 }

+ 2 - 2
src/Renci.SshNet/NetConfClient.cs

@@ -107,7 +107,7 @@ namespace Renci.SshNet
         /// <exception cref="ArgumentException"><paramref name="host"/> is invalid, -or- <paramref name="username"/> is <c>null</c> or contains only whitespace characters.</exception>
         /// <exception cref="ArgumentOutOfRangeException"><paramref name="port"/> is not within <see cref="IPEndPoint.MinPort"/> and <see cref="IPEndPoint.MaxPort"/>.</exception>
         [SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope", Justification = "Disposed in Dispose(bool) method.")]
-        public NetConfClient(string host, int port, string username, params IHostAlgorithmsProvider[] keyFiles)
+        public NetConfClient(string host, int port, string username, params IPrivateKeySource[] keyFiles)
             : this(new PrivateKeyConnectionInfo(host, port, username, keyFiles), ownsConnectionInfo: true)
         {
         }
@@ -120,7 +120,7 @@ namespace Renci.SshNet
         /// <param name="keyFiles">Authentication private key file(s) .</param>
         /// <exception cref="ArgumentNullException"><paramref name="keyFiles"/> is <c>null</c>.</exception>
         /// <exception cref="ArgumentException"><paramref name="host"/> is invalid, -or- <paramref name="username"/> is <c>null</c> or contains only whitespace characters.</exception>
-        public NetConfClient(string host, string username, params IHostAlgorithmsProvider[] keyFiles)
+        public NetConfClient(string host, string username, params IPrivateKeySource[] keyFiles)
             : this(host, ConnectionInfo.DefaultPort, username, keyFiles)
         {
         }

+ 4 - 4
src/Renci.SshNet/PrivateKeyAuthenticationMethod.cs

@@ -31,7 +31,7 @@ namespace Renci.SshNet
         /// <summary>
         /// Gets the key files used for authentication.
         /// </summary>
-        public ICollection<IHostAlgorithmsProvider> KeyFiles { get; private set; }
+        public ICollection<IPrivateKeySource> KeyFiles { get; private set; }
 
         /// <summary>
         /// Initializes a new instance of the <see cref="PrivateKeyAuthenticationMethod"/> class.
@@ -39,7 +39,7 @@ namespace Renci.SshNet
         /// <param name="username">The username.</param>
         /// <param name="keyFiles">The key files.</param>
         /// <exception cref="ArgumentException"><paramref name="username"/> is whitespace or <c>null</c>.</exception>
-        public PrivateKeyAuthenticationMethod(string username, params IHostAlgorithmsProvider[] keyFiles)
+        public PrivateKeyAuthenticationMethod(string username, params IPrivateKeySource[] keyFiles)
             : base(username)
         {
             if (keyFiles is null)
@@ -47,7 +47,7 @@ namespace Renci.SshNet
                 throw new ArgumentNullException(nameof(keyFiles));
             }
 
-            KeyFiles = new Collection<IHostAlgorithmsProvider>(keyFiles);
+            KeyFiles = new Collection<IPrivateKeySource>(keyFiles);
         }
 
         /// <summary>
@@ -65,7 +65,7 @@ namespace Renci.SshNet
 
             session.RegisterMessage("SSH_MSG_USERAUTH_PK_OK");
 
-            var hostAlgorithms = KeyFiles.SelectMany(x => x.HostAlgorithms).ToList();
+            var hostAlgorithms = KeyFiles.SelectMany(x => x.HostKeyAlgorithms).ToList();
 
             try
             {

+ 9 - 9
src/Renci.SshNet/PrivateKeyConnectionInfo.cs

@@ -17,7 +17,7 @@ namespace Renci.SshNet
         /// <summary>
         /// Gets the key files used for authentication.
         /// </summary>
-        public ICollection<IHostAlgorithmsProvider> KeyFiles { get; private set; }
+        public ICollection<IPrivateKeySource> KeyFiles { get; private set; }
 
         /// <summary>
         /// Initializes a new instance of the <see cref="PrivateKeyConnectionInfo"/> class.
@@ -41,7 +41,7 @@ namespace Renci.SshNet
         /// <param name="port">Connection port.</param>
         /// <param name="username">Connection username.</param>
         /// <param name="keyFiles">Connection key files.</param>
-        public PrivateKeyConnectionInfo(string host, int port, string username, params IHostAlgorithmsProvider[] keyFiles)
+        public PrivateKeyConnectionInfo(string host, int port, string username, params IPrivateKeySource[] keyFiles)
             : this(host, port, username, ProxyTypes.None, string.Empty, 0, string.Empty, string.Empty, keyFiles)
         {
         }
@@ -56,7 +56,7 @@ namespace Renci.SshNet
         /// <param name="proxyHost">The proxy host.</param>
         /// <param name="proxyPort">The proxy port.</param>
         /// <param name="keyFiles">The key files.</param>
-        public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, params IHostAlgorithmsProvider[] keyFiles)
+        public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, params IPrivateKeySource[] keyFiles)
             : this(host, port, username, proxyType, proxyHost, proxyPort, string.Empty, string.Empty, keyFiles)
         {
         }
@@ -72,7 +72,7 @@ namespace Renci.SshNet
         /// <param name="proxyPort">The proxy port.</param>
         /// <param name="proxyUsername">The proxy username.</param>
         /// <param name="keyFiles">The key files.</param>
-        public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, params IHostAlgorithmsProvider[] keyFiles)
+        public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, params IPrivateKeySource[] keyFiles)
             : this(host, port, username, proxyType, proxyHost, proxyPort, proxyUsername, string.Empty, keyFiles)
         {
         }
@@ -86,7 +86,7 @@ namespace Renci.SshNet
         /// <param name="proxyHost">The proxy host.</param>
         /// <param name="proxyPort">The proxy port.</param>
         /// <param name="keyFiles">The key files.</param>
-        public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, params IHostAlgorithmsProvider[] keyFiles)
+        public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, params IPrivateKeySource[] keyFiles)
             : this(host, DefaultPort, username, proxyType, proxyHost, proxyPort, string.Empty, string.Empty, keyFiles)
         {
         }
@@ -101,7 +101,7 @@ namespace Renci.SshNet
         /// <param name="proxyPort">The proxy port.</param>
         /// <param name="proxyUsername">The proxy username.</param>
         /// <param name="keyFiles">The key files.</param>
-        public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, params IHostAlgorithmsProvider[] keyFiles)
+        public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, params IPrivateKeySource[] keyFiles)
             : this(host, DefaultPort, username, proxyType, proxyHost, proxyPort, proxyUsername, string.Empty, keyFiles)
         {
         }
@@ -117,7 +117,7 @@ namespace Renci.SshNet
         /// <param name="proxyUsername">The proxy username.</param>
         /// <param name="proxyPassword">The proxy password.</param>
         /// <param name="keyFiles">The key files.</param>
-        public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, string proxyPassword, params IHostAlgorithmsProvider[] keyFiles)
+        public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, string proxyPassword, params IPrivateKeySource[] keyFiles)
             : this(host, DefaultPort, username, proxyType, proxyHost, proxyPort, proxyUsername, proxyPassword, keyFiles)
         {
         }
@@ -134,10 +134,10 @@ namespace Renci.SshNet
         /// <param name="proxyUsername">The proxy username.</param>
         /// <param name="proxyPassword">The proxy password.</param>
         /// <param name="keyFiles">The key files.</param>
-        public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, string proxyPassword, params IHostAlgorithmsProvider[] keyFiles)
+        public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, string proxyPassword, params IPrivateKeySource[] keyFiles)
             : base(host, port, username, proxyType, proxyHost, proxyPort, proxyUsername, proxyPassword, new PrivateKeyAuthenticationMethod(username, keyFiles))
         {
-            KeyFiles = new Collection<IHostAlgorithmsProvider>(keyFiles);
+            KeyFiles = new Collection<IPrivateKeySource>(keyFiles);
         }
 
         /// <summary>

+ 17 - 28
src/Renci.SshNet/PrivateKeyFile.cs

@@ -65,11 +65,7 @@ namespace Renci.SshNet
     /// </list>
     /// </para>
     /// </remarks>
-    public class PrivateKeyFile : IHostAlgorithmsProvider,
-#pragma warning disable CS0618 // Type or member is obsolete
-        IPrivateKeySource,
-#pragma warning restore CS0618 // Type or member is obsolete
-        IDisposable
+    public class PrivateKeyFile : IPrivateKeySource, IDisposable
     {
         private static readonly Regex PrivateKeyRegex = new Regex(@"^-+ *BEGIN (?<keyName>\w+( \w+)*) PRIVATE KEY *-+\r?\n((Proc-Type: 4,ENCRYPTED\r?\nDEK-Info: (?<cipherName>[A-Z0-9-]+),(?<salt>[A-F0-9]+)\r?\n\r?\n)|(Comment: ""?[^\r\n]*""?\r?\n))?(?<data>([a-zA-Z0-9/+=]{1,80}\r?\n)+)-+ *END \k<keyName> PRIVATE KEY *-+",
             RegexOptions.Compiled | RegexOptions.Multiline);
@@ -79,32 +75,24 @@ namespace Renci.SshNet
         private bool _isDisposed;
 
         /// <summary>
-        /// Gets the host key.
+        /// The supported host algorithms for this key file.
         /// </summary>
-        /// <remarks>
-        /// This property returns the first item in <see cref="HostAlgorithms"/>.
-        /// </remarks>
-        public HostAlgorithm HostKey
+        public IReadOnlyCollection<HostAlgorithm> HostKeyAlgorithms
         {
             get
             {
-                return _hostAlgorithms[0];
-            }
-            private set
-            {
-                Debug.Assert(_hostAlgorithms.Count == 0, $"Only expected to set {nameof(HostKey)} at most once.");
-                _hostAlgorithms.Add(value);
+                return _hostAlgorithms;
             }
         }
 
         /// <summary>
-        /// The supported host algorithms for this key file.
+        /// Gets the key.
         /// </summary>
-        public IReadOnlyCollection<HostAlgorithm> HostAlgorithms
+        public Key Key
         {
             get
             {
-                return _hostAlgorithms;
+                return _key;
             }
         }
 
@@ -114,7 +102,8 @@ namespace Renci.SshNet
         /// <param name="key">The key.</param>
         public PrivateKeyFile(Key key)
         {
-            HostKey = new KeyHostAlgorithm(key.ToString(), key);
+            _key = key;
+            _hostAlgorithms.Add(new KeyHostAlgorithm(key.ToString(), key));
         }
 
         /// <summary>
@@ -124,7 +113,7 @@ namespace Renci.SshNet
         public PrivateKeyFile(Stream privateKey)
         {
             Open(privateKey, passPhrase: null);
-            Debug.Assert(_hostAlgorithms.Count > 0, $"{nameof(HostKey)} is not set.");
+            Debug.Assert(_hostAlgorithms.Count > 0, $"{nameof(HostKeyAlgorithms)} is not set.");
         }
 
         /// <summary>
@@ -161,7 +150,7 @@ namespace Renci.SshNet
                 Open(keyFile, passPhrase);
             }
 
-            Debug.Assert(_hostAlgorithms.Count > 0, $"{nameof(HostKey)} is not set.");
+            Debug.Assert(_hostAlgorithms.Count > 0, $"{nameof(HostKeyAlgorithms)} is not set.");
         }
 
         /// <summary>
@@ -173,7 +162,8 @@ namespace Renci.SshNet
         public PrivateKeyFile(Stream privateKey, string passPhrase)
         {
             Open(privateKey, passPhrase);
-            Debug.Assert(_hostAlgorithms.Count > 0, $"{nameof(HostKey)} is not set.");
+
+            Debug.Assert(_hostAlgorithms.Count > 0, $"{nameof(HostKeyAlgorithms)} is not set.");
         }
 
         /// <summary>
@@ -266,11 +256,11 @@ namespace Renci.SshNet
                     break;
                 case "DSA":
                     _key = new DsaKey(decryptedData);
-                    HostKey = new KeyHostAlgorithm("ssh-dss", _key);
+                    _hostAlgorithms.Add(new KeyHostAlgorithm("ssh-dss", _key));
                     break;
                 case "EC":
                     _key = new EcdsaKey(decryptedData);
-                    HostKey = new KeyHostAlgorithm(_key.ToString(), _key);
+                    _hostAlgorithms.Add(new KeyHostAlgorithm(_key.ToString(), _key));
                     break;
                 case "OPENSSH":
                     _key = ParseOpenSshV1Key(decryptedData, passPhrase);
@@ -282,9 +272,8 @@ namespace Renci.SshNet
                     }
                     else
                     {
-                        HostKey = new KeyHostAlgorithm(_key.ToString(), _key);
+                        _hostAlgorithms.Add(new KeyHostAlgorithm(_key.ToString(), _key));
                     }
-
                     break;
                 case "SSH2 ENCRYPTED":
                     var reader = new SshDataReader(decryptedData);
@@ -358,7 +347,7 @@ namespace Renci.SshNet
                         var y = reader.ReadBigIntWithBits();
                         var x = reader.ReadBigIntWithBits();
                         _key = new DsaKey(p, q, g, y, x);
-                        HostKey = new KeyHostAlgorithm("ssh-dss", _key);
+                        _hostAlgorithms.Add(new KeyHostAlgorithm("ssh-dss", _key));
                     }
                     else
                     {

+ 2 - 2
src/Renci.SshNet/ScpClient.cs

@@ -146,7 +146,7 @@ namespace Renci.SshNet
         /// <exception cref="ArgumentException"><paramref name="host"/> is invalid, -or- <paramref name="username"/> is <c>null</c> or contains only whitespace characters.</exception>
         /// <exception cref="ArgumentOutOfRangeException"><paramref name="port"/> is not within <see cref="IPEndPoint.MinPort"/> and <see cref="IPEndPoint.MaxPort"/>.</exception>
         [SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope", Justification = "Disposed in Dispose(bool) method.")]
-        public ScpClient(string host, int port, string username, params IHostAlgorithmsProvider[] keyFiles)
+        public ScpClient(string host, int port, string username, params IPrivateKeySource[] keyFiles)
             : this(new PrivateKeyConnectionInfo(host, port, username, keyFiles), ownsConnectionInfo: true)
         {
         }
@@ -159,7 +159,7 @@ namespace Renci.SshNet
         /// <param name="keyFiles">Authentication private key file(s) .</param>
         /// <exception cref="ArgumentNullException"><paramref name="keyFiles"/> is <c>null</c>.</exception>
         /// <exception cref="ArgumentException"><paramref name="host"/> is invalid, -or- <paramref name="username"/> is <c>null</c> or contains only whitespace characters.</exception>
-        public ScpClient(string host, string username, params IHostAlgorithmsProvider[] keyFiles)
+        public ScpClient(string host, string username, params IPrivateKeySource[] keyFiles)
             : this(host, ConnectionInfo.DefaultPort, username, keyFiles)
         {
         }

+ 2 - 2
src/Renci.SshNet/SftpClient.cs

@@ -218,7 +218,7 @@ namespace Renci.SshNet
         /// <exception cref="ArgumentException"><paramref name="host"/> is invalid. <para>-or-</para> <paramref name="username"/> is nu<b>null</b>ll or contains only whitespace characters.</exception>
         /// <exception cref="ArgumentOutOfRangeException"><paramref name="port"/> is not within <see cref="IPEndPoint.MinPort"/> and <see cref="IPEndPoint.MaxPort"/>.</exception>
         [SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope", Justification = "Disposed in Dispose(bool) method.")]
-        public SftpClient(string host, int port, string username, params IHostAlgorithmsProvider[] keyFiles)
+        public SftpClient(string host, int port, string username, params IPrivateKeySource[] keyFiles)
             : this(new PrivateKeyConnectionInfo(host, port, username, keyFiles), ownsConnectionInfo: true)
         {
         }
@@ -231,7 +231,7 @@ namespace Renci.SshNet
         /// <param name="keyFiles">Authentication private key file(s) .</param>
         /// <exception cref="ArgumentNullException"><paramref name="keyFiles"/> is <b>null</b>.</exception>
         /// <exception cref="ArgumentException"><paramref name="host"/> is invalid. <para>-or-</para> <paramref name="username"/> is <b>null</b> or contains only whitespace characters.</exception>
-        public SftpClient(string host, string username, params IHostAlgorithmsProvider[] keyFiles)
+        public SftpClient(string host, string username, params IPrivateKeySource[] keyFiles)
             : this(host, ConnectionInfo.DefaultPort, username, keyFiles)
         {
         }

+ 2 - 2
src/Renci.SshNet/SshClient.cs

@@ -103,7 +103,7 @@ namespace Renci.SshNet
         /// <exception cref="ArgumentException"><paramref name="host"/> is invalid, -or- <paramref name="username"/> is <c>null</c> or contains only whitespace characters.</exception>
         /// <exception cref="ArgumentOutOfRangeException"><paramref name="port"/> is not within <see cref="IPEndPoint.MinPort"/> and <see cref="IPEndPoint.MaxPort"/>.</exception>
         [SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope", Justification = "Disposed in Dispose(bool) method.")]
-        public SshClient(string host, int port, string username, params IHostAlgorithmsProvider[] keyFiles)
+        public SshClient(string host, int port, string username, params IPrivateKeySource[] keyFiles)
             : this(new PrivateKeyConnectionInfo(host, port, username, keyFiles), ownsConnectionInfo: true)
         {
         }
@@ -120,7 +120,7 @@ namespace Renci.SshNet
         /// </example>
         /// <exception cref="ArgumentNullException"><paramref name="keyFiles"/> is <c>null</c>.</exception>
         /// <exception cref="ArgumentException"><paramref name="host"/> is invalid, -or- <paramref name="username"/> is <c>null</c> or contains only whitespace characters.</exception>
-        public SshClient(string host, string username, params IHostAlgorithmsProvider[] keyFiles)
+        public SshClient(string host, string username, params IPrivateKeySource[] keyFiles)
             : this(host, ConnectionInfo.DefaultPort, username, keyFiles)
         {
         }