mirror of
https://github.com/sshnet/SSH.NET.git
synced 2026-09-10 09:15:47 +00:00
Enable trim analysis and fix warnings (#1216)
* Enable trim analysis and fix warnings * Use EnableTrimAnalyzer instead of IsTrimmable I don't know how IsTrimmable works with references (i.e. to SshNet.Security.Cryptography) * Add additional aot/trimming related analyzers * Initialise the hash instance in the constructor --------- Co-authored-by: Wojciech Nagórski <wojtpl2@gmail.com>
This commit is contained in:
@@ -93,23 +93,6 @@ namespace Renci.SshNet.Common
|
||||
Debug.WriteLine(sb.ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of the specified type using that type's default constructor.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type to create.</typeparam>
|
||||
/// <param name="type">Type of the instance to create.</param>
|
||||
/// <returns>A reference to the newly created object.</returns>
|
||||
internal static T CreateInstance<T>(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)
|
||||
|
||||
@@ -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
|
||||
/// <summary>
|
||||
/// Gets supported key exchange algorithms for this connection.
|
||||
/// </summary>
|
||||
public IDictionary<string, Type> KeyExchangeAlgorithms { get; private set; }
|
||||
public IDictionary<string, Func<IKeyExchange>> KeyExchangeAlgorithms { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets supported encryptions for this connection.
|
||||
@@ -71,7 +72,7 @@ namespace Renci.SshNet
|
||||
/// <summary>
|
||||
/// Gets supported compression algorithms for this connection.
|
||||
/// </summary>
|
||||
public IDictionary<string, Type> CompressionAlgorithms { get; private set; }
|
||||
public IDictionary<string, Func<Compressor>> CompressionAlgorithms { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the supported channel requests for this connection.
|
||||
@@ -337,19 +338,19 @@ namespace Renci.SshNet
|
||||
MaxSessions = 10;
|
||||
Encoding = Encoding.UTF8;
|
||||
|
||||
KeyExchangeAlgorithms = new Dictionary<string, Type>
|
||||
KeyExchangeAlgorithms = new Dictionary<string, Func<IKeyExchange>>
|
||||
{
|
||||
{ "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<string, CipherInfo>
|
||||
@@ -402,7 +403,7 @@ namespace Renci.SshNet
|
||||
{ "ssh-dss", data => new KeyHostAlgorithm("ssh-dss", new DsaKey(new SshKeyData(data))) },
|
||||
};
|
||||
|
||||
CompressionAlgorithms = new Dictionary<string, Type>
|
||||
CompressionAlgorithms = new Dictionary<string, Func<Compressor>>
|
||||
{
|
||||
{ "none", null },
|
||||
};
|
||||
|
||||
@@ -73,7 +73,7 @@ namespace Renci.SshNet
|
||||
/// Negotiates a key exchange algorithm, and creates a <see cref="IKeyExchange" /> for the negotiated
|
||||
/// algorithm.
|
||||
/// </summary>
|
||||
/// <param name="clientAlgorithms">A <see cref="IDictionary{String, Type}"/> 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.</param>
|
||||
/// <param name="clientAlgorithms">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.</param>
|
||||
/// <param name="serverAlgorithms">The names of the key exchange algorithms supported by the SSH server.</param>
|
||||
/// <returns>
|
||||
/// A <see cref="IKeyExchange"/> that was negotiated between client and server.
|
||||
@@ -81,7 +81,7 @@ namespace Renci.SshNet
|
||||
/// <exception cref="ArgumentNullException"><paramref name="clientAlgorithms"/> is <see langword="null"/>.</exception>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="serverAlgorithms"/> is <see langword="null"/>.</exception>
|
||||
/// <exception cref="SshConnectionException">No key exchange algorithm is supported by both client and server.</exception>
|
||||
IKeyExchange CreateKeyExchange(IDictionary<string, Type> clientAlgorithms, string[] serverAlgorithms);
|
||||
IKeyExchange CreateKeyExchange(IDictionary<string, Func<IKeyExchange>> clientAlgorithms, string[] serverAlgorithms);
|
||||
|
||||
/// <summary>
|
||||
/// Creates an <see cref="ISftpFileReader"/> for the specified file and with the specified
|
||||
|
||||
@@ -5,11 +5,17 @@
|
||||
<TargetFrameworks>net462;netstandard2.0;netstandard2.1;net6.0;net7.0;net8.0</TargetFrameworks>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" $([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net6.0')) ">
|
||||
<EnableTrimAnalyzer>true</EnableTrimAnalyzer>
|
||||
<EnableSingleFileAnalyzer>true</EnableSingleFileAnalyzer>
|
||||
<EnableAotAnalyzer>true</EnableAotAnalyzer>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(TargetFramework)' == 'net462' ">
|
||||
<DefineConstants>$(DefineConstants);FEATURE_BINARY_SERIALIZATION;FEATURE_HASH_RIPEMD160_CREATE;FEATURE_HMAC_RIPEMD160</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' or '$(TargetFramework)' == 'netstandard2.1' or '$(TargetFramework)' == 'net6.0' or '$(TargetFramework)' == 'net7.0' or '$(TargetFramework)' == 'net8.0' ">
|
||||
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' or $([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'netstandard2.1')) ">
|
||||
<PackageReference Include="SshNet.Security.Cryptography" Version="[1.3.0]" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -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
|
||||
/// </summary>
|
||||
public class RsaDigitalSignature : CipherDigitalSignature, IDisposable
|
||||
{
|
||||
private HashAlgorithm _hash;
|
||||
#if NET462
|
||||
private readonly HashAlgorithm _hash;
|
||||
#else
|
||||
private readonly IncrementalHash _hash;
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RsaDigitalSignature"/> 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
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -42,13 +53,16 @@ namespace Renci.SshNet.Security.Cryptography
|
||||
/// </returns>
|
||||
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;
|
||||
|
||||
/// <summary>
|
||||
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
|
||||
/// </summary>
|
||||
@@ -64,31 +78,7 @@ namespace Renci.SshNet.Security.Cryptography
|
||||
/// <param name="disposing"><see langword="true"/> to release both managed and unmanaged resources; <see langword="false"/> to release only unmanaged resources.</param>
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (_isDisposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
var hash = _hash;
|
||||
if (hash != null)
|
||||
{
|
||||
hash.Dispose();
|
||||
_hash = null;
|
||||
}
|
||||
|
||||
_isDisposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases unmanaged resources and performs other cleanup operations before the
|
||||
/// <see cref="RsaDigitalSignature"/> is reclaimed by garbage collection.
|
||||
/// </summary>
|
||||
~RsaDigitalSignature()
|
||||
{
|
||||
Dispose(disposing: false);
|
||||
_hash.Dispose();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -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<Compressor> _compressorFactory;
|
||||
private Func<Compressor> _decompressorFactory;
|
||||
|
||||
/// <summary>
|
||||
/// 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];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -269,7 +269,7 @@ namespace Renci.SshNet.Security
|
||||
/// </returns>
|
||||
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<Compressor>();
|
||||
var compressor = _compressorFactory();
|
||||
|
||||
compressor.Init(Session);
|
||||
|
||||
@@ -293,7 +293,7 @@ namespace Renci.SshNet.Security
|
||||
/// </returns>
|
||||
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<Compressor>();
|
||||
var decompressor = _decompressorFactory();
|
||||
|
||||
decompressor.Init(Session);
|
||||
|
||||
|
||||
@@ -79,19 +79,8 @@ namespace Renci.SshNet
|
||||
return new PipeStream();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Negotiates a key exchange algorithm, and creates a <see cref="IKeyExchange" /> for the negotiated
|
||||
/// algorithm.
|
||||
/// </summary>
|
||||
/// <param name="clientAlgorithms">A <see cref="IDictionary{String, Type}"/> 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.</param>
|
||||
/// <param name="serverAlgorithms">The names of the key exchange algorithms supported by the SSH server.</param>
|
||||
/// <returns>
|
||||
/// A <see cref="IKeyExchange"/> that was negotiated between client and server.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="clientAlgorithms"/> is <see langword="null"/>.</exception>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="serverAlgorithms"/> is <see langword="null"/>.</exception>
|
||||
/// <exception cref="SshConnectionException">No key exchange algorithms are supported by both client and server.</exception>
|
||||
public IKeyExchange CreateKeyExchange(IDictionary<string, Type> clientAlgorithms, string[] serverAlgorithms)
|
||||
/// <inheritdoc/>
|
||||
public IKeyExchange CreateKeyExchange(IDictionary<string, Func<IKeyExchange>> 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<IKeyExchange>();
|
||||
return keyExchangeAlgorithmFactory();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
Reference in New Issue
Block a user