diff --git a/src/Renci.SshNet/IPrivateKeySource.cs b/src/Renci.SshNet/IPrivateKeySource.cs new file mode 100644 index 000000000..fc3405462 --- /dev/null +++ b/src/Renci.SshNet/IPrivateKeySource.cs @@ -0,0 +1,15 @@ +using Renci.SshNet.Security; + +namespace Renci.SshNet +{ + /// + /// Represents private key source interface. + /// + public interface IPrivateKeySource + { + /// + /// Gets the host key. + /// + HostAlgorithm HostKey { get; } + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/NetConfClient.cs b/src/Renci.SshNet/NetConfClient.cs index b1877c601..b7ec82ec2 100644 --- a/src/Renci.SshNet/NetConfClient.cs +++ b/src/Renci.SshNet/NetConfClient.cs @@ -103,7 +103,7 @@ public NetConfClient(string host, string username, string password) /// is invalid, -or- is null or contains only whitespace characters. /// is not within and . [SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope", Justification = "Disposed in Dispose(bool) method.")] - public NetConfClient(string host, int port, string username, params PrivateKeyFile[] keyFiles) + public NetConfClient(string host, int port, string username, params IPrivateKeySource[] keyFiles) : this(new PrivateKeyConnectionInfo(host, port, username, keyFiles), true) { } @@ -116,7 +116,7 @@ public NetConfClient(string host, int port, string username, params PrivateKeyFi /// Authentication private key file(s) . /// is null. /// is invalid, -or- is null or contains only whitespace characters. - public NetConfClient(string host, string username, params PrivateKeyFile[] keyFiles) + public NetConfClient(string host, string username, params IPrivateKeySource[] keyFiles) : this(host, ConnectionInfo.DefaultPort, username, keyFiles) { } @@ -163,7 +163,7 @@ internal NetConfClient(ConnectionInfo connectionInfo, bool ownsConnectionInfo, I /// /// The NetConf server capabilities. /// - public XmlDocument ServerCapabilities + public XmlDocument ServerCapabilities { get { return _netConfSession.ServerCapabilities; } } @@ -277,4 +277,4 @@ private INetConfSession CreateAndConnectNetConfSession() } } } -} +} \ No newline at end of file diff --git a/src/Renci.SshNet/PrivateKeyAuthenticationMethod.cs b/src/Renci.SshNet/PrivateKeyAuthenticationMethod.cs index 93ebbe19d..43d80b506 100644 --- a/src/Renci.SshNet/PrivateKeyAuthenticationMethod.cs +++ b/src/Renci.SshNet/PrivateKeyAuthenticationMethod.cs @@ -28,7 +28,7 @@ public override string Name /// /// Gets the key files used for authentication. /// - public ICollection KeyFiles { get; private set; } + public ICollection KeyFiles { get; private set; } /// /// Initializes a new instance of the class. @@ -36,13 +36,13 @@ public override string Name /// The username. /// The key files. /// is whitespace or null. - public PrivateKeyAuthenticationMethod(string username, params PrivateKeyFile[] keyFiles) + public PrivateKeyAuthenticationMethod(string username, params IPrivateKeySource[] keyFiles) : base(username) { if (keyFiles == null) throw new ArgumentNullException("keyFiles"); - KeyFiles = new Collection(keyFiles); + KeyFiles = new Collection(keyFiles); } /// @@ -250,4 +250,4 @@ protected override void SaveData() } } } -} +} \ No newline at end of file diff --git a/src/Renci.SshNet/PrivateKeyConnectionInfo.cs b/src/Renci.SshNet/PrivateKeyConnectionInfo.cs index 7f0c4f658..1f717631b 100644 --- a/src/Renci.SshNet/PrivateKeyConnectionInfo.cs +++ b/src/Renci.SshNet/PrivateKeyConnectionInfo.cs @@ -15,7 +15,7 @@ public class PrivateKeyConnectionInfo : ConnectionInfo, IDisposable /// /// Gets the key files used for authentication. /// - public ICollection KeyFiles { get; private set; } + public ICollection KeyFiles { get; private set; } /// /// Initializes a new instance of the class. @@ -40,7 +40,7 @@ public PrivateKeyConnectionInfo(string host, string username, params PrivateKeyF /// Connection port. /// Connection username. /// Connection key files. - public PrivateKeyConnectionInfo(string host, int port, string username, params PrivateKeyFile[] 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) { } @@ -55,7 +55,7 @@ public PrivateKeyConnectionInfo(string host, int port, string username, params P /// The proxy host. /// The proxy port. /// The key files. - public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, params PrivateKeyFile[] 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) { } @@ -71,7 +71,7 @@ public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTyp /// The proxy port. /// The proxy username. /// The key files. - public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, params PrivateKeyFile[] 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) { } @@ -85,7 +85,7 @@ public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTyp /// The proxy host. /// The proxy port. /// The key files. - public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, params PrivateKeyFile[] 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) { } @@ -100,7 +100,7 @@ public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyTy /// The proxy port. /// The proxy username. /// The key files. - public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, params PrivateKeyFile[] 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) { } @@ -116,7 +116,7 @@ public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyTy /// The proxy username. /// The proxy password. /// The key files. - public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, string proxyPassword, params PrivateKeyFile[] 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) { } @@ -133,10 +133,10 @@ public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyTy /// The proxy username. /// The proxy password. /// The key files. - public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, string proxyPassword, params PrivateKeyFile[] 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(keyFiles); + KeyFiles = new Collection(keyFiles); } #region IDisposable Members @@ -194,4 +194,4 @@ protected virtual void Dispose(bool disposing) #endregion } -} +} \ No newline at end of file diff --git a/src/Renci.SshNet/PrivateKeyFile.cs b/src/Renci.SshNet/PrivateKeyFile.cs index 1424134f6..f29b3e958 100644 --- a/src/Renci.SshNet/PrivateKeyFile.cs +++ b/src/Renci.SshNet/PrivateKeyFile.cs @@ -63,7 +63,7 @@ namespace Renci.SshNet /// /// /// - public class PrivateKeyFile : IDisposable + public class PrivateKeyFile : IPrivateKeySource, IDisposable { private static readonly Regex PrivateKeyRegex = new Regex(@"^-+ *BEGIN (?\w+( \w+)*) PRIVATE KEY *-+\r?\n((Proc-Type: 4,ENCRYPTED\r?\nDEK-Info: (?[A-Z0-9-]+),(?[A-F0-9]+)\r?\n\r?\n)|(Comment: ""?[^\r\n]*""?\r?\n))?(?([a-zA-Z0-9/+=]{1,80}\r?\n)+)-+ *END \k PRIVATE KEY *-+", #if FEATURE_REGEX_COMPILE @@ -79,6 +79,15 @@ public class PrivateKeyFile : IDisposable /// public HostAlgorithm HostKey { get; private set; } + /// + /// Initializes a new instance of the class. + /// + /// The key. + public PrivateKeyFile(Key key) + { + HostKey = new KeyHostAlgorithm(key.ToString(), key); + } + /// /// Initializes a new instance of the class. /// @@ -262,7 +271,7 @@ private void Open(Stream privateKey, string passPhrase) if (decryptedLength > blobSize - 4) throw new SshException("Invalid passphrase."); - + if (keyType == "if-modn{sign{rsa-pkcs1-sha1},encrypt{rsa-pkcs1v2-oaep}}") { var exponent = reader.ReadBigIntWithBits();//e @@ -515,8 +524,7 @@ private Key ParseOpenSshV1Key(byte[] keyFileData, string passPhrase) throw new SshException("OpenSSH key type '" + keyType + "' is not supported."); } - //comment, we don't need this but we could log it, not sure if necessary - var comment = privateKeyReader.ReadString(Encoding.UTF8); + parsedKey.Comment = privateKeyReader.ReadString(Encoding.UTF8); //The list of privatekey/comment pairs is padded with the bytes 1, 2, 3, ... //until the total length is a multiple of the cipher block size. @@ -642,4 +650,4 @@ protected override void SaveData() } } } -} +} \ No newline at end of file diff --git a/src/Renci.SshNet/ScpClient.cs b/src/Renci.SshNet/ScpClient.cs index 8a252cac9..d8ad55692 100644 --- a/src/Renci.SshNet/ScpClient.cs +++ b/src/Renci.SshNet/ScpClient.cs @@ -142,7 +142,7 @@ public ScpClient(string host, string username, string password) /// is invalid, -or- is null or contains only whitespace characters. /// is not within and . [SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope", Justification = "Disposed in Dispose(bool) method.")] - public ScpClient(string host, int port, string username, params PrivateKeyFile[] keyFiles) + public ScpClient(string host, int port, string username, params IPrivateKeySource[] keyFiles) : this(new PrivateKeyConnectionInfo(host, port, username, keyFiles), true) { } @@ -155,7 +155,7 @@ public ScpClient(string host, int port, string username, params PrivateKeyFile[] /// Authentication private key file(s) . /// is null. /// is invalid, -or- is null or contains only whitespace characters. - public ScpClient(string host, string username, params PrivateKeyFile[] keyFiles) + public ScpClient(string host, string username, params IPrivateKeySource[] keyFiles) : this(host, ConnectionInfo.DefaultPort, username, keyFiles) { } @@ -466,4 +466,4 @@ private static SshException SecureExecutionRequestRejectedException() throw new SshException("Secure copy execution request was rejected by the server. Please consult the server logs."); } } -} +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/Cryptography/ED25519Key.cs b/src/Renci.SshNet/Security/Cryptography/ED25519Key.cs index deb4b1181..15f1cb019 100644 --- a/src/Renci.SshNet/Security/Cryptography/ED25519Key.cs +++ b/src/Renci.SshNet/Security/Cryptography/ED25519Key.cs @@ -99,6 +99,15 @@ public ED25519Key() { } + /// + /// Initializes a new instance of the class. + /// + /// pk data. + public ED25519Key(byte[] pk) + { + publicKey = pk.TrimLeadingZeros().Pad(Ed25519.PublicKeySizeInBytes); + } + /// /// Initializes a new instance of the class. /// diff --git a/src/Renci.SshNet/Security/Cryptography/EcdsaDigitalSignature.cs b/src/Renci.SshNet/Security/Cryptography/EcdsaDigitalSignature.cs index 38d60966e..920614672 100644 --- a/src/Renci.SshNet/Security/Cryptography/EcdsaDigitalSignature.cs +++ b/src/Renci.SshNet/Security/Cryptography/EcdsaDigitalSignature.cs @@ -39,12 +39,12 @@ public override bool Verify(byte[] input, byte[] signature) // for 521 sig_size is 132 var sig_size = _key.KeyLength == 521 ? 132 : _key.KeyLength / 4; var ssh_data = new SshDataSignature(signature, sig_size); -#if NETSTANDARD2_0 - return _key.Ecdsa.VerifyData(input, ssh_data.Signature, _key.HashAlgorithm); -#else +#if NETFRAMEWORK var ecdsa = (ECDsaCng)_key.Ecdsa; ecdsa.HashAlgorithm = _key.HashAlgorithm; return ecdsa.VerifyData(input, ssh_data.Signature); +#else + return _key.Ecdsa.VerifyData(input, ssh_data.Signature, _key.HashAlgorithm); #endif } @@ -57,12 +57,12 @@ public override bool Verify(byte[] input, byte[] signature) /// public override byte[] Sign(byte[] input) { -#if NETSTANDARD2_0 - var signed = _key.Ecdsa.SignData(input, _key.HashAlgorithm); -#else +#if NETFRAMEWORK var ecdsa = (ECDsaCng)_key.Ecdsa; ecdsa.HashAlgorithm = _key.HashAlgorithm; var signed = ecdsa.SignData(input); +#else + var signed = _key.Ecdsa.SignData(input, _key.HashAlgorithm); #endif var ssh_data = new SshDataSignature(signed.Length); ssh_data.Signature = signed; diff --git a/src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs b/src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs index 58861f020..46f1dcc65 100644 --- a/src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs +++ b/src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs @@ -18,7 +18,7 @@ public class EcdsaKey : Key, IDisposable internal const string ECDSA_P384_OID_VALUE = "1.3.132.0.34"; // Also called nistP384 or secP384r1 internal const string ECDSA_P521_OID_VALUE = "1.3.132.0.35"; // Also called nistP521or secP521r1 -#if !NETSTANDARD2_0 +#if NETFRAMEWORK internal enum KeyBlobMagicNumber : int { BCRYPT_ECDSA_PUBLIC_P256_MAGIC = 0x31534345, @@ -57,45 +57,45 @@ public override string ToString() return string.Format("ecdsa-sha2-nistp{0}", KeyLength); } -#if NETSTANDARD2_0 +#if NETFRAMEWORK /// /// Gets the HashAlgorithm to use /// - public HashAlgorithmName HashAlgorithm + public CngAlgorithm HashAlgorithm { get { - switch (KeyLength) + switch (Ecdsa.KeySize) { case 256: - return HashAlgorithmName.SHA256; + return CngAlgorithm.Sha256; case 384: - return HashAlgorithmName.SHA384; + return CngAlgorithm.Sha384; case 521: - return HashAlgorithmName.SHA512; + return CngAlgorithm.Sha512; + default: + throw new SshException("Unknown KeySize: " + Ecdsa.KeySize); } - return HashAlgorithmName.SHA256; } } #else /// /// Gets the HashAlgorithm to use /// - public CngAlgorithm HashAlgorithm + public HashAlgorithmName HashAlgorithm { get { - switch (Ecdsa.KeySize) + switch (KeyLength) { case 256: - return CngAlgorithm.Sha256; + return HashAlgorithmName.SHA256; case 384: - return CngAlgorithm.Sha384; + return HashAlgorithmName.SHA384; case 521: - return CngAlgorithm.Sha512; - default: - throw new SshException("Unknown KeySize: " + Ecdsa.KeySize); + return HashAlgorithmName.SHA512; } + return HashAlgorithmName.SHA256; } } #endif @@ -144,28 +144,7 @@ public override BigInteger[] Public byte[] curve; byte[] qx; byte[] qy; -#if NETSTANDARD2_0 - var parameter = Ecdsa.ExportParameters(false); - qx = parameter.Q.X; - qy = parameter.Q.Y; - switch (parameter.Curve.Oid.FriendlyName) - { - case "ECDSA_P256": - case "nistP256": - curve = Encoding.ASCII.GetBytes("nistp256"); - break; - case "ECDSA_P384": - case "nistP384": - curve = Encoding.ASCII.GetBytes("nistp384"); - break; - case "ECDSA_P521": - case "nistP521": - curve = Encoding.ASCII.GetBytes("nistp521"); - break; - default: - throw new SshException("Unexpected Curve Name: " + parameter.Curve.Oid.FriendlyName); - } -#else +#if NETFRAMEWORK var blob = key.Export(CngKeyBlobFormat.EccPublicBlob); KeyBlobMagicNumber magic; @@ -191,6 +170,27 @@ public override BigInteger[] Public default: throw new SshException("Unexpected Curve Magic: " + magic); } +#else + var parameter = Ecdsa.ExportParameters(false); + qx = parameter.Q.X; + qy = parameter.Q.Y; + switch (parameter.Curve.Oid.FriendlyName) + { + case "ECDSA_P256": + case "nistP256": + curve = Encoding.ASCII.GetBytes("nistp256"); + break; + case "ECDSA_P384": + case "nistP384": + curve = Encoding.ASCII.GetBytes("nistp384"); + break; + case "ECDSA_P521": + case "nistP521": + curve = Encoding.ASCII.GetBytes("nistp521"); + break; + default: + throw new SshException("Unexpected Curve Name: " + parameter.Curve.Oid.FriendlyName); + } #endif // Make ECPoint from x and y // Prepend 04 (uncompressed format) + qx-bytes + qy-bytes @@ -212,6 +212,11 @@ public override BigInteger[] Public } } + /// + /// Gets the PrivateKey Bytes + /// + public byte[] PrivateKey { get; private set; } + /// /// Gets ECDsa Object /// @@ -278,29 +283,7 @@ public EcdsaKey(byte[] data) private void Import(string curve_oid, byte[] publickey, byte[] privatekey) { -#if NETSTANDARD2_0 - var curve = ECCurve.CreateFromValue(curve_oid); - var parameter = new ECParameters - { - Curve = curve - }; - - // ECPoint as BigInteger(2) - var cord_size = (publickey.Length - 1) / 2; - var qx = new byte[cord_size]; - Buffer.BlockCopy(publickey, 1, qx, 0, qx.Length); - - var qy = new byte[cord_size]; - Buffer.BlockCopy(publickey, cord_size + 1, qy, 0, qy.Length); - - parameter.Q.X = qx; - parameter.Q.Y = qy; - - if (privatekey != null) - parameter.D = privatekey.TrimLeadingZeros().Pad(cord_size); - - Ecdsa = ECDsa.Create(parameter); -#else +#if NETFRAMEWORK var curve_magic = KeyBlobMagicNumber.BCRYPT_ECDH_PRIVATE_GENERIC_MAGIC; switch (GetCurveName(curve_oid)) { @@ -335,7 +318,10 @@ private void Import(string curve_oid, byte[] publickey, byte[] privatekey) Buffer.BlockCopy(publickey, cord_size + 1, qy, 0, qy.Length); if (privatekey != null) + { privatekey = privatekey.Pad(cord_size); + PrivateKey = privatekey; + } int headerSize = Marshal.SizeOf(typeof(BCRYPT_ECCKEY_BLOB)); int blobSize = headerSize + qx.Length + qy.Length; @@ -355,6 +341,31 @@ private void Import(string curve_oid, byte[] publickey, byte[] privatekey) key = CngKey.Import(blob, privatekey == null ? CngKeyBlobFormat.EccPublicBlob : CngKeyBlobFormat.EccPrivateBlob); Ecdsa = new ECDsaCng(key); +#else + var curve = ECCurve.CreateFromValue(curve_oid); + var parameter = new ECParameters + { + Curve = curve + }; + + // ECPoint as BigInteger(2) + var cord_size = (publickey.Length - 1) / 2; + var qx = new byte[cord_size]; + Buffer.BlockCopy(publickey, 1, qx, 0, qx.Length); + + var qy = new byte[cord_size]; + Buffer.BlockCopy(publickey, cord_size + 1, qy, 0, qy.Length); + + parameter.Q.X = qx; + parameter.Q.Y = qy; + + if (privatekey != null) + { + parameter.D = privatekey.TrimLeadingZeros().Pad(cord_size); + PrivateKey = parameter.D; + } + + Ecdsa = ECDsa.Create(parameter); #endif } diff --git a/src/Renci.SshNet/Security/Cryptography/Key.cs b/src/Renci.SshNet/Security/Cryptography/Key.cs index c668a66c3..61c5150c2 100644 --- a/src/Renci.SshNet/Security/Cryptography/Key.cs +++ b/src/Renci.SshNet/Security/Cryptography/Key.cs @@ -36,6 +36,11 @@ public abstract class Key /// public abstract int KeyLength { get; } + /// + /// Gets the Key Comment + /// + public string Comment { get; set; } + /// /// Initializes a new instance of the class. /// diff --git a/src/Renci.SshNet/SftpClient.cs b/src/Renci.SshNet/SftpClient.cs index 4ac9d5543..d33e21816 100644 --- a/src/Renci.SshNet/SftpClient.cs +++ b/src/Renci.SshNet/SftpClient.cs @@ -208,7 +208,7 @@ public SftpClient(string host, string username, string password) /// is invalid. -or- is nunullll or contains only whitespace characters. /// is not within and . [SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope", Justification = "Disposed in Dispose(bool) method.")] - public SftpClient(string host, int port, string username, params PrivateKeyFile[] keyFiles) + public SftpClient(string host, int port, string username, params IPrivateKeySource[] keyFiles) : this(new PrivateKeyConnectionInfo(host, port, username, keyFiles), true) { } @@ -221,7 +221,7 @@ public SftpClient(string host, int port, string username, params PrivateKeyFile[ /// Authentication private key file(s) . /// is null. /// is invalid. -or- is null or contains only whitespace characters. - public SftpClient(string host, string username, params PrivateKeyFile[] keyFiles) + public SftpClient(string host, string username, params IPrivateKeySource[] keyFiles) : this(host, ConnectionInfo.DefaultPort, username, keyFiles) { } @@ -712,13 +712,13 @@ public bool Exists(string path) // using SSH_FXP_REALPATH is not an alternative as the SFTP specification has not always // been clear on how the server should respond when the specified path is not present on // the server: - // + // // SSH 1 to 4: // No mention of how the server should respond if the path is not present on the server. // // SSH 5: // The server SHOULD fail the request if the path is not present on the server. - // + // // SSH 6: // Draft 06: The server SHOULD fail the request if the path is not present on the server. // Draft 07 to 13: The server MUST NOT fail the request if the path does not exist. @@ -747,7 +747,7 @@ public bool Exists(string path) /// is null or contains only whitespace characters. /// Client is not connected. /// Permission to perform the operation was denied by the remote host. -or- A SSH command was denied by the server. - /// was not found on the remote host./// + /// was not found on the remote host./// /// A SSH error where is the message from the remote host. /// The method was called after the client was disposed. /// @@ -2400,4 +2400,4 @@ private ISftpSession CreateAndConnectToSftpSession() } } } -} +} \ No newline at end of file diff --git a/src/Renci.SshNet/SshClient.cs b/src/Renci.SshNet/SshClient.cs index 49c9ff84b..881a173d4 100644 --- a/src/Renci.SshNet/SshClient.cs +++ b/src/Renci.SshNet/SshClient.cs @@ -104,7 +104,7 @@ public SshClient(string host, string username, string password) /// is invalid, -or- is null or contains only whitespace characters. /// is not within and . [SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope", Justification = "Disposed in Dispose(bool) method.")] - public SshClient(string host, int port, string username, params PrivateKeyFile[] keyFiles) + public SshClient(string host, int port, string username, params IPrivateKeySource[] keyFiles) : this(new PrivateKeyConnectionInfo(host, port, username, keyFiles), true) { } @@ -121,7 +121,7 @@ public SshClient(string host, int port, string username, params PrivateKeyFile[] /// /// is null. /// is invalid, -or- is null or contains only whitespace characters. - public SshClient(string host, string username, params PrivateKeyFile[] keyFiles) + public SshClient(string host, string username, params IPrivateKeySource[] keyFiles) : this(host, ConnectionInfo.DefaultPort, username, keyFiles) { } @@ -507,4 +507,4 @@ private void EnsureSessionIsOpen() throw new SshConnectionException("Client not connected."); } } -} +} \ No newline at end of file