KeyExchangeDiffieHellmanGroupExchange
Provides the implementation of "diffie-hellman-group-exchange" algorithms.
            
                using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Agreement;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Renci.SshNet.Abstractions;
using Renci.SshNet.Common;
using Renci.SshNet.Messages.Transport;
using System;
using System.Runtime.CompilerServices;
using System.Security.Cryptography;
namespace Renci.SshNet.Security
{
    [NullableContext(1)]
    [Nullable(0)]
    public class KeyExchangeDiffieHellmanGroupExchange : KeyExchange
    {
        [Nullable(2)]
        private byte[] _clientPayload;
        [Nullable(2)]
        private byte[] _serverPayload;
        [Nullable(2)]
        private byte[] _clientExchangeValue;
        [Nullable(2)]
        private byte[] _serverExchangeValue;
        [Nullable(2)]
        private byte[] _prime;
        [Nullable(2)]
        private byte[] _group;
        [Nullable(2)]
        private byte[] _hostKey;
        [Nullable(2)]
        private byte[] _signature;
        private readonly IncrementalHash _hash;
        private readonly int _hashLengthInBits;
        private readonly uint _minimumGroupSize;
        private readonly uint _preferredGroupSize;
        private readonly uint _maximumGroupSize;
        [Nullable(2)]
        private DHParameters _dhParameters;
        [Nullable(2)]
        private DHBasicAgreement _keyAgreement;
        public override string Name { get; }
        public KeyExchangeDiffieHellmanGroupExchange(string name, HashAlgorithmName hashAlgorithm)
            : this(name, hashAlgorithm, 2048, 4096, 8192)
        {
        }
        public KeyExchangeDiffieHellmanGroupExchange(string name, HashAlgorithmName hashAlgorithm, uint minimumGroupSize, uint preferredGroupSize, uint maximumGroupSize)
        {
            ThrowHelper.ThrowIfNull(name, "name");
            ThrowHelper.ThrowIfNullOrEmpty(hashAlgorithm.Name, "hashAlgorithm");
            if (preferredGroupSize < minimumGroupSize || preferredGroupSize > maximumGroupSize)
                throw new ArgumentOutOfRangeException("preferredGroupSize");
            Name = name;
            _minimumGroupSize = minimumGroupSize;
            _preferredGroupSize = preferredGroupSize;
            _maximumGroupSize = maximumGroupSize;
            try {
                _hash = IncrementalHash.CreateHash(hashAlgorithm);
                _hashLengthInBits = _hash.HashLengthInBytes * 8;
            } catch (CryptographicException innerException) {
                DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(26, 2);
                defaultInterpolatedStringHandler.AppendLiteral("Could not create ");
                defaultInterpolatedStringHandler.AppendFormatted("HashAlgorithm");
                defaultInterpolatedStringHandler.AppendLiteral(" from `");
                defaultInterpolatedStringHandler.AppendFormatted(hashAlgorithm);
                defaultInterpolatedStringHandler.AppendLiteral("`.");
                throw new ArgumentException(defaultInterpolatedStringHandler.ToStringAndClear(), "hashAlgorithm", innerException);
            }
        }
        protected override byte[] CalculateHash()
        {
            GroupExchangeHashData groupExchangeHashData = new GroupExchangeHashData {
                ClientVersion = base.Session.ClientVersion,
                ServerVersion = base.Session.ServerVersion,
                ClientPayload = _clientPayload,
                ServerPayload = _serverPayload,
                HostKey = _hostKey,
                MinimumGroupSize = _minimumGroupSize,
                PreferredGroupSize = _preferredGroupSize,
                MaximumGroupSize = _maximumGroupSize,
                Prime = _prime,
                SubGroup = _group,
                ClientExchangeValue = _clientExchangeValue,
                ServerExchangeValue = _serverExchangeValue,
                SharedKey = base.SharedKey
            };
            return Hash(groupExchangeHashData.GetBytes());
        }
        public override void Start(Session session, KeyExchangeInitMessage message, bool sendClientInitMessage)
        {
            base.Start(session, message, sendClientInitMessage);
            _serverPayload = message.GetBytes();
            _clientPayload = base.Session.ClientInitMessage.GetBytes();
            base.Session.RegisterMessage("SSH_MSG_KEX_DH_GEX_GROUP");
            base.Session.KeyExchangeDhGroupExchangeGroupReceived += Session_KeyExchangeDhGroupExchangeGroupReceived;
            SendMessage(new KeyExchangeDhGroupExchangeRequest(_minimumGroupSize, _preferredGroupSize, _maximumGroupSize));
        }
        private void Session_KeyExchangeDhGroupExchangeGroupReceived([Nullable(2)] object sender, MessageEventArgs<KeyExchangeDhGroupExchangeGroup> e)
        {
            KeyExchangeDhGroupExchangeGroup message = e.Message;
            base.Session.UnRegisterMessage("SSH_MSG_KEX_DH_GEX_GROUP");
            base.Session.KeyExchangeDhGroupExchangeGroupReceived -= Session_KeyExchangeDhGroupExchangeGroupReceived;
            _prime = message.SafePrimeBytes;
            _group = message.SubGroupBytes;
            int num = 2 * _hashLengthInBits;
            _dhParameters = new DHParameters(new BigInteger(_prime), new BigInteger(_group), null, num, 0);
            DHKeyPairGenerator val = new DHKeyPairGenerator();
            val.Init(new DHKeyGenerationParameters(CryptoAbstraction.SecureRandom, _dhParameters));
            AsymmetricCipherKeyPair val2 = val.GenerateKeyPair();
            _keyAgreement = new DHBasicAgreement();
            _keyAgreement.Init(val2.get_Private());
            _clientExchangeValue = val2.get_Public().get_Y().ToByteArray();
            base.Session.RegisterMessage("SSH_MSG_KEX_DH_GEX_REPLY");
            base.Session.KeyExchangeDhGroupExchangeReplyReceived += Session_KeyExchangeDhGroupExchangeReplyReceived;
            SendMessage(new KeyExchangeDhGroupExchangeInit(_clientExchangeValue));
        }
        private void Session_KeyExchangeDhGroupExchangeReplyReceived([Nullable(2)] object sender, MessageEventArgs<KeyExchangeDhGroupExchangeReply> e)
        {
            KeyExchangeDhGroupExchangeReply message = e.Message;
            base.Session.KeyExchangeDhGroupExchangeReplyReceived -= Session_KeyExchangeDhGroupExchangeReplyReceived;
            base.Session.UnRegisterMessage("SSH_MSG_KEX_DH_GEX_REPLY");
            base.Session.KeyExchangeDhGroupExchangeReplyReceived -= Session_KeyExchangeDhGroupExchangeReplyReceived;
            _serverExchangeValue = message.F;
            _hostKey = message.HostKey;
            _signature = message.Signature;
            DHPublicKeyParameters val = new DHPublicKeyParameters(new BigInteger(message.F), _dhParameters);
            base.SharedKey = _keyAgreement.CalculateAgreement(val).ToByteArray();
            Finish();
        }
        protected override bool ValidateExchangeHash()
        {
            return ValidateExchangeHash(_hostKey, _signature);
        }
        protected override byte[] Hash(byte[] hashData)
        {
            _hash.AppendData(hashData);
            return _hash.GetHashAndReset();
        }
        protected override void Dispose(bool disposing)
        {
            if (disposing)
                _hash.Dispose();
            base.Dispose(disposing);
        }
    }
}