using System; using System.Text; using Renci.SshNet.Messages.Transport; using Renci.SshNet.Common; namespace Renci.SshNet.Security { /// /// Represents base class for Diffie Hellman key exchange algorithm /// internal abstract class KeyExchangeDiffieHellman : KeyExchange { /// /// Specifies key exchange group number. /// protected BigInteger _group; /// /// Specifies key exchange prime number. /// protected BigInteger _prime; /// /// Specifies client payload /// protected byte[] _clientPayload; /// /// Specifies server payload /// protected byte[] _serverPayload; /// /// Specifies client exchange number. /// protected BigInteger _clientExchangeValue; /// /// Specifies server exchange number. /// protected BigInteger _serverExchangeValue; /// /// Specifies random generated number. /// protected BigInteger _privateExponent; /// /// Specifies host key data. /// protected byte[] _hostKey; /// /// Specifies signature data. /// protected byte[] _signature; /// /// Gets the size, in bits, of the computed hash code. /// /// /// The size, in bits, of the computed hash code. /// protected abstract int HashSize { get; } /// /// Validates the exchange hash. /// /// /// true if exchange hash is valid; otherwise false. /// protected override bool ValidateExchangeHash() { var exchangeHash = CalculateHash(); var length = Pack.BigEndianToUInt32(_hostKey); var algorithmName = Encoding.UTF8.GetString(_hostKey, 4, (int)length); var key = Session.ConnectionInfo.HostKeyAlgorithms[algorithmName](_hostKey); Session.ConnectionInfo.CurrentHostKeyAlgorithm = algorithmName; if (CanTrustHostKey(key)) { return key.VerifySignature(exchangeHash, _signature); } return false; } /// /// Starts key exchange algorithm /// /// The session. /// Key exchange init message. public override void Start(Session session, KeyExchangeInitMessage message) { base.Start(session, message); _serverPayload = message.GetBytes(); _clientPayload = Session.ClientInitMessage.GetBytes(); } /// /// Populates the client exchange value. /// protected void PopulateClientExchangeValue() { if (_group.IsZero) throw new ArgumentNullException("_group"); if (_prime.IsZero) throw new ArgumentNullException("_prime"); // generate private exponent that is twice the hash size (RFC 4419) with a minimum // of 1024 bits (whatever is less) var privateExponentSize = Math.Max(HashSize * 2, 1024); do { // create private component _privateExponent = BigInteger.Random(privateExponentSize); // generate public component _clientExchangeValue = BigInteger.ModPow(_group, _privateExponent, _prime); } while (_clientExchangeValue < 1 || _clientExchangeValue > (_prime - 1)); } /// /// Handles the server DH reply message. /// /// The host key. /// The server exchange value. /// The signature. protected virtual void HandleServerDhReply(byte[] hostKey, BigInteger serverExchangeValue, byte[] signature) { _serverExchangeValue = serverExchangeValue; _hostKey = hostKey; SharedKey = BigInteger.ModPow(serverExchangeValue, _privateExponent, _prime); _signature = signature; } } }