Skip to content

Commit f6e2486

Browse files
committed
Use BCL Curve25519 when possible
1 parent b199467 commit f6e2486

File tree

5 files changed

+95
-43
lines changed

5 files changed

+95
-43
lines changed

src/Renci.SshNet/Security/KeyExchangeECDH.BclImpl.cs renamed to src/Renci.SshNet/Security/KeyExchangeEC.BclImpl.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44

55
namespace Renci.SshNet.Security
66
{
7-
internal abstract partial class KeyExchangeECDH
7+
internal abstract partial class KeyExchangeEC
88
{
9-
private sealed class BclImpl : Impl
9+
protected internal sealed class BclImpl : Impl
1010
{
1111
private readonly ECCurve _curve;
1212
private readonly ECDiffieHellman _clientECDH;

src/Renci.SshNet/Security/KeyExchangeEC.cs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
using Renci.SshNet.Messages.Transport;
1+
using System;
2+
3+
using Renci.SshNet.Messages.Transport;
24

35
namespace Renci.SshNet.Security
46
{
5-
internal abstract class KeyExchangeEC : KeyExchange
7+
internal abstract partial class KeyExchangeEC : KeyExchange
68
{
79
#pragma warning disable SA1401 // Fields should be private
810
/// <summary>
@@ -76,5 +78,23 @@ public override void Start(Session session, KeyExchangeInitMessage message, bool
7678
_serverPayload = message.GetBytes();
7779
_clientPayload = Session.ClientInitMessage.GetBytes();
7880
}
81+
82+
protected internal abstract class Impl : IDisposable
83+
{
84+
public abstract byte[] GenerateClientECPoint();
85+
86+
public abstract byte[] CalculateAgreement(byte[] serverECPoint);
87+
88+
protected virtual void Dispose(bool disposing)
89+
{
90+
}
91+
92+
public void Dispose()
93+
{
94+
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
95+
Dispose(disposing: true);
96+
GC.SuppressFinalize(this);
97+
}
98+
}
7999
}
80100
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
using Org.BouncyCastle.Crypto.Agreement;
2+
using Org.BouncyCastle.Crypto.Generators;
3+
using Org.BouncyCastle.Crypto.Parameters;
4+
5+
using Renci.SshNet.Abstractions;
6+
7+
namespace Renci.SshNet.Security
8+
{
9+
internal partial class KeyExchangeECCurve25519
10+
{
11+
private sealed class BouncyCastleImpl : Impl
12+
{
13+
private X25519Agreement _keyAgreement;
14+
15+
public override byte[] GenerateClientECPoint()
16+
{
17+
var g = new X25519KeyPairGenerator();
18+
g.Init(new X25519KeyGenerationParameters(CryptoAbstraction.SecureRandom));
19+
20+
var aKeyPair = g.GenerateKeyPair();
21+
_keyAgreement = new X25519Agreement();
22+
_keyAgreement.Init(aKeyPair.Private);
23+
24+
return ((X25519PublicKeyParameters)aKeyPair.Public).GetEncoded();
25+
}
26+
27+
public override byte[] CalculateAgreement(byte[] serverECPoint)
28+
{
29+
var publicKey = new X25519PublicKeyParameters(serverECPoint);
30+
31+
var k1 = new byte[_keyAgreement.AgreementSize];
32+
_keyAgreement.CalculateAgreement(publicKey, k1, 0);
33+
34+
return k1;
35+
}
36+
}
37+
}
38+
}

src/Renci.SshNet/Security/KeyExchangeECCurve25519.cs

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
1-
using Org.BouncyCastle.Crypto.Agreement;
2-
using Org.BouncyCastle.Crypto.Generators;
3-
using Org.BouncyCastle.Crypto.Parameters;
4-
5-
using Renci.SshNet.Abstractions;
1+
using Renci.SshNet.Abstractions;
62
using Renci.SshNet.Common;
73
using Renci.SshNet.Messages.Transport;
84

95
namespace Renci.SshNet.Security
106
{
11-
internal sealed class KeyExchangeECCurve25519 : KeyExchangeEC
7+
internal sealed partial class KeyExchangeECCurve25519 : KeyExchangeEC
128
{
13-
private X25519Agreement _keyAgreement;
9+
#if NET
10+
private Impl _impl;
11+
#else
12+
private BouncyCastleImpl _impl;
13+
#endif
1414

1515
/// <summary>
1616
/// Gets algorithm name.
@@ -40,13 +40,19 @@ public override void Start(Session session, KeyExchangeInitMessage message, bool
4040

4141
Session.KeyExchangeEcdhReplyMessageReceived += Session_KeyExchangeEcdhReplyMessageReceived;
4242

43-
var g = new X25519KeyPairGenerator();
44-
g.Init(new X25519KeyGenerationParameters(CryptoAbstraction.SecureRandom));
43+
#if NET
44+
if (System.OperatingSystem.IsWindowsVersionAtLeast(10))
45+
{
46+
var curve = System.Security.Cryptography.ECCurve.CreateFromFriendlyName("Curve25519");
47+
_impl = new BclImpl(curve);
48+
}
49+
else
50+
#endif
51+
{
52+
_impl = new BouncyCastleImpl();
53+
}
4554

46-
var aKeyPair = g.GenerateKeyPair();
47-
_keyAgreement = new X25519Agreement();
48-
_keyAgreement.Init(aKeyPair.Private);
49-
_clientExchangeValue = ((X25519PublicKeyParameters)aKeyPair.Public).GetEncoded();
55+
_clientExchangeValue = _impl.GenerateClientECPoint();
5056

5157
SendMessage(new KeyExchangeEcdhInitMessage(_clientExchangeValue));
5258
}
@@ -98,11 +104,19 @@ private void HandleServerEcdhReply(byte[] hostKey, byte[] serverExchangeValue, b
98104
_hostKey = hostKey;
99105
_signature = signature;
100106

101-
var publicKey = new X25519PublicKeyParameters(serverExchangeValue);
102-
103-
var k1 = new byte[_keyAgreement.AgreementSize];
104-
_keyAgreement.CalculateAgreement(publicKey, k1, 0);
107+
var k1 = _impl.CalculateAgreement(serverExchangeValue);
105108
SharedKey = k1.ToBigInteger2().ToByteArray(isBigEndian: true);
106109
}
110+
111+
/// <inheritdoc/>
112+
protected override void Dispose(bool disposing)
113+
{
114+
base.Dispose(disposing);
115+
116+
if (disposing)
117+
{
118+
_impl?.Dispose();
119+
}
120+
}
107121
}
108122
}

src/Renci.SshNet/Security/KeyExchangeECDH.cs

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
using System;
2-
3-
using Org.BouncyCastle.Asn1.X9;
1+
using Org.BouncyCastle.Asn1.X9;
42

53
using Renci.SshNet.Common;
64
using Renci.SshNet.Messages.Transport;
@@ -41,7 +39,7 @@ public override void Start(Session session, KeyExchangeInitMessage message, bool
4139
Session.KeyExchangeEcdhReplyMessageReceived += Session_KeyExchangeEcdhReplyMessageReceived;
4240

4341
#if NET
44-
if (!OperatingSystem.IsWindows() || OperatingSystem.IsWindowsVersionAtLeast(10))
42+
if (!System.OperatingSystem.IsWindows() || System.OperatingSystem.IsWindowsVersionAtLeast(10))
4543
{
4644
_impl = new BclImpl(Curve);
4745
}
@@ -106,23 +104,5 @@ protected override void Dispose(bool disposing)
106104
_impl?.Dispose();
107105
}
108106
}
109-
110-
private abstract class Impl : IDisposable
111-
{
112-
public abstract byte[] GenerateClientECPoint();
113-
114-
public abstract byte[] CalculateAgreement(byte[] serverECPoint);
115-
116-
protected virtual void Dispose(bool disposing)
117-
{
118-
}
119-
120-
public void Dispose()
121-
{
122-
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
123-
Dispose(disposing: true);
124-
GC.SuppressFinalize(this);
125-
}
126-
}
127107
}
128108
}

0 commit comments

Comments
 (0)