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);
}
}
}