using Renci.SshNet.Messages;
using Renci.SshNet.Messages.Transport;
namespace Renci.SshNet.Security
{
    public abstract class KeyExchangeDiffieHellmanGroupExchangeShaBase : KeyExchangeDiffieHellman
    {
        private const int MinimumGroupSize = 1024;
        private const int PreferredGroupSize = 1024;
        private const int MaximumProupSize = 8192;
        /// 
        /// Calculates key exchange hash value.
        /// 
        /// 
        /// Key exchange hash.
        /// 
        protected override byte[] CalculateHash()
        {
            var hashData = new GroupExchangeHashData
                {
                    ClientVersion = Session.ClientVersion,
                    ServerVersion = Session.ServerVersion,
                    ClientPayload = _clientPayload,
                    ServerPayload = _serverPayload,
                    HostKey = _hostKey,
                    MinimumGroupSize = MinimumGroupSize,
                    PreferredGroupSize = PreferredGroupSize,
                    MaximumGroupSize = MaximumProupSize,
                    Prime = _prime,
                    SubGroup = _group,
                    ClientExchangeValue = _clientExchangeValue,
                    ServerExchangeValue = _serverExchangeValue,
                    SharedKey = SharedKey,
                }.GetBytes();
            return this.Hash(hashData);
        }
        /// 
        /// Starts key exchange algorithm
        /// 
        /// The session.
        /// Key exchange init message.
        public override void Start(Session session, KeyExchangeInitMessage message)
        {
            base.Start(session, message);
            Session.RegisterMessage("SSH_MSG_KEX_DH_GEX_GROUP");
            Session.RegisterMessage("SSH_MSG_KEX_DH_GEX_REPLY");
            Session.MessageReceived += Session_MessageReceived;
            //  1. send SSH_MSG_KEY_DH_GEX_REQUEST
            SendMessage(new KeyExchangeDhGroupExchangeRequest(MinimumGroupSize, PreferredGroupSize,
                MaximumProupSize));
        }
        /// 
        /// Finishes key exchange algorithm.
        /// 
        public override void Finish()
        {
            base.Finish();
            Session.MessageReceived -= Session_MessageReceived;
        }
        private void Session_MessageReceived(object sender, MessageEventArgs e)
        {
            var groupMessage = e.Message as KeyExchangeDhGroupExchangeGroup;
            if (groupMessage != null)
            {
                //  Unregister message once received
                Session.UnRegisterMessage("SSH_MSG_KEX_DH_GEX_GROUP");
                //  2. Receive SSH_MSG_KEX_DH_GEX_GROUP
                _prime = groupMessage.SafePrime;
                _group = groupMessage.SubGroup;
                PopulateClientExchangeValue();
                //  3. Send SSH_MSG_KEX_DH_GEX_INIT
                SendMessage(new KeyExchangeDhGroupExchangeInit(_clientExchangeValue));
            }
            else
            {
                var replyMessage = e.Message as KeyExchangeDhGroupExchangeReply;
                if (replyMessage != null)
                {
                    //  Unregister message once received
                    Session.UnRegisterMessage("SSH_MSG_KEX_DH_GEX_REPLY");
                    HandleServerDhReply(replyMessage.HostKey, replyMessage.F, replyMessage.Signature);
                    //  When SSH_MSG_KEX_DH_GEX_REPLY received key exchange is completed
                    Finish();
                }
            }
        }
    }
}