<PackageReference Include="SSH.NET" Version="2024.2.0" />

KeyExchangeECDH

abstract class KeyExchangeECDH : KeyExchangeEC
using Org.BouncyCastle.Asn1.X9; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Agreement; using Org.BouncyCastle.Crypto.Generators; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Math.EC; using Renci.SshNet.Abstractions; using Renci.SshNet.Common; using Renci.SshNet.Messages.Transport; using System; using System.Security.Cryptography; namespace Renci.SshNet.Security { internal abstract class KeyExchangeECDH : KeyExchangeEC { private sealed class BclImpl : Impl { private readonly ECCurve _curve; private readonly ECDiffieHellman _clientECDH; public BclImpl(ECCurve curve) { _curve = curve; _clientECDH = ECDiffieHellman.Create(); } public unsafe override byte[] GenerateClientECPoint() { _clientECDH.GenerateKey(_curve); return EncodeECPoint(((IntPtr)(void*)_clientECDH.get_PublicKey().ExportParameters()).Q); } public override byte[] CalculateAgreement(byte[] serverECPoint) { ECPoint q = DecodeECPoint(serverECPoint); ECParameters val = default(ECParameters); val.Curve = _curve; val.Q = q; ECDiffieHellman val2 = ECDiffieHellman.Create(val); try { return _clientECDH.DeriveRawSecretAgreement(val2.get_PublicKey()); } finally { ((IDisposable)val2)?.Dispose(); } } private unsafe static byte[] EncodeECPoint(ECPoint point) { byte[] array = new byte[1 + ((IntPtr)(void*)point).X.Length + ((IntPtr)(void*)point).Y.Length]; array[0] = 4; Buffer.BlockCopy(((IntPtr)(void*)point).X, 0, array, 1, ((IntPtr)(void*)point).X.Length); Buffer.BlockCopy(((IntPtr)(void*)point).Y, 0, array, ((IntPtr)(void*)point).X.Length + 1, ((IntPtr)(void*)point).Y.Length); return array; } private static ECPoint DecodeECPoint(byte[] q) { int num = (q.Length - 1) / 2; byte[] array = new byte[num]; byte[] array2 = new byte[num]; Buffer.BlockCopy(q, 1, array, 0, array.Length); Buffer.BlockCopy(q, num + 1, array2, 0, array2.Length); ECPoint result = default(ECPoint); result.X = array; result.Y = array2; return result; } protected override void Dispose(bool disposing) { base.Dispose(disposing); if (disposing) _clientECDH.Dispose(); } } private sealed class BouncyCastleImpl : Impl { private readonly ECDomainParameters _domainParameters; private readonly ECDHCBasicAgreement _keyAgreement; public BouncyCastleImpl(X9ECParameters curveParameters) { _domainParameters = new ECDomainParameters(curveParameters); _keyAgreement = new ECDHCBasicAgreement(); } public override byte[] GenerateClientECPoint() { ECKeyPairGenerator val = new ECKeyPairGenerator(); val.Init(new ECKeyGenerationParameters(_domainParameters, CryptoAbstraction.SecureRandom)); AsymmetricCipherKeyPair val2 = val.GenerateKeyPair(); _keyAgreement.Init(val2.get_Private()); return val2.get_Public().get_Q().GetEncoded(); } public override byte[] CalculateAgreement(byte[] serverECPoint) { ECPoint val = _domainParameters.get_Curve().DecodePoint(serverECPoint); ECPublicKeyParameters val2 = new ECPublicKeyParameters("ECDH", val, _domainParameters); return _keyAgreement.CalculateAgreement(val2).ToByteArray(); } } private abstract class Impl : IDisposable { public abstract byte[] GenerateClientECPoint(); public abstract byte[] CalculateAgreement(byte[] serverECPoint); protected virtual void Dispose(bool disposing) { } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } } private Impl _impl; protected abstract ECCurve Curve { get; } protected abstract X9ECParameters CurveParameter { get; } public override void Start(Session session, KeyExchangeInitMessage message, bool sendClientInitMessage) { base.Start(session, message, sendClientInitMessage); base.Session.RegisterMessage("SSH_MSG_KEX_ECDH_REPLY"); base.Session.KeyExchangeEcdhReplyMessageReceived += Session_KeyExchangeEcdhReplyMessageReceived; if (!OperatingSystem.IsWindows() || OperatingSystem.IsWindowsVersionAtLeast(10, 0, 0, 0)) _impl = new BclImpl(Curve); else _impl = new BouncyCastleImpl(CurveParameter); _clientExchangeValue = _impl.GenerateClientECPoint(); SendMessage(new KeyExchangeEcdhInitMessage(_clientExchangeValue)); } public override void Finish() { base.Finish(); base.Session.KeyExchangeEcdhReplyMessageReceived -= Session_KeyExchangeEcdhReplyMessageReceived; } private void Session_KeyExchangeEcdhReplyMessageReceived(object sender, MessageEventArgs<KeyExchangeEcdhReplyMessage> e) { KeyExchangeEcdhReplyMessage message = e.Message; base.Session.UnRegisterMessage("SSH_MSG_KEX_ECDH_REPLY"); HandleServerEcdhReply(message.KS, message.QS, message.Signature); Finish(); } private void HandleServerEcdhReply(byte[] hostKey, byte[] serverExchangeValue, byte[] signature) { _serverExchangeValue = serverExchangeValue; _hostKey = hostKey; _signature = signature; byte[] data = _impl.CalculateAgreement(serverExchangeValue); base.SharedKey = data.ToBigInteger2().ToByteArray(false, true); } protected override void Dispose(bool disposing) { base.Dispose(disposing); if (disposing) _impl?.Dispose(); } } }