Skip to content

Commit 64b428f

Browse files
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 <[email protected]>
1 parent 0a7ef46 commit 64b428f

File tree

7 files changed

+56
-87
lines changed

7 files changed

+56
-87
lines changed

src/Renci.SshNet/Common/Extensions.cs

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -93,23 +93,6 @@ internal static void DebugPrint(this IEnumerable<byte> bytes)
9393
Debug.WriteLine(sb.ToString());
9494
}
9595

96-
/// <summary>
97-
/// Creates an instance of the specified type using that type's default constructor.
98-
/// </summary>
99-
/// <typeparam name="T">The type to create.</typeparam>
100-
/// <param name="type">Type of the instance to create.</param>
101-
/// <returns>A reference to the newly created object.</returns>
102-
internal static T CreateInstance<T>(this Type type)
103-
where T : class
104-
{
105-
if (type is null)
106-
{
107-
return null;
108-
}
109-
110-
return Activator.CreateInstance(type) as T;
111-
}
112-
11396
internal static void ValidatePort(this uint value, string argument)
11497
{
11598
if (value > IPEndPoint.MaxPort)

src/Renci.SshNet/ConnectionInfo.cs

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
using Renci.SshNet.Abstractions;
99
using Renci.SshNet.Common;
10+
using Renci.SshNet.Compression;
1011
using Renci.SshNet.Messages.Authentication;
1112
using Renci.SshNet.Messages.Connection;
1213
using Renci.SshNet.Security;
@@ -46,7 +47,7 @@ public class ConnectionInfo : IConnectionInfoInternal
4647
/// <summary>
4748
/// Gets supported key exchange algorithms for this connection.
4849
/// </summary>
49-
public IDictionary<string, Type> KeyExchangeAlgorithms { get; private set; }
50+
public IDictionary<string, Func<IKeyExchange>> KeyExchangeAlgorithms { get; private set; }
5051

5152
/// <summary>
5253
/// Gets supported encryptions for this connection.
@@ -71,7 +72,7 @@ public class ConnectionInfo : IConnectionInfoInternal
7172
/// <summary>
7273
/// Gets supported compression algorithms for this connection.
7374
/// </summary>
74-
public IDictionary<string, Type> CompressionAlgorithms { get; private set; }
75+
public IDictionary<string, Func<Compressor>> CompressionAlgorithms { get; private set; }
7576

7677
/// <summary>
7778
/// Gets the supported channel requests for this connection.
@@ -337,19 +338,19 @@ public ConnectionInfo(string host, int port, string username, ProxyTypes proxyTy
337338
MaxSessions = 10;
338339
Encoding = Encoding.UTF8;
339340

340-
KeyExchangeAlgorithms = new Dictionary<string, Type>
341+
KeyExchangeAlgorithms = new Dictionary<string, Func<IKeyExchange>>
341342
{
342-
{ "curve25519-sha256", typeof(KeyExchangeECCurve25519) },
343-
{ "[email protected]", typeof(KeyExchangeECCurve25519) },
344-
{ "ecdh-sha2-nistp256", typeof(KeyExchangeECDH256) },
345-
{ "ecdh-sha2-nistp384", typeof(KeyExchangeECDH384) },
346-
{ "ecdh-sha2-nistp521", typeof(KeyExchangeECDH521) },
347-
{ "diffie-hellman-group-exchange-sha256", typeof(KeyExchangeDiffieHellmanGroupExchangeSha256) },
348-
{ "diffie-hellman-group-exchange-sha1", typeof(KeyExchangeDiffieHellmanGroupExchangeSha1) },
349-
{ "diffie-hellman-group16-sha512", typeof(KeyExchangeDiffieHellmanGroup16Sha512) },
350-
{ "diffie-hellman-group14-sha256", typeof(KeyExchangeDiffieHellmanGroup14Sha256) },
351-
{ "diffie-hellman-group14-sha1", typeof(KeyExchangeDiffieHellmanGroup14Sha1) },
352-
{ "diffie-hellman-group1-sha1", typeof(KeyExchangeDiffieHellmanGroup1Sha1) },
343+
{ "curve25519-sha256", () => new KeyExchangeECCurve25519() },
344+
{ "[email protected]", () => new KeyExchangeECCurve25519() },
345+
{ "ecdh-sha2-nistp256", () => new KeyExchangeECDH256() },
346+
{ "ecdh-sha2-nistp384", () => new KeyExchangeECDH384() },
347+
{ "ecdh-sha2-nistp521", () => new KeyExchangeECDH521() },
348+
{ "diffie-hellman-group-exchange-sha256", () => new KeyExchangeDiffieHellmanGroupExchangeSha256() },
349+
{ "diffie-hellman-group-exchange-sha1", () => new KeyExchangeDiffieHellmanGroupExchangeSha1() },
350+
{ "diffie-hellman-group16-sha512", () => new KeyExchangeDiffieHellmanGroup16Sha512() },
351+
{ "diffie-hellman-group14-sha256", () => new KeyExchangeDiffieHellmanGroup14Sha256() },
352+
{ "diffie-hellman-group14-sha1", () => new KeyExchangeDiffieHellmanGroup14Sha1() },
353+
{ "diffie-hellman-group1-sha1", () => new KeyExchangeDiffieHellmanGroup1Sha1() },
353354
};
354355

355356
Encryptions = new Dictionary<string, CipherInfo>
@@ -402,7 +403,7 @@ public ConnectionInfo(string host, int port, string username, ProxyTypes proxyTy
402403
{ "ssh-dss", data => new KeyHostAlgorithm("ssh-dss", new DsaKey(new SshKeyData(data))) },
403404
};
404405

405-
CompressionAlgorithms = new Dictionary<string, Type>
406+
CompressionAlgorithms = new Dictionary<string, Func<Compressor>>
406407
{
407408
{ "none", null },
408409
};

src/Renci.SshNet/IServiceFactory.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,15 +73,15 @@ internal partial interface IServiceFactory
7373
/// Negotiates a key exchange algorithm, and creates a <see cref="IKeyExchange" /> for the negotiated
7474
/// algorithm.
7575
/// </summary>
76-
/// <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>
76+
/// <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>
7777
/// <param name="serverAlgorithms">The names of the key exchange algorithms supported by the SSH server.</param>
7878
/// <returns>
7979
/// A <see cref="IKeyExchange"/> that was negotiated between client and server.
8080
/// </returns>
8181
/// <exception cref="ArgumentNullException"><paramref name="clientAlgorithms"/> is <see langword="null"/>.</exception>
8282
/// <exception cref="ArgumentNullException"><paramref name="serverAlgorithms"/> is <see langword="null"/>.</exception>
8383
/// <exception cref="SshConnectionException">No key exchange algorithm is supported by both client and server.</exception>
84-
IKeyExchange CreateKeyExchange(IDictionary<string, Type> clientAlgorithms, string[] serverAlgorithms);
84+
IKeyExchange CreateKeyExchange(IDictionary<string, Func<IKeyExchange>> clientAlgorithms, string[] serverAlgorithms);
8585

8686
/// <summary>
8787
/// Creates an <see cref="ISftpFileReader"/> for the specified file and with the specified

src/Renci.SshNet/Renci.SshNet.csproj

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,17 @@
55
<TargetFrameworks>net462;netstandard2.0;netstandard2.1;net6.0;net7.0;net8.0</TargetFrameworks>
66
</PropertyGroup>
77

8+
<PropertyGroup Condition=" $([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net6.0')) ">
9+
<EnableTrimAnalyzer>true</EnableTrimAnalyzer>
10+
<EnableSingleFileAnalyzer>true</EnableSingleFileAnalyzer>
11+
<EnableAotAnalyzer>true</EnableAotAnalyzer>
12+
</PropertyGroup>
13+
814
<PropertyGroup Condition=" '$(TargetFramework)' == 'net462' ">
915
<DefineConstants>$(DefineConstants);FEATURE_BINARY_SERIALIZATION;FEATURE_HASH_RIPEMD160_CREATE;FEATURE_HMAC_RIPEMD160</DefineConstants>
1016
</PropertyGroup>
1117

12-
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' or '$(TargetFramework)' == 'netstandard2.1' or '$(TargetFramework)' == 'net6.0' or '$(TargetFramework)' == 'net7.0' or '$(TargetFramework)' == 'net8.0' ">
18+
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' or $([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'netstandard2.1')) ">
1319
<PackageReference Include="SshNet.Security.Cryptography" Version="[1.3.0]" />
1420
</ItemGroup>
1521

src/Renci.SshNet/Security/Cryptography/RsaDigitalSignature.cs

Lines changed: 18 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Security.Cryptography;
3+
34
using Renci.SshNet.Common;
45
using Renci.SshNet.Security.Cryptography.Ciphers;
56

@@ -10,7 +11,11 @@ namespace Renci.SshNet.Security.Cryptography
1011
/// </summary>
1112
public class RsaDigitalSignature : CipherDigitalSignature, IDisposable
1213
{
13-
private HashAlgorithm _hash;
14+
#if NET462
15+
private readonly HashAlgorithm _hash;
16+
#else
17+
private readonly IncrementalHash _hash;
18+
#endif
1419

1520
/// <summary>
1621
/// Initializes a new instance of the <see cref="RsaDigitalSignature"/> class with the SHA-1 hash algorithm.
@@ -29,8 +34,14 @@ public RsaDigitalSignature(RsaKey rsaKey)
2934
public RsaDigitalSignature(RsaKey rsaKey, HashAlgorithmName hashAlgorithmName)
3035
: base(ObjectIdentifier.FromHashAlgorithmName(hashAlgorithmName), new RsaCipher(rsaKey))
3136
{
37+
#if NET462
3238
_hash = CryptoConfig.CreateFromName(hashAlgorithmName.Name) as HashAlgorithm
3339
?? throw new ArgumentException($"Could not create {nameof(HashAlgorithm)} from `{hashAlgorithmName}`.", nameof(hashAlgorithmName));
40+
#else
41+
// CryptoConfig.CreateFromName is a somewhat legacy API and is incompatible with trimming.
42+
// Use IncrementalHash instead (which is also more modern and lighter-weight than HashAlgorithm).
43+
_hash = IncrementalHash.CreateHash(hashAlgorithmName);
44+
#endif
3445
}
3546

3647
/// <summary>
@@ -42,13 +53,16 @@ public RsaDigitalSignature(RsaKey rsaKey, HashAlgorithmName hashAlgorithmName)
4253
/// </returns>
4354
protected override byte[] Hash(byte[] input)
4455
{
56+
#if NET462
4557
return _hash.ComputeHash(input);
58+
#else
59+
_hash.AppendData(input);
60+
return _hash.GetHashAndReset();
61+
#endif
4662
}
4763

4864
#region IDisposable Members
4965

50-
private bool _isDisposed;
51-
5266
/// <summary>
5367
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
5468
/// </summary>
@@ -64,31 +78,7 @@ public void Dispose()
6478
/// <param name="disposing"><see langword="true"/> to release both managed and unmanaged resources; <see langword="false"/> to release only unmanaged resources.</param>
6579
protected virtual void Dispose(bool disposing)
6680
{
67-
if (_isDisposed)
68-
{
69-
return;
70-
}
71-
72-
if (disposing)
73-
{
74-
var hash = _hash;
75-
if (hash != null)
76-
{
77-
hash.Dispose();
78-
_hash = null;
79-
}
80-
81-
_isDisposed = true;
82-
}
83-
}
84-
85-
/// <summary>
86-
/// Releases unmanaged resources and performs other cleanup operations before the
87-
/// <see cref="RsaDigitalSignature"/> is reclaimed by garbage collection.
88-
/// </summary>
89-
~RsaDigitalSignature()
90-
{
91-
Dispose(disposing: false);
81+
_hash.Dispose();
9282
}
9383

9484
#endregion

src/Renci.SshNet/Security/KeyExchange.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ public abstract class KeyExchange : Algorithm, IKeyExchange
2121
private CipherInfo _serverCipherInfo;
2222
private HashInfo _clientHashInfo;
2323
private HashInfo _serverHashInfo;
24-
private Type _compressionType;
25-
private Type _decompressionType;
24+
private Func<Compressor> _compressorFactory;
25+
private Func<Compressor> _decompressorFactory;
2626

2727
/// <summary>
2828
/// Gets the session.
@@ -148,8 +148,8 @@ from a in message.CompressionAlgorithmsServerToClient
148148
_serverCipherInfo = session.ConnectionInfo.Encryptions[serverDecryptionAlgorithmName];
149149
_clientHashInfo = session.ConnectionInfo.HmacAlgorithms[clientHmacAlgorithmName];
150150
_serverHashInfo = session.ConnectionInfo.HmacAlgorithms[serverHmacAlgorithmName];
151-
_compressionType = session.ConnectionInfo.CompressionAlgorithms[compressionAlgorithmName];
152-
_decompressionType = session.ConnectionInfo.CompressionAlgorithms[decompressionAlgorithmName];
151+
_compressorFactory = session.ConnectionInfo.CompressionAlgorithms[compressionAlgorithmName];
152+
_decompressorFactory = session.ConnectionInfo.CompressionAlgorithms[decompressionAlgorithmName];
153153
}
154154

155155
/// <summary>
@@ -269,7 +269,7 @@ public HashAlgorithm CreateClientHash()
269269
/// </returns>
270270
public Compressor CreateCompressor()
271271
{
272-
if (_compressionType is null)
272+
if (_compressorFactory is null)
273273
{
274274
return null;
275275
}
@@ -278,7 +278,7 @@ public Compressor CreateCompressor()
278278
Session.ToHex(Session.SessionId),
279279
Session.ConnectionInfo.CurrentClientCompressionAlgorithm));
280280

281-
var compressor = _compressionType.CreateInstance<Compressor>();
281+
var compressor = _compressorFactory();
282282

283283
compressor.Init(Session);
284284

@@ -293,7 +293,7 @@ public Compressor CreateCompressor()
293293
/// </returns>
294294
public Compressor CreateDecompressor()
295295
{
296-
if (_decompressionType is null)
296+
if (_decompressorFactory is null)
297297
{
298298
return null;
299299
}
@@ -302,7 +302,7 @@ public Compressor CreateDecompressor()
302302
Session.ToHex(Session.SessionId),
303303
Session.ConnectionInfo.CurrentServerCompressionAlgorithm));
304304

