Skip to content

Commit

Permalink
Use BCL ECDiffieHellman for KeyExchange (.NET 8.0 onward only)
Browse files Browse the repository at this point in the history
  • Loading branch information
scott-xu committed Apr 6, 2024
1 parent 9be67c0 commit 901fd5a
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 34 deletions.
79 changes: 69 additions & 10 deletions src/Renci.SshNet/Security/KeyExchangeECDH.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
using Renci.SshNet.Common;
using Renci.SshNet.Messages.Transport;

using Renci.SshNet.Security.Org.BouncyCastle.Asn1.X9;
using Renci.SshNet.Security.Org.BouncyCastle.Asn1.Sec;
using Renci.SshNet.Security.Org.BouncyCastle.Crypto.Agreement;
using Renci.SshNet.Security.Org.BouncyCastle.Crypto.Generators;
using Renci.SshNet.Security.Org.BouncyCastle.Crypto.Parameters;
Expand All @@ -13,13 +13,17 @@ namespace Renci.SshNet.Security
{
internal abstract class KeyExchangeECDH : KeyExchangeEC
{
#if NET8_0_OR_GREATER
private System.Security.Cryptography.ECDiffieHellman _clientECDH;
#endif

/// <summary>
/// Gets the parameter of the curve.
/// Gets the name of the curve.
/// </summary>
/// <value>
/// The parameter of the curve.
/// The name of the curve.
/// </value>
protected abstract X9ECParameters CurveParameter { get; }
protected abstract string CurveName { get; }

private ECDHCBasicAgreement _keyAgreement;
private ECDomainParameters _domainParameters;
Expand All @@ -33,11 +37,30 @@ public override void Start(Session session, KeyExchangeInitMessage message, bool

Session.KeyExchangeEcdhReplyMessageReceived += Session_KeyExchangeEcdhReplyMessageReceived;

_domainParameters = new ECDomainParameters(CurveParameter.Curve,
CurveParameter.G,
CurveParameter.N,
CurveParameter.H,
CurveParameter.GetSeed());
#if NET8_0_OR_GREATER
if (IsNonWindowsOrWindowsVersionAtLeast(10))
{
_clientECDH = System.Security.Cryptography.ECDiffieHellman.Create();
_clientECDH.GenerateKey(System.Security.Cryptography.ECCurve.CreateFromFriendlyName(CurveName));

var q = _clientECDH.PublicKey.ExportParameters().Q;

_clientExchangeValue = new byte[1 + q.X.Length + q.Y.Length];
_clientExchangeValue[0] = 0x04;
Buffer.BlockCopy(q.X, 0, _clientExchangeValue, 1, q.X.Length);
Buffer.BlockCopy(q.Y, 0, _clientExchangeValue, q.X.Length + 1, q.Y.Length);

SendMessage(new KeyExchangeEcdhInitMessage(_clientExchangeValue));

return;
}
#endif
var curveParameter = SecNamedCurves.GetByName(CurveName);
_domainParameters = new ECDomainParameters(curveParameter.Curve,
curveParameter.G,
curveParameter.N,
curveParameter.H,
curveParameter.GetSeed());

var g = new ECKeyPairGenerator();
g.Init(new ECKeyGenerationParameters(_domainParameters, new SecureRandom()));
Expand All @@ -46,7 +69,6 @@ public override void Start(Session session, KeyExchangeInitMessage message, bool
_keyAgreement = new ECDHCBasicAgreement();
_keyAgreement.Init(aKeyPair.Private);
_clientExchangeValue = ((ECPublicKeyParameters)aKeyPair.Public).Q.GetEncoded();

SendMessage(new KeyExchangeEcdhInitMessage(_clientExchangeValue));
}

Expand Down Expand Up @@ -91,12 +113,49 @@ private void HandleServerEcdhReply(byte[] hostKey, byte[] serverExchangeValue, b
var y = new byte[cordSize];
Buffer.BlockCopy(serverExchangeValue, cordSize + 1, y, 0, y.Length);

#if NET8_0_OR_GREATER
if (IsNonWindowsOrWindowsVersionAtLeast(10))
{
using var serverECDH = System.Security.Cryptography.ECDiffieHellman.Create(new System.Security.Cryptography.ECParameters
{
Curve = System.Security.Cryptography.ECCurve.CreateFromFriendlyName(CurveName),
Q =
{
X = x,
Y = y,
},
});

var k = _clientECDH.DeriveRawSecretAgreement(serverECDH.PublicKey);
SharedKey = k.ToBigInteger2().ToByteArray().Reverse();

return;
}
#endif
var c = (FpCurve)_domainParameters.Curve;
var q = c.CreatePoint(new Org.BouncyCastle.Math.BigInteger(1, x), new Org.BouncyCastle.Math.BigInteger(1, y));
var publicKey = new ECPublicKeyParameters("ECDH", q, _domainParameters);

var k1 = _keyAgreement.CalculateAgreement(publicKey);
SharedKey = k1.ToByteArray().ToBigInteger2().ToByteArray().Reverse();
}

#if NET8_0_OR_GREATER

/// <inheritdoc/>
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
{
_clientECDH?.Dispose();
}
}

private static bool IsNonWindowsOrWindowsVersionAtLeast(int major)
{
return Environment.OSVersion.Platform != PlatformID.Win32NT || Environment.OSVersion.Version.Major >= major;
}
#endif
}
}
11 changes: 3 additions & 8 deletions src/Renci.SshNet/Security/KeyExchangeECDH256.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using Renci.SshNet.Abstractions;
using Renci.SshNet.Security.Org.BouncyCastle.Asn1.Sec;
using Renci.SshNet.Security.Org.BouncyCastle.Asn1.X9;

namespace Renci.SshNet.Security
{
Expand All @@ -15,14 +13,11 @@ public override string Name
}

/// <summary>
/// Gets Curve Parameter.
/// Gets curve name.
/// </summary>
protected override X9ECParameters CurveParameter
protected override string CurveName
{
get
{
return SecNamedCurves.GetByName("P-256");
}
get { return "secp256r1"; }
}

/// <summary>
Expand Down
11 changes: 3 additions & 8 deletions src/Renci.SshNet/Security/KeyExchangeECDH384.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using Renci.SshNet.Abstractions;
using Renci.SshNet.Security.Org.BouncyCastle.Asn1.Sec;
using Renci.SshNet.Security.Org.BouncyCastle.Asn1.X9;

namespace Renci.SshNet.Security
{
Expand All @@ -15,14 +13,11 @@ public override string Name
}

/// <summary>
/// Gets Curve Parameter.
/// Gets curve name.
/// </summary>
protected override X9ECParameters CurveParameter
protected override string CurveName
{
get
{
return SecNamedCurves.GetByName("P-384");
}
get { return "secp384r1"; }
}

/// <summary>
Expand Down
11 changes: 3 additions & 8 deletions src/Renci.SshNet/Security/KeyExchangeECDH521.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using Renci.SshNet.Abstractions;
using Renci.SshNet.Security.Org.BouncyCastle.Asn1.Sec;
using Renci.SshNet.Security.Org.BouncyCastle.Asn1.X9;

namespace Renci.SshNet.Security
{
Expand All @@ -15,14 +13,11 @@ public override string Name
}

/// <summary>
/// Gets Curve Parameter.
/// Gets curve name.
/// </summary>
protected override X9ECParameters CurveParameter
protected override string CurveName
{
get
{
return SecNamedCurves.GetByName("P-521");
}
get { return "secp521r1"; }
}

/// <summary>
Expand Down

0 comments on commit 901fd5a

Please sign in to comment.