using Renci.SshNet.Messages; using Renci.SshNet.Messages.Transport; namespace Renci.SshNet.Security { /// /// Base class for "diffie-hellman-group-exchange" algorithms. /// 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 Hash(hashData); } /// /// Starts key exchange algorithm /// /// The session. /// Key exchange init message. public override void Start(Session session, KeyExchangeInitMessage message) { base.Start(session, message); // Register SSH_MSG_KEX_DH_GEX_GROUP message Session.RegisterMessage("SSH_MSG_KEX_DH_GEX_GROUP"); // Subscribe to KeyExchangeDhGroupExchangeGroupReceived events Session.KeyExchangeDhGroupExchangeGroupReceived += Session_KeyExchangeDhGroupExchangeGroupReceived; // 1. client sends SSH_MSG_KEY_DH_GEX_REQUEST SendMessage(new KeyExchangeDhGroupExchangeRequest(MinimumGroupSize, PreferredGroupSize, MaximumProupSize)); } /// /// Finishes key exchange algorithm. /// public override void Finish() { base.Finish(); Session.KeyExchangeDhGroupExchangeGroupReceived -= Session_KeyExchangeDhGroupExchangeGroupReceived; Session.KeyExchangeDhGroupExchangeReplyReceived -= Session_KeyExchangeDhGroupExchangeReplyReceived; } private void Session_KeyExchangeDhGroupExchangeGroupReceived(object sender, MessageEventArgs e) { // 2. server sends SSH_MSG_KEX_DH_GEX_GROUP var groupMessage = e.Message; // Unregister SSH_MSG_KEX_DH_GEX_GROUP message once received Session.UnRegisterMessage("SSH_MSG_KEX_DH_GEX_GROUP"); // Unsubscribe from KeyExchangeDhGroupExchangeGroupReceived events Session.KeyExchangeDhGroupExchangeGroupReceived -= Session_KeyExchangeDhGroupExchangeGroupReceived; // Register in order to be able to receive SSH_MSG_KEX_DH_GEX_REPLY message Session.RegisterMessage("SSH_MSG_KEX_DH_GEX_REPLY"); // Subscribe to KeyExchangeDhGroupExchangeReplyReceived events Session.KeyExchangeDhGroupExchangeReplyReceived += Session_KeyExchangeDhGroupExchangeReplyReceived; _prime = groupMessage.SafePrime; _group = groupMessage.SubGroup; PopulateClientExchangeValue(); // 3. client sends SSH_MSG_KEX_DH_GEX_INIT SendMessage(new KeyExchangeDhGroupExchangeInit(_clientExchangeValue)); } private void Session_KeyExchangeDhGroupExchangeReplyReceived(object sender, MessageEventArgs e) { // 4. server sends SSH_MSG_KEX_DH_GEX_REPLY var replyMessage = e.Message; // Unregister SSH_MSG_KEX_DH_GEX_REPLY message once received Session.UnRegisterMessage("SSH_MSG_KEX_DH_GEX_REPLY"); // Unsubscribe from KeyExchangeDhGroupExchangeReplyReceived events Session.KeyExchangeDhGroupExchangeReplyReceived -= Session_KeyExchangeDhGroupExchangeReplyReceived; HandleServerDhReply(replyMessage.HostKey, replyMessage.F, replyMessage.Signature); // When SSH_MSG_KEX_DH_GEX_REPLY received key exchange is completed Finish(); } } }