Skip to content
22 changes: 21 additions & 1 deletion src/Renci.SshNet/Security/KeyExchangeEC.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using Renci.SshNet.Messages.Transport;
using System;

using Renci.SshNet.Messages.Transport;

namespace Renci.SshNet.Security
{
Expand Down Expand Up @@ -76,5 +78,23 @@ public override void Start(Session session, KeyExchangeInitMessage message, bool
_serverPayload = message.GetBytes();
_clientPayload = Session.ClientInitMessage.GetBytes();
}

protected abstract class Impl : IDisposable
{
public abstract byte[] GenerateClientPublicKey();

public abstract byte[] CalculateAgreement(byte[] serverPublicKey);

protected virtual void Dispose(bool disposing)
{
}

public void Dispose()
{
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
}
}
}
57 changes: 57 additions & 0 deletions src/Renci.SshNet/Security/KeyExchangeECCurve25519.BclImpl.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#if NET
using System.Security.Cryptography;

namespace Renci.SshNet.Security
{
internal partial class KeyExchangeECCurve25519
{
protected sealed class BclImpl : Impl
{
private readonly ECCurve _curve;
private readonly ECDiffieHellman _clientECDH;

public BclImpl()
{
_curve = ECCurve.CreateFromFriendlyName("Curve25519");
_clientECDH = ECDiffieHellman.Create();
}

public override byte[] GenerateClientPublicKey()
{
_clientECDH.GenerateKey(_curve);

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

return q.X;
}

public override byte[] CalculateAgreement(byte[] serverPublicKey)
{
var parameters = new ECParameters
{
Curve = _curve,
Q = new ECPoint
{
X = serverPublicKey,
Y = new byte[serverPublicKey.Length]
},
};

using var serverECDH = ECDiffieHellman.Create(parameters);

return _clientECDH.DeriveRawSecretAgreement(serverECDH.PublicKey);
}

protected override void Dispose(bool disposing)
{
base.Dispose(disposing);

if (disposing)
{
_clientECDH.Dispose();
}
}
}
}
}
#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using Org.BouncyCastle.Crypto.Agreement;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Parameters;

using Renci.SshNet.Abstractions;

namespace Renci.SshNet.Security
{
internal partial class KeyExchangeECCurve25519
{
protected sealed class BouncyCastleImpl : Impl
{
private X25519Agreement _keyAgreement;

public override byte[] GenerateClientPublicKey()
{
var g = new X25519KeyPairGenerator();
g.Init(new X25519KeyGenerationParameters(CryptoAbstraction.SecureRandom));

var aKeyPair = g.GenerateKeyPair();
_keyAgreement = new X25519Agreement();
_keyAgreement.Init(aKeyPair.Private);

return ((X25519PublicKeyParameters)aKeyPair.Public).GetEncoded();
}

public override byte[] CalculateAgreement(byte[] serverPublicKey)
{
var publicKey = new X25519PublicKeyParameters(serverPublicKey);

var k1 = new byte[_keyAgreement.AgreementSize];
_keyAgreement.CalculateAgreement(publicKey, k1, 0);

return k1;
}
}
}
}
69 changes: 48 additions & 21 deletions src/Renci.SshNet/Security/KeyExchangeECCurve25519.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
using Org.BouncyCastle.Crypto.Agreement;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Parameters;

using Renci.SshNet.Abstractions;
using Renci.SshNet.Abstractions;
using Renci.SshNet.Common;
using Renci.SshNet.Messages.Transport;

