diff --git a/src/Renci.SshNet/Common/Extensions.cs b/src/Renci.SshNet/Common/Extensions.cs
index 1d6ce3ca..ae390d60 100644
--- a/src/Renci.SshNet/Common/Extensions.cs
+++ b/src/Renci.SshNet/Common/Extensions.cs
@@ -93,23 +93,6 @@ namespace Renci.SshNet.Common
Debug.WriteLine(sb.ToString());
}
- ///
- /// Creates an instance of the specified type using that type's default constructor.
- ///
- /// The type to create.
- /// Type of the instance to create.
- /// A reference to the newly created object.
- internal static T CreateInstance(this Type type)
- where T : class
- {
- if (type is null)
- {
- return null;
- }
-
- return Activator.CreateInstance(type) as T;
- }
-
internal static void ValidatePort(this uint value, string argument)
{
if (value > IPEndPoint.MaxPort)
diff --git a/src/Renci.SshNet/ConnectionInfo.cs b/src/Renci.SshNet/ConnectionInfo.cs
index 721a4576..b4cb0fc8 100644
--- a/src/Renci.SshNet/ConnectionInfo.cs
+++ b/src/Renci.SshNet/ConnectionInfo.cs
@@ -7,6 +7,7 @@ using System.Text;
using Renci.SshNet.Abstractions;
using Renci.SshNet.Common;
+using Renci.SshNet.Compression;
using Renci.SshNet.Messages.Authentication;
using Renci.SshNet.Messages.Connection;
using Renci.SshNet.Security;
@@ -46,7 +47,7 @@ namespace Renci.SshNet
///
/// Gets supported key exchange algorithms for this connection.
///
- public IDictionary KeyExchangeAlgorithms { get; private set; }
+ public IDictionary> KeyExchangeAlgorithms { get; private set; }
///
/// Gets supported encryptions for this connection.
@@ -71,7 +72,7 @@ namespace Renci.SshNet
///
/// Gets supported compression algorithms for this connection.
///
- public IDictionary CompressionAlgorithms { get; private set; }
+ public IDictionary> CompressionAlgorithms { get; private set; }
///
/// Gets the supported channel requests for this connection.
@@ -337,19 +338,19 @@ namespace Renci.SshNet
MaxSessions = 10;
Encoding = Encoding.UTF8;
- KeyExchangeAlgorithms = new Dictionary
+ KeyExchangeAlgorithms = new Dictionary>
{
- { "curve25519-sha256", typeof(KeyExchangeECCurve25519) },
- { "curve25519-sha256@libssh.org", typeof(KeyExchangeECCurve25519) },
- { "ecdh-sha2-nistp256", typeof(KeyExchangeECDH256) },
- { "ecdh-sha2-nistp384", typeof(KeyExchangeECDH384) },
- { "ecdh-sha2-nistp521", typeof(KeyExchangeECDH521) },
- { "diffie-hellman-group-exchange-sha256", typeof(KeyExchangeDiffieHellmanGroupExchangeSha256) },
- { "diffie-hellman-group-exchange-sha1", typeof(KeyExchangeDiffieHellmanGroupExchangeSha1) },
- { "diffie-hellman-group16-sha512", typeof(KeyExchangeDiffieHellmanGroup16Sha512) },
- { "diffie-hellman-group14-sha256", typeof(KeyExchangeDiffieHellmanGroup14Sha256) },
- { "diffie-hellman-group14-sha1", typeof(KeyExchangeDiffieHellmanGroup14Sha1) },
- { "diffie-hellman-group1-sha1", typeof(KeyExchangeDiffieHellmanGroup1Sha1) },
+ { "curve25519-sha256", () => new KeyExchangeECCurve25519() },
+ { "curve25519-sha256@libssh.org", () => new KeyExchangeECCurve25519() },
+ { "ecdh-sha2-nistp256", () => new KeyExchangeECDH256() },
+ { "ecdh-sha2-nistp384", () => new KeyExchangeECDH384() },
+ { "ecdh-sha2-nistp521", () => new KeyExchangeECDH521() },
+ { "diffie-hellman-group-exchange-sha256", () => new KeyExchangeDiffieHellmanGroupExchangeSha256() },
+ { "diffie-hellman-group-exchange-sha1", () => new KeyExchangeDiffieHellmanGroupExchangeSha1() },
+ { "diffie-hellman-group16-sha512", () => new KeyExchangeDiffieHellmanGroup16Sha512() },
+ { "diffie-hellman-group14-sha256", () => new KeyExchangeDiffieHellmanGroup14Sha256() },
+ { "diffie-hellman-group14-sha1", () => new KeyExchangeDiffieHellmanGroup14Sha1() },
+ { "diffie-hellman-group1-sha1", () => new KeyExchangeDiffieHellmanGroup1Sha1() },
};
Encryptions = new Dictionary
@@ -402,7 +403,7 @@ namespace Renci.SshNet
{ "ssh-dss", data => new KeyHostAlgorithm("ssh-dss", new DsaKey(new SshKeyData(data))) },
};
- CompressionAlgorithms = new Dictionary
+ CompressionAlgorithms = new Dictionary>
{
{ "none", null },
};
diff --git a/src/Renci.SshNet/IServiceFactory.cs b/src/Renci.SshNet/IServiceFactory.cs
index 8b2c8650..f19110d7 100644
--- a/src/Renci.SshNet/IServiceFactory.cs
+++ b/src/Renci.SshNet/IServiceFactory.cs
@@ -73,7 +73,7 @@ namespace Renci.SshNet
/// Negotiates a key exchange algorithm, and creates a for the negotiated
/// algorithm.
///
- /// A of the key exchange algorithms supported by the client where the key is the name of the algorithm, and the value is the type implementing this algorithm.
+ /// A dictionary of the key exchange algorithms supported by the client where the key is the name of the algorithm, and the value is a factory returning this algorithm.
/// The names of the key exchange algorithms supported by the SSH server.
///
/// A that was negotiated between client and server.
@@ -81,7 +81,7 @@ namespace Renci.SshNet
/// is .
/// is .
/// No key exchange algorithm is supported by both client and server.
- IKeyExchange CreateKeyExchange(IDictionary clientAlgorithms, string[] serverAlgorithms);
+ IKeyExchange CreateKeyExchange(IDictionary> clientAlgorithms, string[] serverAlgorithms);
///
/// Creates an for the specified file and with the specified
diff --git a/src/Renci.SshNet/Renci.SshNet.csproj b/src/Renci.SshNet/Renci.SshNet.csproj
index adda89ad..91f2149e 100644
--- a/src/Renci.SshNet/Renci.SshNet.csproj
+++ b/src/Renci.SshNet/Renci.SshNet.csproj
@@ -5,11 +5,17 @@
net462;netstandard2.0;netstandard2.1;net6.0;net7.0;net8.0
+
+ true
+ true
+ true
+
+
$(DefineConstants);FEATURE_BINARY_SERIALIZATION;FEATURE_HASH_RIPEMD160_CREATE;FEATURE_HMAC_RIPEMD160
-
+
diff --git a/src/Renci.SshNet/Security/Cryptography/RsaDigitalSignature.cs b/src/Renci.SshNet/Security/Cryptography/RsaDigitalSignature.cs
index 00a4898f..63982d11 100644
--- a/src/Renci.SshNet/Security/Cryptography/RsaDigitalSignature.cs
+++ b/src/Renci.SshNet/Security/Cryptography/RsaDigitalSignature.cs
@@ -1,5 +1,6 @@
using System;
using System.Security.Cryptography;
+
using Renci.SshNet.Common;
using Renci.SshNet.Security.Cryptography.Ciphers;
@@ -10,7 +11,11 @@ namespace Renci.SshNet.Security.Cryptography
///
public class RsaDigitalSignature : CipherDigitalSignature, IDisposable
{
- private HashAlgorithm _hash;
+#if NET462
+ private readonly HashAlgorithm _hash;
+#else
+ private readonly IncrementalHash _hash;
+#endif
///
/// Initializes a new instance of the class with the SHA-1 hash algorithm.
@@ -29,8 +34,14 @@ namespace Renci.SshNet.Security.Cryptography
public RsaDigitalSignature(RsaKey rsaKey, HashAlgorithmName hashAlgorithmName)
: base(ObjectIdentifier.FromHashAlgorithmName(hashAlgorithmName), new RsaCipher(rsaKey))
{
+#if NET462
_hash = CryptoConfig.CreateFromName(hashAlgorithmName.Name) as HashAlgorithm
?? throw new ArgumentException($"Could not create {nameof(HashAlgorithm)} from `{hashAlgorithmName}`.", nameof(hashAlgorithmName));
+#else
+ // CryptoConfig.CreateFromName is a somewhat legacy API and is incompatible with trimming.
+ // Use IncrementalHash instead (which is also more modern and lighter-weight than HashAlgorithm).
+ _hash = IncrementalHash.CreateHash(hashAlgorithmName);
+#endif
}
///
@@ -42,13 +53,16 @@ namespace Renci.SshNet.Security.Cryptography
///
protected override byte[] Hash(byte[] input)
{
+#if NET462
return _hash.ComputeHash(input);
+#else
+ _hash.AppendData(input);
+ return _hash.GetHashAndReset();
+#endif
}
#region IDisposable Members
- private bool _isDisposed;
-
///
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
///
@@ -64,31 +78,7 @@ namespace Renci.SshNet.Security.Cryptography
/// to release both managed and unmanaged resources; to release only unmanaged resources.
protected virtual void Dispose(bool disposing)
{
- if (_isDisposed)
- {
- return;
- }
-
- if (disposing)
- {
- var hash = _hash;
- if (hash != null)
- {
- hash.Dispose();
- _hash = null;
- }
-
- _isDisposed = true;
- }
- }
-
- ///
- /// Releases unmanaged resources and performs other cleanup operations before the
- /// is reclaimed by garbage collection.
- ///
- ~RsaDigitalSignature()
- {
- Dispose(disposing: false);
+ _hash.Dispose();
}
#endregion
diff --git a/src/Renci.SshNet/Security/KeyExchange.cs b/src/Renci.SshNet/Security/KeyExchange.cs
index f01a4b11..f24dcafe 100644
--- a/src/Renci.SshNet/Security/KeyExchange.cs
+++ b/src/Renci.SshNet/Security/KeyExchange.cs
@@ -21,8 +21,8 @@ namespace Renci.SshNet.Security
private CipherInfo _serverCipherInfo;
private HashInfo _clientHashInfo;
private HashInfo _serverHashInfo;
- private Type _compressionType;
- private Type _decompressionType;
+ private Func _compressorFactory;
+ private Func _decompressorFactory;
///
/// Gets the session.
@@ -148,8 +148,8 @@ namespace Renci.SshNet.Security
_serverCipherInfo = session.ConnectionInfo.Encryptions[serverDecryptionAlgorithmName];
_clientHashInfo = session.ConnectionInfo.HmacAlgorithms[clientHmacAlgorithmName];
_serverHashInfo = session.ConnectionInfo.HmacAlgorithms[serverHmacAlgorithmName];
- _compressionType = session.ConnectionInfo.CompressionAlgorithms[compressionAlgorithmName];
- _decompressionType = session.ConnectionInfo.CompressionAlgorithms[decompressionAlgorithmName];
+ _compressorFactory = session.ConnectionInfo.CompressionAlgorithms[compressionAlgorithmName];
+ _decompressorFactory = session.ConnectionInfo.CompressionAlgorithms[decompressionAlgorithmName];
}
///
@@ -269,7 +269,7 @@ namespace Renci.SshNet.Security
///
public Compressor CreateCompressor()
{
- if (_compressionType is null)
+ if (_compressorFactory is null)
{
return null;
}
@@ -278,7 +278,7 @@ namespace Renci.SshNet.Security
Session.ToHex(Session.SessionId),
Session.ConnectionInfo.CurrentClientCompressionAlgorithm));
- var compressor = _compressionType.CreateInstance();
+ var compressor = _compressorFactory();
compressor.Init(Session);
@@ -293,7 +293,7 @@ namespace Renci.SshNet.Security
///
public Compressor CreateDecompressor()
{
- if (_decompressionType is null)
+ if (_decompressorFactory is null)
{
return null;
}
@@ -302,7 +302,7 @@ namespace Renci.SshNet.Security
Session.ToHex(Session.SessionId),
Session.ConnectionInfo.CurrentServerCompressionAlgorithm));
- var decompressor = _decompressionType.CreateInstance();
+ var decompressor = _decompressorFactory();
decompressor.Init(Session);
diff --git a/src/Renci.SshNet/ServiceFactory.cs b/src/Renci.SshNet/ServiceFactory.cs
index af30f11c..ece94505 100644
--- a/src/Renci.SshNet/ServiceFactory.cs
+++ b/src/Renci.SshNet/ServiceFactory.cs
@@ -79,19 +79,8 @@ namespace Renci.SshNet
return new PipeStream();
}
- ///
- /// Negotiates a key exchange algorithm, and creates a for the negotiated
- /// algorithm.
- ///
- /// A of the key exchange algorithms supported by the client where key is the name of the algorithm, and value is the type implementing this algorithm.
- /// The names of the key exchange algorithms supported by the SSH server.
- ///
- /// A that was negotiated between client and server.
- ///
- /// is .
- /// is .
- /// No key exchange algorithms are supported by both client and server.
- public IKeyExchange CreateKeyExchange(IDictionary clientAlgorithms, string[] serverAlgorithms)
+ ///
+ public IKeyExchange CreateKeyExchange(IDictionary> clientAlgorithms, string[] serverAlgorithms)
{
if (clientAlgorithms is null)
{
@@ -104,17 +93,17 @@ namespace Renci.SshNet
}
// find an algorithm that is supported by both client and server
- var keyExchangeAlgorithmType = (from c in clientAlgorithms
+ var keyExchangeAlgorithmFactory = (from c in clientAlgorithms
from s in serverAlgorithms
where s == c.Key
select c.Value).FirstOrDefault();
- if (keyExchangeAlgorithmType is null)
+ if (keyExchangeAlgorithmFactory is null)
{
throw new SshConnectionException("Failed to negotiate key exchange algorithm.", DisconnectReason.KeyExchangeFailed);
}
- return keyExchangeAlgorithmType.CreateInstance();
+ return keyExchangeAlgorithmFactory();
}
///