KeyExchangeECDH
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 override byte[] GenerateClientPublicKey()
            {
                _clientECDH.GenerateKey(_curve);
                return EncodeECPoint(_clientECDH.PublicKey.ExportParameters().Q);
            }
            public override byte[] CalculateAgreement(byte[] serverPublicKey)
            {
                ECPoint q = DecodeECPoint(serverPublicKey);
                ECParameters parameters = default(ECParameters);
                parameters.Curve = _curve;
                parameters.Q = q;
                using (ECDiffieHellman eCDiffieHellman = ECDiffieHellman.Create(parameters))
                    return _clientECDH.DeriveRawSecretAgreement(eCDiffieHellman.PublicKey);
            }
            private static byte[] EncodeECPoint(ECPoint point)
            {
                byte[] array = new byte[1 + point.X.Length + point.Y.Length];
                array[0] = 4;
                Buffer.BlockCopy(point.X, 0, array, 1, point.X.Length);
                Buffer.BlockCopy(point.Y, 0, array, point.X.Length + 1, 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[] GenerateClientPublicKey()
            {
                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[] serverPublicKey)
            {
                ECPoint val = _domainParameters.get_Curve().DecodePoint(serverPublicKey);
                ECPublicKeyParameters val2 = new ECPublicKeyParameters("ECDH", val, _domainParameters);
                return _keyAgreement.CalculateAgreement(val2).ToByteArray();
            }
        }
        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.GenerateClientPublicKey();
            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();
        }
    }
}