namespace Renci.SshNet.Security
{
internal sealed class KeyExchangeECCurve25519 : KeyExchangeEC
internal partial class KeyExchangeECCurve25519 : KeyExchangeEC
{
private X25519Agreement _keyAgreement;
#pragma warning disable SA1401 // Fields should be private
#if NET
protected Impl _impl;
#else
protected BouncyCastleImpl _impl;
#endif
#pragma warning restore SA1401 // Fields should be private

/// <summary>
/// Gets algorithm name.
Expand All @@ -35,29 +37,46 @@ protected override int HashSize
public override void Start(Session session, KeyExchangeInitMessage message, bool sendClientInitMessage)
{
base.Start(session, message, sendClientInitMessage);
#if NET
if (System.OperatingSystem.IsWindowsVersionAtLeast(10))
{
_impl = new BclImpl();
}
else
#endif
{
_impl = new BouncyCastleImpl();
}

StartImpl();
}

/// <summary>
/// The implementation of start key exchange algorithm.
/// </summary>
protected virtual void StartImpl()
{
Session.RegisterMessage("SSH_MSG_KEX_ECDH_REPLY");

Session.KeyExchangeEcdhReplyMessageReceived += Session_KeyExchangeEcdhReplyMessageReceived;

var g = new X25519KeyPairGenerator();
g.Init(new X25519KeyGenerationParameters(CryptoAbstraction.SecureRandom));

var aKeyPair = g.GenerateKeyPair();
_keyAgreement = new X25519Agreement();
_keyAgreement.Init(aKeyPair.Private);
_clientExchangeValue = ((X25519PublicKeyParameters)aKeyPair.Public).GetEncoded();
_clientExchangeValue = _impl.GenerateClientPublicKey();

SendMessage(new KeyExchangeEcdhInitMessage(_clientExchangeValue));
}

/// <summary>
/// Finishes key exchange algorithm.
/// </summary>
/// <inheritdoc/>
public override void Finish()
{
base.Finish();
FinishImpl();
}

/// <summary>
/// The implementation of finish key exchange algorithm.
/// </summary>
protected virtual void FinishImpl()
{
Session.KeyExchangeEcdhReplyMessageReceived -= Session_KeyExchangeEcdhReplyMessageReceived;
}

Expand Down Expand Up @@ -98,11 +117,19 @@ private void HandleServerEcdhReply(byte[] hostKey, byte[] serverExchangeValue, b
_hostKey = hostKey;
_signature = signature;

var publicKey = new X25519PublicKeyParameters(serverExchangeValue);

var k1 = new byte[_keyAgreement.AgreementSize];
_keyAgreement.CalculateAgreement(publicKey, k1, 0);
var k1 = _impl.CalculateAgreement(serverExchangeValue);
SharedKey = k1.ToBigInteger2().ToByteArray(isBigEndian: true);
}

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

if (disposing)
{
_impl?.Dispose();
}
}
}
}
6 changes: 3 additions & 3 deletions src/Renci.SshNet/Security/KeyExchangeECDH.BclImpl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public BclImpl(ECCurve curve)
_clientECDH = ECDiffieHellman.Create();
}

public override byte[] GenerateClientECPoint()
public override byte[] GenerateClientPublicKey()
{
_clientECDH.GenerateKey(_curve);

Expand All @@ -26,9 +26,9 @@ public override byte[] GenerateClientECPoint()
return EncodeECPoint(q);
}

public override byte[] CalculateAgreement(byte[] serverECPoint)
public override byte[] CalculateAgreement(byte[] serverPublicKey)
{
var q = DecodeECPoint(serverECPoint);
var q = DecodeECPoint(serverPublicKey);

var parameters = new ECParameters
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public BouncyCastleImpl(X9ECParameters curveParameters)
_keyAgreement = new ECDHCBasicAgreement();
}

public override byte[] GenerateClientECPoint()
public override byte[] GenerateClientPublicKey()
{
var g = new ECKeyPairGenerator();
g.Init(new ECKeyGenerationParameters(_domainParameters, CryptoAbstraction.SecureRandom));
Expand All @@ -31,10 +31,10 @@ public override byte[] GenerateClientECPoint()
return ((ECPublicKeyParameters)aKeyPair.Public).Q.GetEncoded();
}

public override byte[] CalculateAgreement(byte[] serverECPoint)
public override byte[] CalculateAgreement(byte[] serverPublicKey)
{
var c = _domainParameters.Curve;
var q = c.DecodePoint(serverECPoint);
var q = c.DecodePoint(serverPublicKey);
var publicKey = new ECPublicKeyParameters("ECDH", q, _domainParameters);

return _keyAgreement.CalculateAgreement(publicKey).ToByteArray();
Expand Down
26 changes: 3 additions & 23 deletions src/Renci.SshNet/Security/KeyExchangeECDH.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using System;

using Org.BouncyCastle.Asn1.X9;
using Org.BouncyCastle.Asn1.X9;

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

#if NET
if (!OperatingSystem.IsWindows() || OperatingSystem.IsWindowsVersionAtLeast(10))
if (!System.OperatingSystem.IsWindows() || System.OperatingSystem.IsWindowsVersionAtLeast(10))
{
_impl = new BclImpl(Curve);
}
Expand All @@ -51,7 +49,7 @@ public override void Start(Session session, KeyExchangeInitMessage message, bool
_impl = new BouncyCastleImpl(CurveParameter);
}

_clientExchangeValue = _impl.GenerateClientECPoint();
_clientExchangeValue = _impl.GenerateClientPublicKey();

SendMessage(new KeyExchangeEcdhInitMessage(_clientExchangeValue));
}
Expand Down Expand Up @@ -106,23 +104,5 @@ protected override void Dispose(bool disposing)
_impl?.Dispose();
}
}

private abstract class Impl : IDisposable
{
public abstract byte[] GenerateClientECPoint();

public abstract byte[] CalculateAgreement(byte[] serverECPoint);

protected virtual void Dispose(bool disposing)
{
}

public void Dispose()
{
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
}
}
}
Loading
Loading