diff --git a/src/Renci.SshNet/ConnectionInfo.cs b/src/Renci.SshNet/ConnectionInfo.cs index dce02ada2..80e071906 100644 --- a/src/Renci.SshNet/ConnectionInfo.cs +++ b/src/Renci.SshNet/ConnectionInfo.cs @@ -5,6 +5,8 @@ using System.Security.Cryptography; using System.Text; +using Org.BouncyCastle.Crypto.Agreement; + using Renci.SshNet.Common; using Renci.SshNet.Compression; using Renci.SshNet.Messages.Authentication; @@ -355,12 +357,13 @@ public ConnectionInfo(string host, int port, string username, ProxyTypes proxyTy { "ecdh-sha2-nistp256", () => new KeyExchangeECDH256() }, { "ecdh-sha2-nistp384", () => new KeyExchangeECDH384() }, { "ecdh-sha2-nistp521", () => new KeyExchangeECDH521() }, - { "diffie-hellman-group-exchange-sha256", () => new KeyExchangeDiffieHellmanGroupExchangeSha256() }, - { "diffie-hellman-group-exchange-sha1", () => new KeyExchangeDiffieHellmanGroupExchangeSha1() }, - { "diffie-hellman-group16-sha512", () => new KeyExchangeDiffieHellmanGroup16Sha512() }, - { "diffie-hellman-group14-sha256", () => new KeyExchangeDiffieHellmanGroup14Sha256() }, - { "diffie-hellman-group14-sha1", () => new KeyExchangeDiffieHellmanGroup14Sha1() }, - { "diffie-hellman-group1-sha1", () => new KeyExchangeDiffieHellmanGroup1Sha1() }, + { "diffie-hellman-group-exchange-sha256", () => new KeyExchangeDiffieHellmanGroupExchange("diffie-hellman-group-exchange-sha256", HashAlgorithmName.SHA256) }, + { "diffie-hellman-group16-sha512", () => new KeyExchangeDiffieHellman("diffie-hellman-group16-sha512", DHStandardGroups.rfc3526_4096, HashAlgorithmName.SHA512) }, + { "diffie-hellman-group18-sha512", () => new KeyExchangeDiffieHellman("diffie-hellman-group18-sha512", DHStandardGroups.rfc3526_8192, HashAlgorithmName.SHA512) }, + { "diffie-hellman-group14-sha256", () => new KeyExchangeDiffieHellman("diffie-hellman-group14-sha256", DHStandardGroups.rfc3526_2048, HashAlgorithmName.SHA256) }, + { "diffie-hellman-group-exchange-sha1", () => new KeyExchangeDiffieHellmanGroupExchange("diffie-hellman-group-exchange-sha1", HashAlgorithmName.SHA1) }, + { "diffie-hellman-group14-sha1", () => new KeyExchangeDiffieHellman("diffie-hellman-group14-sha1", DHStandardGroups.rfc3526_2048, HashAlgorithmName.SHA1) }, + { "diffie-hellman-group1-sha1", () => new KeyExchangeDiffieHellman("diffie-hellman-group1-sha1", DHStandardGroups.rfc2409_1024, HashAlgorithmName.SHA1) }, }; Encryptions = new OrderedDictionary diff --git a/src/Renci.SshNet/Messages/Transport/KeyExchangeDhGroupExchangeGroup.cs b/src/Renci.SshNet/Messages/Transport/KeyExchangeDhGroupExchangeGroup.cs index f2cb1eb4c..129b10206 100644 --- a/src/Renci.SshNet/Messages/Transport/KeyExchangeDhGroupExchangeGroup.cs +++ b/src/Renci.SshNet/Messages/Transport/KeyExchangeDhGroupExchangeGroup.cs @@ -9,8 +9,8 @@ namespace Renci.SshNet.Messages.Transport /// public class KeyExchangeDhGroupExchangeGroup : Message { - private byte[] _safePrime; - private byte[] _subGroup; + internal byte[] SafePrimeBytes { get; private set; } + internal byte[] SubGroupBytes { get; private set; } /// public override string MessageName @@ -38,7 +38,7 @@ public override byte MessageNumber /// public BigInteger SafePrime { - get { return _safePrime.ToBigInteger(); } + get { return SafePrimeBytes.ToBigInteger(); } } /// @@ -49,7 +49,7 @@ public BigInteger SafePrime /// public BigInteger SubGroup { - get { return _subGroup.ToBigInteger(); } + get { return SubGroupBytes.ToBigInteger(); } } /// @@ -64,9 +64,9 @@ protected override int BufferCapacity { var capacity = base.BufferCapacity; capacity += 4; // SafePrime length - capacity += _safePrime.Length; // SafePrime + capacity += SafePrimeBytes.Length; // SafePrime capacity += 4; // SubGroup length - capacity += _subGroup.Length; // SubGroup + capacity += SubGroupBytes.Length; // SubGroup return capacity; } @@ -77,8 +77,8 @@ protected override int BufferCapacity /// protected override void LoadData() { - _safePrime = ReadBinary(); - _subGroup = ReadBinary(); + SafePrimeBytes = ReadBinary(); + SubGroupBytes = ReadBinary(); } /// @@ -86,8 +86,8 @@ protected override void LoadData() /// protected override void SaveData() { - WriteBinaryString(_safePrime); - WriteBinaryString(_subGroup); + WriteBinaryString(SafePrimeBytes); + WriteBinaryString(SubGroupBytes); } internal override void Process(Session session) diff --git a/src/Renci.SshNet/Security/GroupExchangeHashData.cs b/src/Renci.SshNet/Security/GroupExchangeHashData.cs index 9f9bee54c..55d95a0d3 100644 --- a/src/Renci.SshNet/Security/GroupExchangeHashData.cs +++ b/src/Renci.SshNet/Security/GroupExchangeHashData.cs @@ -1,5 +1,4 @@ using System; -using System.Numerics; using Renci.SshNet.Common; @@ -9,8 +8,6 @@ internal sealed class GroupExchangeHashData : SshData { private byte[] _serverVersion; private byte[] _clientVersion; - private byte[] _prime; - private byte[] _subGroup; public string ServerVersion { @@ -36,17 +33,9 @@ public string ClientVersion public uint MaximumGroupSize { get; set; } - public BigInteger Prime - { - private get { return _prime.ToBigInteger(); } - set { _prime = value.ToByteArray(isBigEndian: true); } - } + public byte[] Prime { get; set; } - public BigInteger SubGroup - { - private get { return _subGroup.ToBigInteger(); } - set { _subGroup = value.ToByteArray(isBigEndian: true); } - } + public byte[] SubGroup { get; set; } public byte[] ClientExchangeValue { get; set; } @@ -79,9 +68,9 @@ protected override int BufferCapacity capacity += 4; // PreferredGroupSize capacity += 4; // MaximumGroupSize capacity += 4; // Prime length - capacity += _prime.Length; // Prime + capacity += Prime.Length; // Prime capacity += 4; // SubGroup length - capacity += _subGroup.Length; // SubGroup + capacity += SubGroup.Length; // SubGroup capacity += 4; // ClientExchangeValue length capacity += ClientExchangeValue.Length; // ClientExchangeValue capacity += 4; // ServerExchangeValue length @@ -107,8 +96,8 @@ protected override void SaveData() Write(MinimumGroupSize); Write(PreferredGroupSize); Write(MaximumGroupSize); - WriteBinaryString(_prime); - WriteBinaryString(_subGroup); + WriteBinaryString(Prime); + WriteBinaryString(SubGroup); WriteBinaryString(ClientExchangeValue); WriteBinaryString(ServerExchangeValue); WriteBinaryString(SharedKey); diff --git a/src/Renci.SshNet/Security/KeyExchange.cs b/src/Renci.SshNet/Security/KeyExchange.cs index dc4421560..7c3c6525a 100644 --- a/src/Renci.SshNet/Security/KeyExchange.cs +++ b/src/Renci.SshNet/Security/KeyExchange.cs @@ -482,7 +482,7 @@ protected bool CanTrustHostKey(KeyHostAlgorithm host) /// /// Validates the exchange hash. /// - /// true if exchange hash is valid; otherwise false. + /// if exchange hash is valid; otherwise . protected abstract bool ValidateExchangeHash(); private protected bool ValidateExchangeHash(byte[] encodedKey, byte[] encodedSignature) diff --git a/src/Renci.SshNet/Security/KeyExchangeDiffieHellman.cs b/src/Renci.SshNet/Security/KeyExchangeDiffieHellman.cs index 35ffb971a..c9e31e9ac 100644 --- a/src/Renci.SshNet/Security/KeyExchangeDiffieHellman.cs +++ b/src/Renci.SshNet/Security/KeyExchangeDiffieHellman.cs @@ -1,5 +1,10 @@ -using System; -using System.Numerics; +#nullable enable +using System; +using System.Security.Cryptography; + +using Org.BouncyCastle.Crypto.Agreement; +using Org.BouncyCastle.Crypto.Generators; +using Org.BouncyCastle.Crypto.Parameters; using Renci.SshNet.Abstractions; using Renci.SshNet.Common; @@ -8,74 +13,65 @@ namespace Renci.SshNet.Security { /// - /// Represents base class for Diffie Hellman key exchange algorithm. + /// Provides the implementation of "diffie-hellman-groupN" algorithms. /// - internal abstract class KeyExchangeDiffieHellman : KeyExchange + public class KeyExchangeDiffieHellman : KeyExchange { -#pragma warning disable SA1401 // Fields should be private - /// - /// Specifies key exchange group number. - /// - protected BigInteger _group; - - /// - /// Specifies key exchange prime number. - /// - protected BigInteger _prime; - - /// - /// Specifies client payload. - /// - protected byte[] _clientPayload; + private byte[]? _clientPayload; + private byte[]? _serverPayload; + private byte[]? _clientExchangeValue; + private byte[]? _serverExchangeValue; + private byte[]? _hostKey; + private byte[]? _signature; - /// - /// Specifies server payload. - /// - protected byte[] _serverPayload; - - /// - /// Specifies client exchange number. - /// - protected byte[] _clientExchangeValue; - - /// - /// Specifies server exchange number. - /// - protected byte[] _serverExchangeValue; - - /// - /// Specifies random generated number. - /// - protected BigInteger _privateExponent; - - /// - /// Specifies host key data. - /// - protected byte[] _hostKey; + /// + public override string Name { get; } - /// - /// Specifies signature data. - /// - protected byte[] _signature; -#pragma warning restore SA1401 // Fields should be private + private readonly DHParameters _dhParameters; +#if NET462 + private readonly HashAlgorithm _hash; +#else + private readonly IncrementalHash _hash; +#endif - /// - /// Gets the size, in bits, of the computed hash code. - /// - /// - /// The size, in bits, of the computed hash code. - /// - protected abstract int HashSize { get; } + private DHBasicAgreement? _keyAgreement; /// - /// Validates the exchange hash. + /// Initializes a new instance of the class. /// - /// - /// true if exchange hash is valid; otherwise false. - /// - protected override bool ValidateExchangeHash() + /// The name of the key exchange algorithm. + /// The Diffie-Hellman parameters to be used. + /// The hash algorithm to be used. + /// + /// , , or is . + /// + /// + /// is not a valid hash algorithm. + /// + public KeyExchangeDiffieHellman( + string name, + DHParameters parameters, + HashAlgorithmName hashAlgorithm) { - return ValidateExchangeHash(_hostKey, _signature); + ThrowHelper.ThrowIfNull(name); + ThrowHelper.ThrowIfNull(parameters); + ThrowHelper.ThrowIfNullOrEmpty(hashAlgorithm.Name, nameof(hashAlgorithm)); + + Name = name; + _dhParameters = parameters; +#if NET462 + _hash = CryptoConfig.CreateFromName(hashAlgorithm.Name) as HashAlgorithm + ?? throw new ArgumentException($"Could not create {nameof(HashAlgorithm)} from `{hashAlgorithm}`.", nameof(hashAlgorithm)); +#else + try + { + _hash = IncrementalHash.CreateHash(hashAlgorithm); + } + catch (CryptographicException cex) + { + throw new ArgumentException($"Could not create {nameof(HashAlgorithm)} from `{hashAlgorithm}`.", nameof(hashAlgorithm), cex); + } +#endif } /// @@ -85,66 +81,86 @@ public override void Start(Session session, KeyExchangeInitMessage message, bool _serverPayload = message.GetBytes(); _clientPayload = Session.ClientInitMessage.GetBytes(); + + var g = new DHKeyPairGenerator(); + g.Init(new DHKeyGenerationParameters(CryptoAbstraction.SecureRandom, _dhParameters)); + + var aKeyPair = g.GenerateKeyPair(); + + _keyAgreement = new DHBasicAgreement(); + _keyAgreement.Init(aKeyPair.Private); + _clientExchangeValue = ((DHPublicKeyParameters)aKeyPair.Public).Y.ToByteArray(); + + Session.RegisterMessage("SSH_MSG_KEXDH_REPLY"); + + Session.KeyExchangeDhReplyMessageReceived += Session_KeyExchangeDhReplyMessageReceived; + + SendMessage(new KeyExchangeDhInitMessage(_clientExchangeValue)); } - /// - /// Populates the client exchange value. - /// - protected void PopulateClientExchangeValue() + /// + protected override byte[] CalculateHash() { - if (_group.IsZero) + var keyExchangeHashData = new KeyExchangeHashData { - throw new ArgumentNullException("_group"); - } + ClientVersion = Session.ClientVersion, + ServerVersion = Session.ServerVersion, + ClientPayload = _clientPayload, + ServerPayload = _serverPayload, + HostKey = _hostKey, + ClientExchangeValue = _clientExchangeValue, + ServerExchangeValue = _serverExchangeValue, + SharedKey = SharedKey, + }; + + return Hash(keyExchangeHashData.GetBytes()); + } - if (_prime.IsZero) - { - throw new ArgumentNullException("_prime"); - } + private void Session_KeyExchangeDhReplyMessageReceived(object? sender, MessageEventArgs e) + { + var message = e.Message; - // 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); + Session.KeyExchangeDhReplyMessageReceived -= Session_KeyExchangeDhReplyMessageReceived; - BigInteger clientExchangeValue; + Session.UnRegisterMessage("SSH_MSG_KEXDH_REPLY"); - do - { - // Create private component - _privateExponent = RandomBigInt(privateExponentSize); + _serverExchangeValue = message.F; + _hostKey = message.HostKey; + _signature = message.Signature; - // Generate public component - clientExchangeValue = BigInteger.ModPow(_group, _privateExponent, _prime); - } - while (clientExchangeValue < 1 || clientExchangeValue > (_prime - 1)); + var publicKey = new DHPublicKeyParameters(new Org.BouncyCastle.Math.BigInteger(message.F), _dhParameters); - _clientExchangeValue = clientExchangeValue.ToByteArray(isBigEndian: true); + SharedKey = _keyAgreement!.CalculateAgreement(publicKey).ToByteArray(); + + Finish(); } - /// - /// Generates a new, random of the specified length. - /// - /// The number of bits for the new number. - /// A random number of the specified length. - private static BigInteger RandomBigInt(int bitLength) + /// + protected override bool ValidateExchangeHash() { - var bytesArray = CryptoAbstraction.GenerateRandom((bitLength / 8) + (((bitLength % 8) > 0) ? 1 : 0)); - bytesArray[bytesArray.Length - 1] = (byte)(bytesArray[bytesArray.Length - 1] & 0x7F); // Ensure not a negative value - return new BigInteger(bytesArray); + return ValidateExchangeHash(_hostKey, _signature); } - /// - /// Handles the server DH reply message. - /// - /// The host key. - /// The server exchange value. - /// The signature. - protected virtual void HandleServerDhReply(byte[] hostKey, byte[] serverExchangeValue, byte[] signature) + /// + protected override byte[] Hash(byte[] hashData) + { +#if NET462 + return _hash.ComputeHash(hashData); +#else + _hash.AppendData(hashData); + return _hash.GetHashAndReset(); +#endif + } + + /// + protected override void Dispose(bool disposing) { - _serverExchangeValue = serverExchangeValue; - _hostKey = hostKey; - SharedKey = BigInteger.ModPow(serverExchangeValue.ToBigInteger(), _privateExponent, _prime).ToByteArray(isBigEndian: true); - _signature = signature; + if (disposing) + { + _hash.Dispose(); + } + + base.Dispose(disposing); } } } diff --git a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroup14Sha1.cs b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroup14Sha1.cs deleted file mode 100644 index d328cd5ae..000000000 --- a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroup14Sha1.cs +++ /dev/null @@ -1,62 +0,0 @@ -using System.Numerics; - -namespace Renci.SshNet.Security -{ - /// - /// Represents "diffie-hellman-group14-sha1" algorithm implementation. - /// - internal sealed class KeyExchangeDiffieHellmanGroup14Sha1 : KeyExchangeDiffieHellmanGroupSha1 - { - /// - /// Defined in https://tools.ietf.org/html/rfc2409#section-6.2. - /// - private static readonly BigInteger SecondOkleyGroupReversed = new BigInteger( - [ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x68, 0xaa, 0xac, 0x8a, - 0x5a, 0x8e, 0x72, 0x15, 0x10, 0x05, 0xfa, 0x98, 0x18, 0x26, 0xd2, 0x15, - 0xe5, 0x6a, 0x95, 0xea, 0x7c, 0x49, 0x95, 0x39, 0x18, 0x17, 0x58, 0x95, - 0xf6, 0xcb, 0x2b, 0xde, 0xc9, 0x52, 0x4c, 0x6f, 0xf0, 0x5d, 0xc5, 0xb5, - 0x8f, 0xa2, 0x07, 0xec, 0xa2, 0x83, 0x27, 0x9b, 0x03, 0x86, 0x0e, 0x18, - 0x2c, 0x77, 0x9e, 0xe3, 0x3b, 0xce, 0x36, 0x2e, 0x46, 0x5e, 0x90, 0x32, - 0x7c, 0x21, 0x18, 0xca, 0x08, 0x6c, 0x74, 0xf1, 0x04, 0x98, 0xbc, 0x4a, - 0x4e, 0x35, 0x0c, 0x67, 0x6d, 0x96, 0x96, 0x70, 0x07, 0x29, 0xd5, 0x9e, - 0xbb, 0x52, 0x85, 0x20, 0x56, 0xf3, 0x62, 0x1c, 0x96, 0xad, 0xa3, 0xdc, - 0x23, 0x5d, 0x65, 0x83, 0x5f, 0xcf, 0x24, 0xfd, 0xa8, 0x3f, 0x16, 0x69, - 0x9a, 0xd3, 0x55, 0x1c, 0x36, 0x48, 0xda, 0x98, 0x05, 0xbf, 0x63, 0xa1, - 0xb8, 0x7c, 0x00, 0xc2, 0x3d, 0x5b, 0xe4, 0xec, 0x51, 0x66, 0x28, 0x49, - 0xe6, 0x1f, 0x4b, 0x7c, 0x11, 0x24, 0x9f, 0xae, 0xa5, 0x9f, 0x89, 0x5a, - 0xfb, 0x6b, 0x38, 0xee, 0xed, 0xb7, 0x06, 0xf4, 0xb6, 0x5c, 0xff, 0x0b, - 0x6b, 0xed, 0x37, 0xa6, 0xe9, 0x42, 0x4c, 0xf4, 0xc6, 0x7e, 0x5e, 0x62, - 0x76, 0xb5, 0x85, 0xe4, 0x45, 0xc2, 0x51, 0x6d, 0x6d, 0x35, 0xe1, 0x4f, - 0x37, 0x14, 0x5f, 0xf2, 0x6d, 0x0a, 0x2b, 0x30, 0x1b, 0x43, 0x3a, 0xcd, - 0xb3, 0x19, 0x95, 0xef, 0xdd, 0x04, 0x34, 0x8e, 0x79, 0x08, 0x4a, 0x51, - 0x22, 0x9b, 0x13, 0x3b, 0xa6, 0xbe, 0x0b, 0x02, 0x74, 0xcc, 0x67, 0x8a, - 0x08, 0x4e, 0x02, 0x29, 0xd1, 0x1c, 0xdc, 0x80, 0x8b, 0x62, 0xc6, 0xc4, - 0x34, 0xc2, 0x68, 0x21, 0xa2, 0xda, 0x0f, 0xc9, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0x00 - ]); - - /// - /// Gets algorithm name. - /// - public override string Name - { - get { return "diffie-hellman-group14-sha1"; } - } - - /// - /// Gets the group prime. - /// - /// - /// The group prime. - /// - public override BigInteger GroupPrime - { - get - { - return SecondOkleyGroupReversed; - } - } - } -} diff --git a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroup14Sha256.cs b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroup14Sha256.cs deleted file mode 100644 index ab8a9cef6..000000000 --- a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroup14Sha256.cs +++ /dev/null @@ -1,62 +0,0 @@ -using System.Numerics; - -namespace Renci.SshNet.Security -{ - /// - /// Represents "diffie-hellman-group14-sha256" algorithm implementation. - /// - internal sealed class KeyExchangeDiffieHellmanGroup14Sha256 : KeyExchangeDiffieHellmanGroupSha256 - { - /// - /// Defined in https://tools.ietf.org/html/rfc2409#section-6.2. - /// - private static readonly BigInteger SecondOkleyGroupReversed = new BigInteger( - [ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x68, 0xaa, 0xac, 0x8a, - 0x5a, 0x8e, 0x72, 0x15, 0x10, 0x05, 0xfa, 0x98, 0x18, 0x26, 0xd2, 0x15, - 0xe5, 0x6a, 0x95, 0xea, 0x7c, 0x49, 0x95, 0x39, 0x18, 0x17, 0x58, 0x95, - 0xf6, 0xcb, 0x2b, 0xde, 0xc9, 0x52, 0x4c, 0x6f, 0xf0, 0x5d, 0xc5, 0xb5, - 0x8f, 0xa2, 0x07, 0xec, 0xa2, 0x83, 0x27, 0x9b, 0x03, 0x86, 0x0e, 0x18, - 0x2c, 0x77, 0x9e, 0xe3, 0x3b, 0xce, 0x36, 0x2e, 0x46, 0x5e, 0x90, 0x32, - 0x7c, 0x21, 0x18, 0xca, 0x08, 0x6c, 0x74, 0xf1, 0x04, 0x98, 0xbc, 0x4a, - 0x4e, 0x35, 0x0c, 0x67, 0x6d, 0x96, 0x96, 0x70, 0x07, 0x29, 0xd5, 0x9e, - 0xbb, 0x52, 0x85, 0x20, 0x56, 0xf3, 0x62, 0x1c, 0x96, 0xad, 0xa3, 0xdc, - 0x23, 0x5d, 0x65, 0x83, 0x5f, 0xcf, 0x24, 0xfd, 0xa8, 0x3f, 0x16, 0x69, - 0x9a, 0xd3, 0x55, 0x1c, 0x36, 0x48, 0xda, 0x98, 0x05, 0xbf, 0x63, 0xa1, - 0xb8, 0x7c, 0x00, 0xc2, 0x3d, 0x5b, 0xe4, 0xec, 0x51, 0x66, 0x28, 0x49, - 0xe6, 0x1f, 0x4b, 0x7c, 0x11, 0x24, 0x9f, 0xae, 0xa5, 0x9f, 0x89, 0x5a, - 0xfb, 0x6b, 0x38, 0xee, 0xed, 0xb7, 0x06, 0xf4, 0xb6, 0x5c, 0xff, 0x0b, - 0x6b, 0xed, 0x37, 0xa6, 0xe9, 0x42, 0x4c, 0xf4, 0xc6, 0x7e, 0x5e, 0x62, - 0x76, 0xb5, 0x85, 0xe4, 0x45, 0xc2, 0x51, 0x6d, 0x6d, 0x35, 0xe1, 0x4f, - 0x37, 0x14, 0x5f, 0xf2, 0x6d, 0x0a, 0x2b, 0x30, 0x1b, 0x43, 0x3a, 0xcd, - 0xb3, 0x19, 0x95, 0xef, 0xdd, 0x04, 0x34, 0x8e, 0x79, 0x08, 0x4a, 0x51, - 0x22, 0x9b, 0x13, 0x3b, 0xa6, 0xbe, 0x0b, 0x02, 0x74, 0xcc, 0x67, 0x8a, - 0x08, 0x4e, 0x02, 0x29, 0xd1, 0x1c, 0xdc, 0x80, 0x8b, 0x62, 0xc6, 0xc4, - 0x34, 0xc2, 0x68, 0x21, 0xa2, 0xda, 0x0f, 0xc9, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0x00 - ]); - - /// - /// Gets algorithm name. - /// - public override string Name - { - get { return "diffie-hellman-group14-sha256"; } - } - - /// - /// Gets the group prime. - /// - /// - /// The group prime. - /// - public override BigInteger GroupPrime - { - get - { - return SecondOkleyGroupReversed; - } - } - } -} diff --git a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroup16Sha512.cs b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroup16Sha512.cs deleted file mode 100644 index e212821e5..000000000 --- a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroup16Sha512.cs +++ /dev/null @@ -1,66 +0,0 @@ -using System.Numerics; - -namespace Renci.SshNet.Security -{ - /// - /// Represents "diffie-hellman-group16-sha512" algorithm implementation. - /// - internal sealed class KeyExchangeDiffieHellmanGroup16Sha512 : KeyExchangeDiffieHellmanGroupSha512 - { - /// - /// Defined in https://tools.ietf.org/html/rfc3526#section-5. - /// - private static readonly BigInteger MoreModularExponentialGroup16Reversed = new BigInteger( - [ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x99, 0x31, 0x06, 0x34, 0xc9, 0x35, 0xf4, 0x4d, - 0x8f, 0xc0, 0xa6, 0x90, 0xdc, 0xb7, 0xff, 0x86, 0xc1, 0xdd, 0x8f, 0x8d, 0x98, 0xea, 0xb4, 0x93, - 0xa9, 0x5a, 0xb0, 0xd5, 0x27, 0x91, 0x06, 0xd0, 0x1c, 0x48, 0x70, 0x21, 0x76, 0xdd, 0x1b, 0xb8, - 0xaf, 0xd7, 0xe2, 0xce, 0x70, 0x29, 0x61, 0x1f, 0xed, 0xe7, 0x5b, 0x51, 0x86, 0xa1, 0x3b, 0x23, - 0xa2, 0xc3, 0x90, 0xa0, 0x4f, 0x96, 0xb2, 0x99, 0x5d, 0xc0, 0x6b, 0x4e, 0x47, 0x59, 0x7c, 0x28, - 0xa6, 0xca, 0xbe, 0x1f, 0x14, 0xfc, 0x8e, 0x2e, 0xf9, 0x8e, 0xde, 0x04, 0xdb, 0xc2, 0xbb, 0xdb, - 0xe8, 0x4c, 0xd4, 0x2a, 0xca, 0xe9, 0x83, 0x25, 0xda, 0x0b, 0x15, 0xb6, 0x34, 0x68, 0x94, 0x1a, - 0x3c, 0xe2, 0xf4, 0x6a, 0x18, 0x27, 0xc3, 0x99, 0x26, 0x5b, 0xba, 0xbd, 0x10, 0x9a, 0x71, 0x88, - 0xd7, 0xe6, 0x87, 0xa7, 0x12, 0x3c, 0x72, 0x1a, 0x01, 0x08, 0x21, 0xa9, 0x20, 0xd1, 0x82, 0x4b, - 0x8e, 0x10, 0xfd, 0xe0, 0xfc, 0x5b, 0xdb, 0x43, 0x31, 0xab, 0xe5, 0x74, 0xa0, 0x4f, 0xe2, 0x08, - 0xe2, 0x46, 0xd9, 0xba, 0xc0, 0x88, 0x09, 0x77, 0x6c, 0x5d, 0x61, 0x7a, 0x57, 0x17, 0xe1, 0xbb, - 0x0c, 0x20, 0x7b, 0x17, 0x18, 0x2b, 0x1f, 0x52, 0x64, 0x6a, 0xc8, 0x3e, 0x73, 0x02, 0x76, 0xd8, - 0x64, 0x08, 0x8a, 0xd9, 0x06, 0xfa, 0x2f, 0xf1, 0x6b, 0xee, 0xd2, 0x1a, 0x26, 0xd2, 0xe3, 0xce, - 0x9d, 0x61, 0x25, 0x4a, 0xe0, 0x94, 0x8c, 0x1e, 0xd7, 0x33, 0x09, 0xdb, 0x8c, 0xae, 0xf5, 0xab, - 0xc7, 0xe4, 0xe1, 0xa6, 0x85, 0x0f, 0x97, 0xb3, 0x7d, 0x0c, 0x06, 0x5d, 0x57, 0x71, 0xea, 0x8a, - 0x0a, 0xef, 0xdb, 0x58, 0x04, 0x85, 0xfb, 0xec, 0x64, 0xba, 0x1c, 0xdf, 0xab, 0x21, 0x55, 0xa8, - 0x33, 0x7a, 0x50, 0x04, 0x0d, 0x17, 0x33, 0xad, 0x2d, 0xc4, 0xaa, 0x8a, 0x5a, 0x8e, 0x72, 0x15, - 0x10, 0x05, 0xfa, 0x98, 0x18, 0x26, 0xd2, 0x15, 0xe5, 0x6a, 0x95, 0xea, 0x7c, 0x49, 0x95, 0x39, - 0x18, 0x17, 0x58, 0x95, 0xf6, 0xcb, 0x2b, 0xde, 0xc9, 0x52, 0x4c, 0x6f, 0xf0, 0x5d, 0xc5, 0xb5, - 0x8f, 0xa2, 0x07, 0xec, 0xa2, 0x83, 0x27, 0x9b, 0x03, 0x86, 0x0e, 0x18, 0x2c, 0x77, 0x9e, 0xe3, - 0x3b, 0xce, 0x36, 0x2e, 0x46, 0x5e, 0x90, 0x32, 0x7c, 0x21, 0x18, 0xca, 0x08, 0x6c, 0x74, 0xf1, - 0x04, 0x98, 0xbc, 0x4a, 0x4e, 0x35, 0x0c, 0x67, 0x6d, 0x96, 0x96, 0x70, 0x07, 0x29, 0xd5, 0x9e, - 0xbb, 0x52, 0x85, 0x20, 0x56, 0xf3, 0x62, 0x1c, 0x96, 0xad, 0xa3, 0xdc, 0x23, 0x5d, 0x65, 0x83, - 0x5f, 0xcf, 0x24, 0xfd, 0xa8, 0x3f, 0x16, 0x69, 0x9a, 0xd3, 0x55, 0x1c, 0x36, 0x48, 0xda, 0x98, - 0x05, 0xbf, 0x63, 0xa1, 0xb8, 0x7c, 0x00, 0xc2, 0x3d, 0x5b, 0xe4, 0xec, 0x51, 0x66, 0x28, 0x49, - 0xe6, 0x1f, 0x4b, 0x7c, 0x11, 0x24, 0x9f, 0xae, 0xa5, 0x9f, 0x89, 0x5a, 0xfb, 0x6b, 0x38, 0xee, - 0xed, 0xb7, 0x06, 0xf4, 0xb6, 0x5c, 0xff, 0x0b, 0x6b, 0xed, 0x37, 0xa6, 0xe9, 0x42, 0x4c, 0xf4, - 0xc6, 0x7e, 0x5e, 0x62, 0x76, 0xb5, 0x85, 0xe4, 0x45, 0xc2, 0x51, 0x6d, 0x6d, 0x35, 0xe1, 0x4f, - 0x37, 0x14, 0x5f, 0xf2, 0x6d, 0x0a, 0x2b, 0x30, 0x1b, 0x43, 0x3a, 0xcd, 0xb3, 0x19, 0x95, 0xef, - 0xdd, 0x04, 0x34, 0x8e, 0x79, 0x08, 0x4a, 0x51, 0x22, 0x9b, 0x13, 0x3b, 0xa6, 0xbe, 0x0b, 0x02, - 0x74, 0xcc, 0x67, 0x8a, 0x08, 0x4e, 0x02, 0x29, 0xd1, 0x1c, 0xdc, 0x80, 0x8b, 0x62, 0xc6, 0xc4, - 0x34, 0xc2, 0x68, 0x21, 0xa2, 0xda, 0x0f, 0xc9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00 - ]); - - public override BigInteger GroupPrime - { - get - { - return MoreModularExponentialGroup16Reversed; - } - } - - /// - /// Gets algorithm name. - /// - public override string Name - { - get { return "diffie-hellman-group16-sha512"; } - } - } -} diff --git a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroup1Sha1.cs b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroup1Sha1.cs deleted file mode 100644 index 1319c54df..000000000 --- a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroup1Sha1.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System.Numerics; - -namespace Renci.SshNet.Security -{ - /// - /// Represents "diffie-hellman-group1-sha1" algorithm implementation. - /// - internal sealed class KeyExchangeDiffieHellmanGroup1Sha1 : KeyExchangeDiffieHellmanGroupSha1 - { - private static readonly BigInteger SecondOkleyGroupReversed = new BigInteger( - [ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x81, 0x53, 0xe6, 0xec, - 0x51, 0x66, 0x28, 0x49, 0xe6, 0x1f, 0x4b, 0x7c, 0x11, 0x24, 0x9f, 0xae, - 0xa5, 0x9f, 0x89, 0x5a, 0xfb, 0x6b, 0x38, 0xee, 0xed, 0xb7, 0x06, 0xf4, - 0xb6, 0x5c, 0xff, 0x0b, 0x6b, 0xed, 0x37, 0xa6, 0xe9, 0x42, 0x4c, 0xf4, - 0xc6, 0x7e, 0x5e, 0x62, 0x76, 0xb5, 0x85, 0xe4, 0x45, 0xc2, 0x51, 0x6d, - 0x6d, 0x35, 0xe1, 0x4f, 0x37, 0x14, 0x5f, 0xf2, 0x6d, 0x0a, 0x2b, 0x30, - 0x1b, 0x43, 0x3a, 0xcd, 0xb3, 0x19, 0x95, 0xef, 0xdd, 0x04, 0x34, 0x8e, - 0x79, 0x08, 0x4a, 0x51, 0x22, 0x9b, 0x13, 0x3b, 0xa6, 0xbe, 0x0b, 0x02, - 0x74, 0xcc, 0x67, 0x8a, 0x08, 0x4e, 0x02, 0x29, 0xd1, 0x1c, 0xdc, 0x80, - 0x8b, 0x62, 0xc6, 0xc4, 0x34, 0xc2, 0x68, 0x21, 0xa2, 0xda, 0x0f, 0xc9, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00 - ]); - - /// - /// Gets algorithm name. - /// - public override string Name - { - get { return "diffie-hellman-group1-sha1"; } - } - - /// - /// Gets the group prime. - /// - /// - /// The group prime. - /// - public override BigInteger GroupPrime - { - get - { - return SecondOkleyGroupReversed; - } - } - } -} diff --git a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchange.cs b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchange.cs new file mode 100644 index 000000000..0a9d46579 --- /dev/null +++ b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchange.cs @@ -0,0 +1,244 @@ +#nullable enable +using System; +using System.Security.Cryptography; + +using Org.BouncyCastle.Crypto.Agreement; +using Org.BouncyCastle.Crypto.Generators; +using Org.BouncyCastle.Crypto.Parameters; + +using Renci.SshNet.Abstractions; +using Renci.SshNet.Common; +using Renci.SshNet.Messages.Transport; + +namespace Renci.SshNet.Security +{ + /// + /// Provides the implementation of "diffie-hellman-group-exchange" algorithms. + /// + public class KeyExchangeDiffieHellmanGroupExchange : KeyExchange + { + private byte[]? _clientPayload; + private byte[]? _serverPayload; + private byte[]? _clientExchangeValue; + private byte[]? _serverExchangeValue; + private byte[]? _prime; + private byte[]? _group; + private byte[]? _hostKey; + private byte[]? _signature; + + /// + public override string Name { get; } +#if NET + private readonly IncrementalHash _hash; +#else + private readonly HashAlgorithm _hash; +#endif + private readonly int _hashLengthInBits; + private readonly uint _minimumGroupSize; + private readonly uint _preferredGroupSize; + private readonly uint _maximumGroupSize; + + private DHParameters? _dhParameters; + private DHBasicAgreement? _keyAgreement; + + /// + /// Initializes a new instance of the class. + /// + /// The name of the key exchange algorithm. + /// The hash algorithm to be used. + /// + /// or is . + /// + /// + /// is not a valid hash algorithm. + /// + public KeyExchangeDiffieHellmanGroupExchange( + string name, + HashAlgorithmName hashAlgorithm) + : this(name, hashAlgorithm, 2048, 4096, 8192) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The name of the key exchange algorithm. + /// The hash algorithm to be used. + /// The minimum size in bits of an acceptable group. + /// The preferred size in bits of an acceptable group. + /// The maximum size in bits of an acceptable group. + /// + /// or is . + /// + /// + /// is not a valid hash algorithm. + /// + /// + /// is not between and . + /// + public KeyExchangeDiffieHellmanGroupExchange( + string name, + HashAlgorithmName hashAlgorithm, + uint minimumGroupSize, + uint preferredGroupSize, + uint maximumGroupSize) + { + ThrowHelper.ThrowIfNull(name); + ThrowHelper.ThrowIfNullOrEmpty(hashAlgorithm.Name, nameof(hashAlgorithm)); + + if (preferredGroupSize < minimumGroupSize || preferredGroupSize > maximumGroupSize) + { + throw new ArgumentOutOfRangeException(nameof(preferredGroupSize)); + } + + Name = name; + _minimumGroupSize = minimumGroupSize; + _preferredGroupSize = preferredGroupSize; + _maximumGroupSize = maximumGroupSize; +#if NET + try + { + _hash = IncrementalHash.CreateHash(hashAlgorithm); + _hashLengthInBits = _hash.HashLengthInBytes * 8; + } + catch (CryptographicException cex) + { + throw new ArgumentException($"Could not create {nameof(HashAlgorithm)} from `{hashAlgorithm}`.", nameof(hashAlgorithm), cex); + } +#else + _hash = CryptoConfig.CreateFromName(hashAlgorithm.Name) as HashAlgorithm + ?? throw new ArgumentException($"Could not create {nameof(HashAlgorithm)} from `{hashAlgorithm}`.", nameof(hashAlgorithm)); + _hashLengthInBits = _hash.HashSize; +#endif + } + + /// + protected override byte[] CalculateHash() + { + var groupExchangeHashData = new GroupExchangeHashData + { + ClientVersion = Session.ClientVersion, + ServerVersion = Session.ServerVersion, + ClientPayload = _clientPayload, + ServerPayload = _serverPayload, + HostKey = _hostKey, + MinimumGroupSize = _minimumGroupSize, + PreferredGroupSize = _preferredGroupSize, + MaximumGroupSize = _maximumGroupSize, + Prime = _prime, + SubGroup = _group, + ClientExchangeValue = _clientExchangeValue, + ServerExchangeValue = _serverExchangeValue, + SharedKey = SharedKey, + }; + + return Hash(groupExchangeHashData.GetBytes()); + } + + /// + public override void Start(Session session, KeyExchangeInitMessage message, bool sendClientInitMessage) + { + base.Start(session, message, sendClientInitMessage); + + _serverPayload = message.GetBytes(); + _clientPayload = Session.ClientInitMessage.GetBytes(); + + Session.RegisterMessage("SSH_MSG_KEX_DH_GEX_GROUP"); + + Session.KeyExchangeDhGroupExchangeGroupReceived += Session_KeyExchangeDhGroupExchangeGroupReceived; + + // 1. client sends SSH_MSG_KEY_DH_GEX_REQUEST + SendMessage(new KeyExchangeDhGroupExchangeRequest(_minimumGroupSize, _preferredGroupSize, _maximumGroupSize)); + } + + private void Session_KeyExchangeDhGroupExchangeGroupReceived(object? sender, MessageEventArgs e) + { + // 2. server sends SSH_MSG_KEX_DH_GEX_GROUP + var groupMessage = e.Message; + + Session.UnRegisterMessage("SSH_MSG_KEX_DH_GEX_GROUP"); + + Session.KeyExchangeDhGroupExchangeGroupReceived -= Session_KeyExchangeDhGroupExchangeGroupReceived; + + _prime = groupMessage.SafePrimeBytes; + _group = groupMessage.SubGroupBytes; + + // https://datatracker.ietf.org/doc/html/rfc4419#section-6.2 + var minimumBitLength = 2 * _hashLengthInBits; + + _dhParameters = new DHParameters( + new Org.BouncyCastle.Math.BigInteger(_prime), + new Org.BouncyCastle.Math.BigInteger(_group), + q: null, + m: minimumBitLength, + l: 0); + + var g = new DHKeyPairGenerator(); + g.Init(new DHKeyGenerationParameters(CryptoAbstraction.SecureRandom, _dhParameters)); + + var aKeyPair = g.GenerateKeyPair(); + + _keyAgreement = new DHBasicAgreement(); + _keyAgreement.Init(aKeyPair.Private); + _clientExchangeValue = ((DHPublicKeyParameters)aKeyPair.Public).Y.ToByteArray(); + + Session.RegisterMessage("SSH_MSG_KEX_DH_GEX_REPLY"); + + Session.KeyExchangeDhGroupExchangeReplyReceived += Session_KeyExchangeDhGroupExchangeReplyReceived; + + // 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 message = e.Message; + + Session.KeyExchangeDhGroupExchangeReplyReceived -= Session_KeyExchangeDhGroupExchangeReplyReceived; + + Session.UnRegisterMessage("SSH_MSG_KEX_DH_GEX_REPLY"); + + Session.KeyExchangeDhGroupExchangeReplyReceived -= Session_KeyExchangeDhGroupExchangeReplyReceived; + + _serverExchangeValue = message.F; + _hostKey = message.HostKey; + _signature = message.Signature; + + var publicKey = new DHPublicKeyParameters(new Org.BouncyCastle.Math.BigInteger(message.F), _dhParameters); + + SharedKey = _keyAgreement!.CalculateAgreement(publicKey).ToByteArray(); + + // When SSH_MSG_KEX_DH_GEX_REPLY received key exchange is completed + Finish(); + } + + /// + protected override bool ValidateExchangeHash() + { + return ValidateExchangeHash(_hostKey, _signature); + } + + /// + protected override byte[] Hash(byte[] hashData) + { +#if NET + _hash.AppendData(hashData); + return _hash.GetHashAndReset(); +#else + return _hash.ComputeHash(hashData); +#endif + } + + /// + protected override void Dispose(bool disposing) + { + if (disposing) + { + _hash.Dispose(); + } + + base.Dispose(disposing); + } + } +} diff --git a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeSha1.cs b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeSha1.cs deleted file mode 100644 index 5eb0e7c17..000000000 --- a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeSha1.cs +++ /dev/null @@ -1,41 +0,0 @@ -using Renci.SshNet.Abstractions; - -namespace Renci.SshNet.Security -{ - /// - /// Represents "diffie-hellman-group-exchange-sha1" algorithm implementation. - /// - internal sealed class KeyExchangeDiffieHellmanGroupExchangeSha1 : KeyExchangeDiffieHellmanGroupExchangeShaBase - { - /// - /// Gets algorithm name. - /// - public override string Name - { - get { return "diffie-hellman-group-exchange-sha1"; } - } - - /// - /// Gets the size, in bits, of the computed hash code. - /// - /// - /// The size, in bits, of the computed hash code. - /// - protected override int HashSize - { - get { return 160; } - } - - /// - /// Hashes the specified data bytes. - /// - /// The hash data. - /// - /// The hash of the data. - /// - protected override byte[] Hash(byte[] hashData) - { - return CryptoAbstraction.HashSHA1(hashData); - } - } -} diff --git a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeSha256.cs b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeSha256.cs deleted file mode 100644 index 62d466cc1..000000000 --- a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeSha256.cs +++ /dev/null @@ -1,41 +0,0 @@ -using Renci.SshNet.Abstractions; - -namespace Renci.SshNet.Security -{ - /// - /// Represents "diffie-hellman-group-exchange-sha256" algorithm implementation. - /// - internal sealed class KeyExchangeDiffieHellmanGroupExchangeSha256 : KeyExchangeDiffieHellmanGroupExchangeShaBase - { - /// - /// Gets algorithm name. - /// - public override string Name - { - get { return "diffie-hellman-group-exchange-sha256"; } - } - - /// - /// Gets the size, in bits, of the computed hash code. - /// - /// - /// The size, in bits, of the computed hash code. - /// - protected override int HashSize - { - get { return 256; } - } - - /// - /// Hashes the specified data bytes. - /// - /// Data to hash. - /// - /// The hash of the data. - /// - protected override byte[] Hash(byte[] hashData) - { - return CryptoAbstraction.HashSHA256(hashData); - } - } -} diff --git a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeShaBase.cs b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeShaBase.cs deleted file mode 100644 index d35983887..000000000 --- a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeShaBase.cs +++ /dev/null @@ -1,111 +0,0 @@ -using Renci.SshNet.Messages.Transport; - -namespace Renci.SshNet.Security -{ - /// - /// Base class for "diffie-hellman-group-exchange" algorithms. - /// - internal 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 groupExchangeHashData = 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, - }; - - return Hash(groupExchangeHashData.GetBytes()); - } - - /// - public override void Start(Session session, KeyExchangeInitMessage message, bool sendClientInitMessage) - { - base.Start(session, message, sendClientInitMessage); - - // 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(); - } - } -} diff --git a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha1.cs b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha1.cs deleted file mode 100644 index 26d13a4d4..000000000 --- a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha1.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Renci.SshNet.Abstractions; - -namespace Renci.SshNet.Security -{ - /// - /// Represents "diffie-hellman-group1-sha1" algorithm implementation. - /// - internal abstract class KeyExchangeDiffieHellmanGroupSha1 : KeyExchangeDiffieHellmanGroupShaBase - { - /// - /// Gets the size, in bits, of the computed hash code. - /// - /// - /// The size, in bits, of the computed hash code. - /// - protected override int HashSize - { - get { return 160; } - } - - /// - /// Hashes the specified data bytes. - /// - /// The hash data. - /// - /// The hash of the data. - /// - protected override byte[] Hash(byte[] hashData) - { - return CryptoAbstraction.HashSHA1(hashData); - } - } -} diff --git a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha256.cs b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha256.cs deleted file mode 100644 index 3246a3d8e..000000000 --- a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha256.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Renci.SshNet.Abstractions; - -namespace Renci.SshNet.Security -{ - /// - /// Base class for "diffie-hellman" SHA-256 group algorithm implementations. - /// - internal abstract class KeyExchangeDiffieHellmanGroupSha256 : KeyExchangeDiffieHellmanGroupShaBase - { - /// - /// Gets the size, in bits, of the computed hash code. - /// - /// - /// The size, in bits, of the computed hash code. - /// - protected override int HashSize - { - get { return 256; } - } - - /// - /// Hashes the specified data bytes. - /// - /// The hash data. - /// - /// The hash of the data. - /// - protected override byte[] Hash(byte[] hashData) - { - return CryptoAbstraction.HashSHA256(hashData); - } - } -} diff --git a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha512.cs b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha512.cs deleted file mode 100644 index b599e9d2e..000000000 --- a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha512.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Renci.SshNet.Abstractions; - -namespace Renci.SshNet.Security -{ - /// - /// Base class for "diffie-hellman" SHA-512 group algorithm implementations. - /// - internal abstract class KeyExchangeDiffieHellmanGroupSha512 : KeyExchangeDiffieHellmanGroupShaBase - { - /// - /// Gets the size, in bits, of the computed hash code. - /// - /// - /// The size, in bits, of the computed hash code. - /// - protected override int HashSize - { - get { return 512; } - } - - /// - /// Hashes the specified data bytes. - /// - /// The hash data. - /// - /// The hash of the data. - /// - protected override byte[] Hash(byte[] hashData) - { - return CryptoAbstraction.HashSHA512(hashData); - } - } -} diff --git a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupShaBase.cs b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupShaBase.cs deleted file mode 100644 index f4d64833f..000000000 --- a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupShaBase.cs +++ /dev/null @@ -1,80 +0,0 @@ -using System.Numerics; - -using Renci.SshNet.Messages.Transport; - -namespace Renci.SshNet.Security -{ - internal abstract class KeyExchangeDiffieHellmanGroupShaBase : KeyExchangeDiffieHellman - { - /// - /// Gets the group prime. - /// - /// - /// The group prime. - /// - public abstract BigInteger GroupPrime { get; } - - /// - public override void Start(Session session, KeyExchangeInitMessage message, bool sendClientInitMessage) - { - base.Start(session, message, sendClientInitMessage); - - Session.RegisterMessage("SSH_MSG_KEXDH_REPLY"); - - Session.KeyExchangeDhReplyMessageReceived += Session_KeyExchangeDhReplyMessageReceived; - - _prime = GroupPrime; - _group = 2; - - PopulateClientExchangeValue(); - - SendMessage(new KeyExchangeDhInitMessage(_clientExchangeValue)); - } - - /// - /// Finishes key exchange algorithm. - /// - public override void Finish() - { - base.Finish(); - - Session.KeyExchangeDhReplyMessageReceived -= Session_KeyExchangeDhReplyMessageReceived; - } - - /// - /// Calculates key exchange hash value. - /// - /// - /// Key exchange hash. - /// - protected override byte[] CalculateHash() - { - var keyExchangeHashData = new KeyExchangeHashData - { - ClientVersion = Session.ClientVersion, - ServerVersion = Session.ServerVersion, - ClientPayload = _clientPayload, - ServerPayload = _serverPayload, - HostKey = _hostKey, - ClientExchangeValue = _clientExchangeValue, - ServerExchangeValue = _serverExchangeValue, - SharedKey = SharedKey, - }; - - return Hash(keyExchangeHashData.GetBytes()); - } - - private void Session_KeyExchangeDhReplyMessageReceived(object sender, MessageEventArgs e) - { - var message = e.Message; - - // Unregister message once received - Session.UnRegisterMessage("SSH_MSG_KEXDH_REPLY"); - - HandleServerDhReply(message.HostKey, message.F, message.Signature); - - // When SSH_MSG_KEXDH_REPLY received key exchange is completed - Finish(); - } - } -} diff --git a/src/Renci.SshNet/Security/KeyExchangeEC.cs b/src/Renci.SshNet/Security/KeyExchangeEC.cs index a0b41538e..a36bb7bc5 100644 --- a/src/Renci.SshNet/Security/KeyExchangeEC.cs +++ b/src/Renci.SshNet/Security/KeyExchangeEC.cs @@ -44,12 +44,7 @@ internal abstract class KeyExchangeEC : KeyExchange /// protected abstract int HashSize { get; } - /// - /// Calculates key exchange hash value. - /// - /// - /// Key exchange hash. - /// + /// protected override byte[] CalculateHash() { var hashData = new KeyExchangeHashData @@ -67,12 +62,7 @@ protected override byte[] CalculateHash() return Hash(hashData.GetBytes()); } - /// - /// Validates the exchange hash. - /// - /// - /// true if exchange hash is valid; otherwise false. - /// + /// protected override bool ValidateExchangeHash() { return ValidateExchangeHash(_hostKey, _signature); diff --git a/test/Renci.SshNet.IntegrationTests/KeyExchangeAlgorithmTests.cs b/test/Renci.SshNet.IntegrationTests/KeyExchangeAlgorithmTests.cs index cb939e609..90e74492f 100644 --- a/test/Renci.SshNet.IntegrationTests/KeyExchangeAlgorithmTests.cs +++ b/test/Renci.SshNet.IntegrationTests/KeyExchangeAlgorithmTests.cs @@ -158,7 +158,6 @@ public void DiffieHellmanGroup16Sha512() } [TestMethod] - [Ignore] public void DiffieHellmanGroup18Sha512() { _remoteSshdConfig.ClearKeyExchangeAlgorithms() diff --git a/test/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroup14Sha1Test.cs b/test/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroup14Sha1Test.cs deleted file mode 100644 index 7b745c4d6..000000000 --- a/test/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroup14Sha1Test.cs +++ /dev/null @@ -1,61 +0,0 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; - -using Renci.SshNet.Common; -using Renci.SshNet.Security; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Security -{ - [TestClass] - public class KeyExchangeDiffieHellmanGroup14Sha1Test : TestBase - { - private static readonly byte[] SecondOkleyGroup = - { - 0x00, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc9, 0x0f, 0xda, 0xa2, - 0x21, 0x68, 0xc2, 0x34, 0xc4, 0xc6, 0x62, 0x8b, 0x80, 0xdc, 0x1c, 0xd1, - 0x29, 0x02, 0x4e, 0x08, 0x8a, 0x67, 0xcc, 0x74, 0x02, 0x0b, 0xbe, 0xa6, - 0x3b, 0x13, 0x9b, 0x22, 0x51, 0x4a, 0x08, 0x79, 0x8e, 0x34, 0x04, 0xdd, - 0xef, 0x95, 0x19, 0xb3, 0xcd, 0x3a, 0x43, 0x1b, 0x30, 0x2b, 0x0a, 0x6d, - 0xf2, 0x5f, 0x14, 0x37, 0x4f, 0xe1, 0x35, 0x6d, 0x6d, 0x51, 0xc2, 0x45, - 0xe4, 0x85, 0xb5, 0x76, 0x62, 0x5e, 0x7e, 0xc6, 0xf4, 0x4c, 0x42, 0xe9, - 0xa6, 0x37, 0xed, 0x6b, 0x0b, 0xff, 0x5c, 0xb6, 0xf4, 0x06, 0xb7, 0xed, - 0xee, 0x38, 0x6b, 0xfb, 0x5a, 0x89, 0x9f, 0xa5, 0xae, 0x9f, 0x24, 0x11, - 0x7c, 0x4b, 0x1f, 0xe6, 0x49, 0x28, 0x66, 0x51, 0xec, 0xe4, 0x5b, 0x3d, - 0xc2, 0x00, 0x7c, 0xb8, 0xa1, 0x63, 0xbf, 0x05, 0x98, 0xda, 0x48, 0x36, - 0x1c, 0x55, 0xd3, 0x9a, 0x69, 0x16, 0x3f, 0xa8, 0xfd, 0x24, 0xcf, 0x5f, - 0x83, 0x65, 0x5d, 0x23, 0xdc, 0xa3, 0xad, 0x96, 0x1c, 0x62, 0xf3, 0x56, - 0x20, 0x85, 0x52, 0xbb, 0x9e, 0xd5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6d, - 0x67, 0x0c, 0x35, 0x4e, 0x4a, 0xbc, 0x98, 0x04, 0xf1, 0x74, 0x6c, 0x08, - 0xca, 0x18, 0x21, 0x7c, 0x32, 0x90, 0x5e, 0x46, 0x2e, 0x36, 0xce, 0x3b, - 0xe3, 0x9e, 0x77, 0x2c, 0x18, 0x0e, 0x86, 0x03, 0x9b, 0x27, 0x83, 0xa2, - 0xec, 0x07, 0xa2, 0x8f, 0xb5, 0xc5, 0x5d, 0xf0, 0x6f, 0x4c, 0x52, 0xc9, - 0xde, 0x2b, 0xcb, 0xf6, 0x95, 0x58, 0x17, 0x18, 0x39, 0x95, 0x49, 0x7c, - 0xea, 0x95, 0x6a, 0xe5, 0x15, 0xd2, 0x26, 0x18, 0x98, 0xfa, 0x05, 0x10, - 0x15, 0x72, 0x8e, 0x5a, 0x8a, 0xac, 0xaa, 0x68, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff - }; - - private KeyExchangeDiffieHellmanGroup14Sha1 _group14; - - protected override void OnInit() - { - base.OnInit(); - - _group14 = new KeyExchangeDiffieHellmanGroup14Sha1(); - } - - [TestMethod] - public void GroupPrimeShouldBeSecondOakleyGroup() - { - var bytes = _group14.GroupPrime.ToByteArray(isBigEndian: true); - Assert.IsTrue(SecondOkleyGroup.IsEqualTo(bytes)); - } - - [TestMethod] - public void NameShouldBeDiffieHellmanGroup14Sha1() - { - Assert.AreEqual("diffie-hellman-group14-sha1", _group14.Name); - } - } -} diff --git a/test/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroup14Sha256Test.cs b/test/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroup14Sha256Test.cs deleted file mode 100644 index fa89b3ec2..000000000 --- a/test/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroup14Sha256Test.cs +++ /dev/null @@ -1,61 +0,0 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; - -using Renci.SshNet.Common; -using Renci.SshNet.Security; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Security -{ - [TestClass] - public class KeyExchangeDiffieHellmanGroup14Sha256Test : TestBase - { - private static readonly byte[] SecondOkleyGroup = - { - 0x00, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc9, 0x0f, 0xda, 0xa2, - 0x21, 0x68, 0xc2, 0x34, 0xc4, 0xc6, 0x62, 0x8b, 0x80, 0xdc, 0x1c, 0xd1, - 0x29, 0x02, 0x4e, 0x08, 0x8a, 0x67, 0xcc, 0x74, 0x02, 0x0b, 0xbe, 0xa6, - 0x3b, 0x13, 0x9b, 0x22, 0x51, 0x4a, 0x08, 0x79, 0x8e, 0x34, 0x04, 0xdd, - 0xef, 0x95, 0x19, 0xb3, 0xcd, 0x3a, 0x43, 0x1b, 0x30, 0x2b, 0x0a, 0x6d, - 0xf2, 0x5f, 0x14, 0x37, 0x4f, 0xe1, 0x35, 0x6d, 0x6d, 0x51, 0xc2, 0x45, - 0xe4, 0x85, 0xb5, 0x76, 0x62, 0x5e, 0x7e, 0xc6, 0xf4, 0x4c, 0x42, 0xe9, - 0xa6, 0x37, 0xed, 0x6b, 0x0b, 0xff, 0x5c, 0xb6, 0xf4, 0x06, 0xb7, 0xed, - 0xee, 0x38, 0x6b, 0xfb, 0x5a, 0x89, 0x9f, 0xa5, 0xae, 0x9f, 0x24, 0x11, - 0x7c, 0x4b, 0x1f, 0xe6, 0x49, 0x28, 0x66, 0x51, 0xec, 0xe4, 0x5b, 0x3d, - 0xc2, 0x00, 0x7c, 0xb8, 0xa1, 0x63, 0xbf, 0x05, 0x98, 0xda, 0x48, 0x36, - 0x1c, 0x55, 0xd3, 0x9a, 0x69, 0x16, 0x3f, 0xa8, 0xfd, 0x24, 0xcf, 0x5f, - 0x83, 0x65, 0x5d, 0x23, 0xdc, 0xa3, 0xad, 0x96, 0x1c, 0x62, 0xf3, 0x56, - 0x20, 0x85, 0x52, 0xbb, 0x9e, 0xd5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6d, - 0x67, 0x0c, 0x35, 0x4e, 0x4a, 0xbc, 0x98, 0x04, 0xf1, 0x74, 0x6c, 0x08, - 0xca, 0x18, 0x21, 0x7c, 0x32, 0x90, 0x5e, 0x46, 0x2e, 0x36, 0xce, 0x3b, - 0xe3, 0x9e, 0x77, 0x2c, 0x18, 0x0e, 0x86, 0x03, 0x9b, 0x27, 0x83, 0xa2, - 0xec, 0x07, 0xa2, 0x8f, 0xb5, 0xc5, 0x5d, 0xf0, 0x6f, 0x4c, 0x52, 0xc9, - 0xde, 0x2b, 0xcb, 0xf6, 0x95, 0x58, 0x17, 0x18, 0x39, 0x95, 0x49, 0x7c, - 0xea, 0x95, 0x6a, 0xe5, 0x15, 0xd2, 0x26, 0x18, 0x98, 0xfa, 0x05, 0x10, - 0x15, 0x72, 0x8e, 0x5a, 0x8a, 0xac, 0xaa, 0x68, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff - }; - - private KeyExchangeDiffieHellmanGroup14Sha256 _group14; - - protected override void OnInit() - { - base.OnInit(); - - _group14 = new KeyExchangeDiffieHellmanGroup14Sha256(); - } - - [TestMethod] - public void GroupPrimeShouldBeSecondOakleyGroup() - { - var bytes = _group14.GroupPrime.ToByteArray(isBigEndian: true); - Assert.IsTrue(SecondOkleyGroup.IsEqualTo(bytes)); - } - - [TestMethod] - public void NameShouldBeDiffieHellmanGroup14Sha256() - { - Assert.AreEqual("diffie-hellman-group14-sha256", _group14.Name); - } - } -} diff --git a/test/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroup16Sha512Test.cs b/test/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroup16Sha512Test.cs deleted file mode 100644 index 1461e1d68..000000000 --- a/test/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroup16Sha512Test.cs +++ /dev/null @@ -1,71 +0,0 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; - -using Renci.SshNet.Common; -using Renci.SshNet.Security; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Security -{ - [TestClass] - public class KeyExchangeDiffieHellmanGroup16Sha512Test : TestBase - { - private static readonly byte[] MoreModularExponentialGroup16 = - { - 0x00, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xc9,0x0f,0xda,0xa2,0x21,0x68,0xc2,0x34, - 0xc4,0xc6,0x62,0x8b,0x80,0xdc,0x1c,0xd1,0x29,0x02,0x4e,0x08,0x8a,0x67,0xcc,0x74, - 0x02,0x0b,0xbe,0xa6,0x3b,0x13,0x9b,0x22,0x51,0x4a,0x08,0x79,0x8e,0x34,0x04,0xdd, - 0xef,0x95,0x19,0xb3,0xcd,0x3a,0x43,0x1b,0x30,0x2b,0x0a,0x6d,0xf2,0x5f,0x14,0x37, - 0x4f,0xe1,0x35,0x6d,0x6d,0x51,0xc2,0x45,0xe4,0x85,0xb5,0x76,0x62,0x5e,0x7e,0xc6, - 0xf4,0x4c,0x42,0xe9,0xa6,0x37,0xed,0x6b,0x0b,0xff,0x5c,0xb6,0xf4,0x06,0xb7,0xed, - 0xee,0x38,0x6b,0xfb,0x5a,0x89,0x9f,0xa5,0xae,0x9f,0x24,0x11,0x7c,0x4b,0x1f,0xe6, - 0x49,0x28,0x66,0x51,0xec,0xe4,0x5b,0x3d,0xc2,0x00,0x7c,0xb8,0xa1,0x63,0xbf,0x05, - 0x98,0xda,0x48,0x36,0x1c,0x55,0xd3,0x9a,0x69,0x16,0x3f,0xa8,0xfd,0x24,0xcf,0x5f, - 0x83,0x65,0x5d,0x23,0xdc,0xa3,0xad,0x96,0x1c,0x62,0xf3,0x56,0x20,0x85,0x52,0xbb, - 0x9e,0xd5,0x29,0x07,0x70,0x96,0x96,0x6d,0x67,0x0c,0x35,0x4e,0x4a,0xbc,0x98,0x04, - 0xf1,0x74,0x6c,0x08,0xca,0x18,0x21,0x7c,0x32,0x90,0x5e,0x46,0x2e,0x36,0xce,0x3b, - 0xe3,0x9e,0x77,0x2c,0x18,0x0e,0x86,0x03,0x9b,0x27,0x83,0xa2,0xec,0x07,0xa2,0x8f, - 0xb5,0xc5,0x5d,0xf0,0x6f,0x4c,0x52,0xc9,0xde,0x2b,0xcb,0xf6,0x95,0x58,0x17,0x18, - 0x39,0x95,0x49,0x7c,0xea,0x95,0x6a,0xe5,0x15,0xd2,0x26,0x18,0x98,0xfa,0x05,0x10, - 0x15,0x72,0x8e,0x5a,0x8a,0xaa,0xc4,0x2d,0xad,0x33,0x17,0x0d,0x04,0x50,0x7a,0x33, - 0xa8,0x55,0x21,0xab,0xdf,0x1c,0xba,0x64,0xec,0xfb,0x85,0x04,0x58,0xdb,0xef,0x0a, - 0x8a,0xea,0x71,0x57,0x5d,0x06,0x0c,0x7d,0xb3,0x97,0x0f,0x85,0xa6,0xe1,0xe4,0xc7, - 0xab,0xf5,0xae,0x8c,0xdb,0x09,0x33,0xd7,0x1e,0x8c,0x94,0xe0,0x4a,0x25,0x61,0x9d, - 0xce,0xe3,0xd2,0x26,0x1a,0xd2,0xee,0x6b,0xf1,0x2f,0xfa,0x06,0xd9,0x8a,0x08,0x64, - 0xd8,0x76,0x02,0x73,0x3e,0xc8,0x6a,0x64,0x52,0x1f,0x2b,0x18,0x17,0x7b,0x20,0x0c, - 0xbb,0xe1,0x17,0x57,0x7a,0x61,0x5d,0x6c,0x77,0x09,0x88,0xc0,0xba,0xd9,0x46,0xe2, - 0x08,0xe2,0x4f,0xa0,0x74,0xe5,0xab,0x31,0x43,0xdb,0x5b,0xfc,0xe0,0xfd,0x10,0x8e, - 0x4b,0x82,0xd1,0x20,0xa9,0x21,0x08,0x01,0x1a,0x72,0x3c,0x12,0xa7,0x87,0xe6,0xd7, - 0x88,0x71,0x9a,0x10,0xbd,0xba,0x5b,0x26,0x99,0xc3,0x27,0x18,0x6a,0xf4,0xe2,0x3c, - 0x1a,0x94,0x68,0x34,0xb6,0x15,0x0b,0xda,0x25,0x83,0xe9,0xca,0x2a,0xd4,0x4c,0xe8, - 0xdb,0xbb,0xc2,0xdb,0x04,0xde,0x8e,0xf9,0x2e,0x8e,0xfc,0x14,0x1f,0xbe,0xca,0xa6, - 0x28,0x7c,0x59,0x47,0x4e,0x6b,0xc0,0x5d,0x99,0xb2,0x96,0x4f,0xa0,0x90,0xc3,0xa2, - 0x23,0x3b,0xa1,0x86,0x51,0x5b,0xe7,0xed,0x1f,0x61,0x29,0x70,0xce,0xe2,0xd7,0xaf, - 0xb8,0x1b,0xdd,0x76,0x21,0x70,0x48,0x1c,0xd0,0x06,0x91,0x27,0xd5,0xb0,0x5a,0xa9, - 0x93,0xb4,0xea,0x98,0x8d,0x8f,0xdd,0xc1,0x86,0xff,0xb7,0xdc,0x90,0xa6,0xc0,0x8f, - 0x4d,0xf4,0x35,0xc9,0x34,0x06,0x31,0x99,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff - }; - - private KeyExchangeDiffieHellmanGroup16Sha512 _group16; - - protected override void OnInit() - { - base.OnInit(); - - _group16 = new KeyExchangeDiffieHellmanGroup16Sha512(); - } - - [TestMethod] - public void GroupPrimeShouldBeMoreModularExponentialGroup16() - { - var bytes = _group16.GroupPrime.ToByteArray(isBigEndian: true); - Assert.IsTrue(MoreModularExponentialGroup16.IsEqualTo(bytes)); - } - - [TestMethod] - public void NameShouldBeDiffieHellmanGroup16Sha512() - { - Assert.AreEqual("diffie-hellman-group16-sha512", _group16.Name); - } - } -} diff --git a/test/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroup1Sha1Test.cs b/test/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroup1Sha1Test.cs deleted file mode 100644 index d9d420f59..000000000 --- a/test/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroup1Sha1Test.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System.Linq; - -using Microsoft.VisualStudio.TestTools.UnitTesting; - -using Renci.SshNet.Common; -using Renci.SshNet.Security; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Security -{ - [TestClass] - public class KeyExchangeDiffieHellmanGroup1Sha1Test : TestBase - { - private static readonly byte[] SecondOkleyGroup = - { - 0x00, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc9, 0x0f, 0xda, 0xa2, - 0x21, 0x68, 0xc2, 0x34, 0xc4, 0xc6, 0x62, 0x8b, 0x80, 0xdc, 0x1c, 0xd1, - 0x29, 0x02, 0x4e, 0x08, 0x8a, 0x67, 0xcc, 0x74, 0x02, 0x0b, 0xbe, 0xa6, - 0x3b, 0x13, 0x9b, 0x22, 0x51, 0x4a, 0x08, 0x79, 0x8e, 0x34, 0x04, 0xdd, - 0xef, 0x95, 0x19, 0xb3, 0xcd, 0x3a, 0x43, 0x1b, 0x30, 0x2b, 0x0a, 0x6d, - 0xf2, 0x5f, 0x14, 0x37, 0x4f, 0xe1, 0x35, 0x6d, 0x6d, 0x51, 0xc2, 0x45, - 0xe4, 0x85, 0xb5, 0x76, 0x62, 0x5e, 0x7e, 0xc6, 0xf4, 0x4c, 0x42, 0xe9, - 0xa6, 0x37, 0xed, 0x6b, 0x0b, 0xff, 0x5c, 0xb6, 0xf4, 0x06, 0xb7, 0xed, - 0xee, 0x38, 0x6b, 0xfb, 0x5a, 0x89, 0x9f, 0xa5, 0xae, 0x9f, 0x24, 0x11, - 0x7c, 0x4b, 0x1f, 0xe6, 0x49, 0x28, 0x66, 0x51, 0xec, 0xe6, 0x53, 0x81, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff - }; - - private KeyExchangeDiffieHellmanGroup1Sha1 _group1; - - protected override void OnInit() - { - base.OnInit(); - - _group1 = new KeyExchangeDiffieHellmanGroup1Sha1(); - } - - [TestMethod] - public void GroupPrimeShouldBeSecondOakleyGroup() - { - var bytes = _group1.GroupPrime.ToByteArray(isBigEndian: true); - Assert.IsTrue(SecondOkleyGroup.IsEqualTo(bytes)); - - SecondOkleyGroup.Reverse().DebugPrint(); - } - - [TestMethod] - public void NameShouldBeDiffieHellmanGroup1Sha1() - { - Assert.AreEqual("diffie-hellman-group1-sha1", _group1.Name); - } - } -} diff --git a/test/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroupExchangeTest.cs b/test/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroupExchangeTest.cs new file mode 100644 index 000000000..7001986ce --- /dev/null +++ b/test/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroupExchangeTest.cs @@ -0,0 +1,54 @@ +using System; +using System.Security.Cryptography; + +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Renci.SshNet.Security; + +namespace Renci.SshNet.Tests.Classes.Security +{ + [TestClass] + public class KeyExchangeDiffieHellmanGroupExchangeTest + { + [TestMethod] + public void NameShouldBeCtorValue() + { + KeyExchangeDiffieHellmanGroupExchange kex = new("diffie-hellman-group-exchange-sha256", HashAlgorithmName.SHA512); + + Assert.AreEqual("diffie-hellman-group-exchange-sha256", kex.Name); + } + + [TestMethod] + public void Ctor_ArgumentNullException() + { + var ex = Assert.Throws(() => new KeyExchangeDiffieHellmanGroupExchange(name: null, HashAlgorithmName.SHA512)); + Assert.AreEqual("name", ex.ParamName); + + ex = Assert.Throws(() => new KeyExchangeDiffieHellmanGroupExchange("kex", default)); + Assert.AreEqual("hashAlgorithm", ex.ParamName); + + ex = Assert.Throws(() => new KeyExchangeDiffieHellmanGroupExchange("kex", new HashAlgorithmName(null))); + Assert.AreEqual("hashAlgorithm", ex.ParamName); + } + + [TestMethod] + public void Ctor_InvalidHashAlgorithm_ThrowsArgumentException() + { + var ex = Assert.ThrowsExactly(() => new KeyExchangeDiffieHellmanGroupExchange("kex", new HashAlgorithmName("bad"))); + Assert.AreEqual("hashAlgorithm", ex.ParamName); + + ex = Assert.ThrowsExactly(() => new KeyExchangeDiffieHellmanGroupExchange("kex", new HashAlgorithmName(""))); + Assert.AreEqual("hashAlgorithm", ex.ParamName); + } + + [TestMethod] + public void Ctor_InvalidGroupSizes_ThrowsArgumentOutOfRangeException() + { + var ex = Assert.Throws(() => new KeyExchangeDiffieHellmanGroupExchange("kex", HashAlgorithmName.SHA512, 1024, 4096, 2048)); + Assert.AreEqual("preferredGroupSize", ex.ParamName); + + ex = Assert.Throws(() => new KeyExchangeDiffieHellmanGroupExchange("kex", HashAlgorithmName.SHA512, 8192, 4096, 2048)); + Assert.AreEqual("preferredGroupSize", ex.ParamName); + } + } +} diff --git a/test/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanTest.cs b/test/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanTest.cs new file mode 100644 index 000000000..804db0a70 --- /dev/null +++ b/test/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanTest.cs @@ -0,0 +1,49 @@ +using System; +using System.Security.Cryptography; + +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Org.BouncyCastle.Crypto.Agreement; + +using Renci.SshNet.Security; + +namespace Renci.SshNet.Tests.Classes.Security +{ + [TestClass] + public class KeyExchangeDiffieHellmanTest + { + [TestMethod] + public void NameShouldBeCtorValue() + { + KeyExchangeDiffieHellman kex = new("diffie-hellman-group16-sha512", DHStandardGroups.rfc3526_4096, HashAlgorithmName.SHA512); + + Assert.AreEqual("diffie-hellman-group16-sha512", kex.Name); + } + + [TestMethod] + public void Ctor_ArgumentNullException() + { + var ex = Assert.Throws(() => new KeyExchangeDiffieHellman(name: null, DHStandardGroups.rfc3526_4096, HashAlgorithmName.SHA512)); + Assert.AreEqual("name", ex.ParamName); + + ex = Assert.Throws(() => new KeyExchangeDiffieHellman("kex", parameters: null, HashAlgorithmName.SHA512)); + Assert.AreEqual("parameters", ex.ParamName); + + ex = Assert.Throws(() => new KeyExchangeDiffieHellman("kex", DHStandardGroups.rfc3526_4096, default)); + Assert.AreEqual("hashAlgorithm", ex.ParamName); + + ex = Assert.Throws(() => new KeyExchangeDiffieHellman("kex", DHStandardGroups.rfc3526_4096, new HashAlgorithmName(null))); + Assert.AreEqual("hashAlgorithm", ex.ParamName); + } + + [TestMethod] + public void Ctor_InvalidHashAlgorithm_ThrowsArgumentException() + { + var ex = Assert.ThrowsExactly(() => new KeyExchangeDiffieHellman("kex", DHStandardGroups.rfc3526_4096, new HashAlgorithmName("bad"))); + Assert.AreEqual("hashAlgorithm", ex.ParamName); + + ex = Assert.ThrowsExactly(() => new KeyExchangeDiffieHellman("kex", DHStandardGroups.rfc3526_4096, new HashAlgorithmName(""))); + Assert.AreEqual("hashAlgorithm", ex.ParamName); + } + } +}