305-
var decompressor = _decompressionType.CreateInstance<Compressor>();
305+
var decompressor = _decompressorFactory();
306306

307307
decompressor.Init(Session);
308308

src/Renci.SshNet/ServiceFactory.cs

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -79,19 +79,8 @@ public PipeStream CreatePipeStream()
7979
return new PipeStream();
8080
}
8181

82-
/// <summary>
83-
/// Negotiates a key exchange algorithm, and creates a <see cref="IKeyExchange" /> for the negotiated
84-
/// algorithm.
85-
/// </summary>
86-
/// <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>
87-
/// <param name="serverAlgorithms">The names of the key exchange algorithms supported by the SSH server.</param>
88-
/// <returns>
89-
/// A <see cref="IKeyExchange"/> that was negotiated between client and server.
90-
/// </returns>
91-
/// <exception cref="ArgumentNullException"><paramref name="clientAlgorithms"/> is <see langword="null"/>.</exception>
92-
/// <exception cref="ArgumentNullException"><paramref name="serverAlgorithms"/> is <see langword="null"/>.</exception>
93-
/// <exception cref="SshConnectionException">No key exchange algorithms are supported by both client and server.</exception>
94-
public IKeyExchange CreateKeyExchange(IDictionary<string, Type> clientAlgorithms, string[] serverAlgorithms)
82+
/// <inheritdoc/>
83+
public IKeyExchange CreateKeyExchange(IDictionary<string, Func<IKeyExchange>> clientAlgorithms, string[] serverAlgorithms)
9584
{
9685
if (clientAlgorithms is null)
9786
{
@@ -104,17 +93,17 @@ public IKeyExchange CreateKeyExchange(IDictionary<string, Type> clientAlgorithms
10493
}
10594

10695
// find an algorithm that is supported by both client and server
107-
var keyExchangeAlgorithmType = (from c in clientAlgorithms
96+
var keyExchangeAlgorithmFactory = (from c in clientAlgorithms
10897
from s in serverAlgorithms
10998
where s == c.Key
11099
select c.Value).FirstOrDefault();
111100

112-
if (keyExchangeAlgorithmType is null)
101+
if (keyExchangeAlgorithmFactory is null)
113102
{
114103
throw new SshConnectionException("Failed to negotiate key exchange algorithm.", DisconnectReason.KeyExchangeFailed);
115104
}
116105

117-
return keyExchangeAlgorithmType.CreateInstance<IKeyExchange>();
106+
return keyExchangeAlgorithmFactory();
118107
}
119108

120109
/// <summary>

0 commit comments

Comments
 (0)