<PackageReference Include="SSH.NET" Version="2025.1.0" />

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 { [System.Runtime.CompilerServices.NullableContext(1)] [System.Runtime.CompilerServices.Nullable(0)] public class KeyExchangeDiffieHellmanGroupExchange : KeyExchange { [System.Runtime.CompilerServices.Nullable(2)] private byte[] _clientPayload; [System.Runtime.CompilerServices.Nullable(2)] private byte[] _serverPayload; [System.Runtime.CompilerServices.Nullable(2)] private byte[] _clientExchangeValue; [System.Runtime.CompilerServices.Nullable(2)] private byte[] _serverExchangeValue; [System.Runtime.CompilerServices.Nullable(2)] private byte[] _prime; [System.Runtime.CompilerServices.Nullable(2)] private byte[] _group; [System.Runtime.CompilerServices.Nullable(2)] private byte[] _hostKey; [System.Runtime.CompilerServices.Nullable(2)] private byte[] _signature; private readonly HashAlgorithm _hash; private readonly int _hashLengthInBits; private readonly uint _minimumGroupSize; private readonly uint _preferredGroupSize; private readonly uint _maximumGroupSize; [System.Runtime.CompilerServices.Nullable(2)] private DHParameters _dhParameters; [System.Runtime.CompilerServices.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; HashAlgorithm obj = CryptoConfig.CreateFromName(hashAlgorithm.Name) as HashAlgorithm; if (obj == null) throw new ArgumentException(string.Format("Could not create {0} from `{1}`.", "HashAlgorithm", hashAlgorithm), "hashAlgorithm"); _hash = obj; _hashLengthInBits = _hash.HashSize; } 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([System.Runtime.CompilerServices.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([System.Runtime.CompilerServices.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) { return _hash.ComputeHash(hashData); } protected override void Dispose(bool disposing) { if (disposing) _hash.Dispose(); base.Dispose(disposing); } } }