瀏覽代碼

Make key exchange more efficient by using byte[] in our internal structures, and convert to BigInteger when necessary.
Fixes #643.

Introduce base classes for DiffieHelman group key exchange.
Eliminate code duplication.

drieseng 5 年之前
父節點
當前提交
c0da2c14fb

+ 15 - 0
src/Renci.SshNet/Common/Extensions.cs

@@ -72,6 +72,21 @@ namespace Renci.SshNet.Common
             return new BigInteger(reversed.Reverse());
         }
 
+        /// <summary>
+        /// Initializes a new instance of the <see cref="BigInteger"/> structure using the SSH BigNum2 Format
+        /// </summary>
+        public static byte[] ToBigNum2(this byte[] data)
+        {
+            if ((data[0] & (1 << 7)) != 0)
+            {
+                var buf = new byte[data.Length + 1];
+                Buffer.BlockCopy(data, 0, buf, 1, data.Length);
+                data = buf;
+            }
+
+            return data;
+        }
+
         /// <summary>
         /// Initializes a new instance of the <see cref="BigInteger"/> structure using the SSH BigNum2 Format
         /// </summary>

+ 0 - 2
src/Renci.SshNet/ConnectionInfo.cs

@@ -331,8 +331,6 @@ namespace Renci.SshNet
                     {"diffie-hellman-group-exchange-sha1", typeof (KeyExchangeDiffieHellmanGroupExchangeSha1)},
                     {"diffie-hellman-group14-sha1", typeof (KeyExchangeDiffieHellmanGroup14Sha1)},
                     {"diffie-hellman-group1-sha1", typeof (KeyExchangeDiffieHellmanGroup1Sha1)},
-                    //"gss-group1-sha1-toWM5Slw5Ew8Mqkay+al2g==" - WinSSHD
-                    //"gss-gex-sha1-toWM5Slw5Ew8Mqkay+al2g==" - WinSSHD
                 };
 
             Encryptions = new Dictionary<string, CipherInfo>

+ 7 - 14
src/Renci.SshNet/Messages/Transport/KeyExchangeDhGroupExchangeInit.cs

@@ -1,6 +1,4 @@
-using Renci.SshNet.Common;
-
-namespace Renci.SshNet.Messages.Transport
+namespace Renci.SshNet.Messages.Transport
 {
     /// <summary>
     /// Represents SSH_MSG_KEX_DH_GEX_INIT message.
@@ -8,15 +6,10 @@ namespace Renci.SshNet.Messages.Transport
     [Message("SSH_MSG_KEX_DH_GEX_INIT", 32)]
     internal class KeyExchangeDhGroupExchangeInit : Message, IKeyExchangedAllowed
     {
-        private byte[] _eBytes;
-
         /// <summary>
         /// Gets the E value.
         /// </summary>
-        public BigInteger E
-        {
-            get { return _eBytes.ToBigInteger(); }
-        }
+        public byte[] E { get; private set; }
 
         /// <summary>
         /// Gets the size of the message in bytes.
@@ -30,7 +23,7 @@ namespace Renci.SshNet.Messages.Transport
             {
                 var capacity = base.BufferCapacity;
                 capacity += 4; // E length
-                capacity += _eBytes.Length; // E
+                capacity += E.Length; // E
                 return capacity;
             }
         }
@@ -39,9 +32,9 @@ namespace Renci.SshNet.Messages.Transport
         /// Initializes a new instance of the <see cref="KeyExchangeDhGroupExchangeInit"/> class.
         /// </summary>
         /// <param name="clientExchangeValue">The client exchange value.</param>
-        public KeyExchangeDhGroupExchangeInit(BigInteger clientExchangeValue)
+        public KeyExchangeDhGroupExchangeInit(byte[] clientExchangeValue)
         {
-            _eBytes = clientExchangeValue.ToByteArray().Reverse();
+            E = clientExchangeValue;
         }
 
         /// <summary>
@@ -49,7 +42,7 @@ namespace Renci.SshNet.Messages.Transport
         /// </summary>
         protected override void LoadData()
         {
-            _eBytes = ReadBinary();
+            E = ReadBinary();
         }
 
         /// <summary>
@@ -57,7 +50,7 @@ namespace Renci.SshNet.Messages.Transport
         /// </summary>
         protected override void SaveData()
         {
-            WriteBinaryString(_eBytes);
+            WriteBinaryString(E);
         }
 
         internal override void Process(Session session)

+ 4 - 9
src/Renci.SshNet/Messages/Transport/KeyExchangeDhGroupExchangeReply.cs

@@ -10,8 +10,6 @@ namespace Renci.SshNet.Messages.Transport
     {
         internal const byte MessageNumber = 33;
 
-        private byte[] _fBytes;
-
         /// <summary>
         /// Gets server public host key and certificates
         /// </summary>
@@ -21,10 +19,7 @@ namespace Renci.SshNet.Messages.Transport
         /// <summary>
         /// Gets the F value.
         /// </summary>
-        public BigInteger F
-        {
-            get { return _fBytes.ToBigInteger(); }
-        }
+        public byte[] F { get; private set; }
 
         /// <summary>
         /// Gets the signature of H.
@@ -46,7 +41,7 @@ namespace Renci.SshNet.Messages.Transport
                 capacity += 4; // HostKey length
                 capacity += HostKey.Length; // HostKey
                 capacity += 4; // F length
-                capacity += _fBytes.Length; // F
+                capacity += F.Length; // F
                 capacity += 4; // Signature length
                 capacity += Signature.Length; // Signature
                 return capacity;
@@ -59,7 +54,7 @@ namespace Renci.SshNet.Messages.Transport
         protected override void LoadData()
         {
             HostKey = ReadBinary();
-            _fBytes = ReadBinary();
+            F = ReadBinary();
             Signature = ReadBinary();
         }
 
@@ -69,7 +64,7 @@ namespace Renci.SshNet.Messages.Transport
         protected override void SaveData()
         {
             WriteBinaryString(HostKey);
-            WriteBinaryString(_fBytes);
+            WriteBinaryString(F);
             WriteBinaryString(Signature);
         }
 

+ 7 - 14
src/Renci.SshNet/Messages/Transport/KeyExchangeDhInitMessage.cs

@@ -1,6 +1,4 @@
-using Renci.SshNet.Common;
-
-namespace Renci.SshNet.Messages.Transport
+namespace Renci.SshNet.Messages.Transport
 {
     /// <summary>
     /// Represents SSH_MSG_KEXDH_INIT message.
@@ -8,15 +6,10 @@ namespace Renci.SshNet.Messages.Transport
     [Message("SSH_MSG_KEXDH_INIT", 30)]
     internal class KeyExchangeDhInitMessage : Message, IKeyExchangedAllowed
     {
-        private byte[] _eBytes;
-
         /// <summary>
         /// Gets the E value.
         /// </summary>
-        public BigInteger E
-        {
-            get { return _eBytes.ToBigInteger(); }
-        }
+        public byte[] E { get; private set; }
 
         /// <summary>
         /// Gets the size of the message in bytes.
@@ -30,7 +23,7 @@ namespace Renci.SshNet.Messages.Transport
             {
                 var capacity = base.BufferCapacity;
                 capacity += 4; // E length
-                capacity += _eBytes.Length; // E
+                capacity += E.Length; // E
                 return capacity;
             }
         }
@@ -39,9 +32,9 @@ namespace Renci.SshNet.Messages.Transport
         /// Initializes a new instance of the <see cref="KeyExchangeDhInitMessage"/> class.
         /// </summary>
         /// <param name="clientExchangeValue">The client exchange value.</param>
-        public KeyExchangeDhInitMessage(BigInteger clientExchangeValue)
+        public KeyExchangeDhInitMessage(byte[] clientExchangeValue)
         {
-            _eBytes = clientExchangeValue.ToByteArray().Reverse();
+            E = clientExchangeValue;
         }
 
         /// <summary>
@@ -49,7 +42,7 @@ namespace Renci.SshNet.Messages.Transport
         /// </summary>
         protected override void LoadData()
         {
-            _eBytes = ReadBinary();
+            E = ReadBinary();
         }
 
         /// <summary>
@@ -57,7 +50,7 @@ namespace Renci.SshNet.Messages.Transport
         /// </summary>
         protected override void SaveData()
         {
-            WriteBinaryString(_eBytes);
+            WriteBinaryString(E);
         }
 
         internal override void Process(Session session)

+ 5 - 12
src/Renci.SshNet/Messages/Transport/KeyExchangeDhReplyMessage.cs

@@ -1,6 +1,4 @@
-using Renci.SshNet.Common;
-
-namespace Renci.SshNet.Messages.Transport
+namespace Renci.SshNet.Messages.Transport
 {
     /// <summary>
     /// Represents SSH_MSG_KEXDH_REPLY message.
@@ -8,8 +6,6 @@ namespace Renci.SshNet.Messages.Transport
     [Message("SSH_MSG_KEXDH_REPLY", 31)]
     public class KeyExchangeDhReplyMessage : Message
     {
-        private byte[] _fBytes;
-
         /// <summary>
         /// Gets server public host key and certificates
         /// </summary>
@@ -19,10 +15,7 @@ namespace Renci.SshNet.Messages.Transport
         /// <summary>
         /// Gets the F value.
         /// </summary>
-        public BigInteger F
-        {
-            get { return _fBytes.ToBigInteger(); }
-        }
+        public byte[] F { get; private set; }
 
         /// <summary>
         /// Gets the signature of H.
@@ -44,7 +37,7 @@ namespace Renci.SshNet.Messages.Transport
                 capacity += 4; // HostKey length
                 capacity += HostKey.Length; // HostKey
                 capacity += 4; // F length
-                capacity += _fBytes.Length; // F
+                capacity += F.Length; // F
                 capacity += 4; // Signature length
                 capacity += Signature.Length; // Signature
                 return capacity;
@@ -57,7 +50,7 @@ namespace Renci.SshNet.Messages.Transport
         protected override void LoadData()
         {
             HostKey = ReadBinary();
-            _fBytes = ReadBinary();
+            F = ReadBinary();
             Signature = ReadBinary();
         }
 
@@ -67,7 +60,7 @@ namespace Renci.SshNet.Messages.Transport
         protected override void SaveData()
         {
             WriteBinaryString(HostKey);
-            WriteBinaryString(_fBytes);
+            WriteBinaryString(F);
             WriteBinaryString(Signature);
         }
 

+ 0 - 1
src/Renci.SshNet/Renci.SshNet.csproj

@@ -30,7 +30,6 @@
 
   <ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' or '$(TargetFramework)' == 'netstandard2.1' ">
     <PackageReference Include="SshNet.Security.Cryptography" Version="[1.3.0]" />
-    <PackageReference Include="System.Security.Cryptography.Cng" Version="4.7.0" />
   </ItemGroup>
 
   <PropertyGroup Condition=" '$(TargetFramework)' == 'net35' ">

+ 9 - 24
src/Renci.SshNet/Security/GroupExchangeHashData.cs

@@ -9,9 +9,6 @@ namespace Renci.SshNet.Security
         private byte[] _clientVersion;
         private byte[] _prime;
         private byte[] _subGroup;
-        private byte[] _clientExchangeValue;
-        private byte[] _serverExchangeValue;
-        private byte[] _sharedKey;
 
         public string ServerVersion
         {
@@ -50,23 +47,11 @@ namespace Renci.SshNet.Security
             set { _subGroup = value.ToByteArray().Reverse(); }
         }
 
-        public BigInteger ClientExchangeValue
-        {
-            private get { return _clientExchangeValue.ToBigInteger(); }
-            set { _clientExchangeValue = value.ToByteArray().Reverse(); }
-        }
+        public byte[] ClientExchangeValue { get; set; }
 
-        public BigInteger ServerExchangeValue
-        {
-            private get { return _serverExchangeValue.ToBigInteger(); }
-            set { _serverExchangeValue = value.ToByteArray().Reverse(); }
-        }
+        public byte[] ServerExchangeValue { get; set; }
 
-        public BigInteger SharedKey
-        {
-            private get { return _sharedKey.ToBigInteger(); }
-            set { _sharedKey = value.ToByteArray().Reverse(); }
-        }
+        public byte[] SharedKey { get; set; }
 
         /// <summary>
         /// Gets the size of the message in bytes.
@@ -97,11 +82,11 @@ namespace Renci.SshNet.Security
                 capacity += 4; // SubGroup length
                 capacity += _subGroup.Length; // SubGroup
                 capacity += 4; // ClientExchangeValue length
-                capacity += _clientExchangeValue.Length; // ClientExchangeValue
+                capacity += ClientExchangeValue.Length; // ClientExchangeValue
                 capacity += 4; // ServerExchangeValue length
-                capacity += _serverExchangeValue.Length; // ServerExchangeValue
+                capacity += ServerExchangeValue.Length; // ServerExchangeValue
                 capacity += 4; // SharedKey length
-                capacity += _sharedKey.Length; // SharedKey
+                capacity += SharedKey.Length; // SharedKey
                 return capacity;
             }
         }
@@ -123,9 +108,9 @@ namespace Renci.SshNet.Security
             Write(MaximumGroupSize);
             WriteBinaryString(_prime);
             WriteBinaryString(_subGroup);
-            WriteBinaryString(_clientExchangeValue);
-            WriteBinaryString(_serverExchangeValue);
-            WriteBinaryString(_sharedKey);
+            WriteBinaryString(ClientExchangeValue);
+            WriteBinaryString(ServerExchangeValue);
+            WriteBinaryString(SharedKey);
         }
     }
 }

+ 18 - 35
src/Renci.SshNet/Security/KeyExchange.cs

@@ -37,7 +37,7 @@ namespace Renci.SshNet.Security
         /// <value>
         /// The shared key.
         /// </value>
-        public BigInteger SharedKey { get; protected set; }
+        public byte[] SharedKey { get; protected set; }
 
         private byte[] _exchangeHash;
 
@@ -323,13 +323,7 @@ namespace Renci.SshNet.Security
         /// <returns>
         /// Hashed bytes
         /// </returns>
-        protected virtual byte[] Hash(byte[] hashData)
-        {
-            using (var sha1 = CryptoAbstraction.CreateSHA1())
-            {
-                return sha1.ComputeHash(hashData, 0, hashData.Length);
-            }
-        }
+        protected abstract byte[] Hash(byte[] hashData);
 
         /// <summary>
         /// Sends SSH message to the server
@@ -348,7 +342,7 @@ namespace Renci.SshNet.Security
         /// <param name="key">The key.</param>
         /// <param name="size">The size.</param>
         /// <returns></returns>
-        private byte[] GenerateSessionKey(BigInteger sharedKey, byte[] exchangeHash, byte[] key, int size)
+        private byte[] GenerateSessionKey(byte[] sharedKey, byte[] exchangeHash, byte[] key, int size)
         {
             var result = new List<byte>(key);
             while (size > result.Count)
@@ -372,26 +366,21 @@ namespace Renci.SshNet.Security
         /// <param name="p">The p.</param>
         /// <param name="sessionId">The session id.</param>
         /// <returns></returns>
-        private static byte[] GenerateSessionKey(BigInteger sharedKey, byte[] exchangeHash, char p, byte[] sessionId)
+        private static byte[] GenerateSessionKey(byte[] sharedKey, byte[] exchangeHash, char p, byte[] sessionId)
         {
-            return new _SessionKeyGeneration
-            {
-                SharedKey = sharedKey,
-                ExchangeHash = exchangeHash,
-                Char = p,
-                SessionId = sessionId,
-            }.GetBytes();
+            var sessionKeyGeneration = new _SessionKeyGeneration
+                {
+                    SharedKey = sharedKey,
+                    ExchangeHash = exchangeHash,
+                    Char = p,
+                    SessionId = sessionId
+                };
+            return sessionKeyGeneration.GetBytes();
         }
 
         private class _SessionKeyGeneration : SshData
         {
-            private byte[] _sharedKey;
-
-            public BigInteger SharedKey
-            {
-                private get { return _sharedKey.ToBigInteger(); }
-                set { _sharedKey = value.ToByteArray().Reverse(); }
-            }
+            public byte[] SharedKey { get; set; }
             public byte[] ExchangeHash { get; set; }
             public char Char { get; set; }
             public byte[] SessionId { get; set; }
@@ -408,7 +397,7 @@ namespace Renci.SshNet.Security
                 {
                     var capacity = base.BufferCapacity;
                     capacity += 4; // SharedKey length
-                    capacity += _sharedKey.Length; // SharedKey
+                    capacity += SharedKey.Length; // SharedKey
                     capacity += ExchangeHash.Length; // ExchangeHash
                     capacity += 1; // Char
                     capacity += SessionId.Length; // SessionId
@@ -423,7 +412,7 @@ namespace Renci.SshNet.Security
 
             protected override void SaveData()
             {
-                WriteBinaryString(_sharedKey);
+                WriteBinaryString(SharedKey);
                 Write(ExchangeHash);
                 Write((byte) Char);
                 Write(SessionId);
@@ -432,13 +421,7 @@ namespace Renci.SshNet.Security
 
         private class _SessionKeyAdjustment : SshData
         {
-            private byte[] _sharedKey;
-
-            public BigInteger SharedKey
-            {
-                private get { return _sharedKey.ToBigInteger(); }
-                set { _sharedKey = value.ToByteArray().Reverse(); }
-            }
+            public byte[] SharedKey { get; set; }
             public byte[] ExchangeHash { get; set; }
             public byte[] Key { get; set; }
 
@@ -454,7 +437,7 @@ namespace Renci.SshNet.Security
                 {
                     var capacity = base.BufferCapacity;
                     capacity += 4; // SharedKey length
-                    capacity += _sharedKey.Length; // SharedKey
+                    capacity += SharedKey.Length; // SharedKey
                     capacity += ExchangeHash.Length; // ExchangeHash
                     capacity += Key.Length; // Key
                     return capacity;
@@ -468,7 +451,7 @@ namespace Renci.SshNet.Security
 
             protected override void SaveData()
             {
-                WriteBinaryString(_sharedKey);
+                WriteBinaryString(SharedKey);
                 Write(ExchangeHash);
                 Write(Key);
             }

+ 10 - 6
src/Renci.SshNet/Security/KeyExchangeDiffieHellman.cs

@@ -33,12 +33,12 @@ namespace Renci.SshNet.Security
         /// <summary>
         /// Specifies client exchange number.
         /// </summary>
-        protected BigInteger _clientExchangeValue;
+        protected byte[] _clientExchangeValue;
 
         /// <summary>
         /// Specifies server exchange number.
         /// </summary>
-        protected BigInteger _serverExchangeValue;
+        protected byte[] _serverExchangeValue;
 
         /// <summary>
         /// Specifies random generated number.
@@ -114,13 +114,17 @@ namespace Renci.SshNet.Security
             // of 1024 bits (whatever is less)
             var privateExponentSize = Math.Max(HashSize * 2, 1024);
 
+            BigInteger clientExchangeValue;
+
             do
             {
                 // create private component
                 _privateExponent = BigInteger.Random(privateExponentSize);
                 // generate public component
-                _clientExchangeValue = BigInteger.ModPow(_group, _privateExponent, _prime);
-            } while (_clientExchangeValue < 1 || _clientExchangeValue > (_prime - 1));
+                clientExchangeValue = BigInteger.ModPow(_group, _privateExponent, _prime);
+            } while (clientExchangeValue < 1 || clientExchangeValue > (_prime - 1));
+
+            _clientExchangeValue = clientExchangeValue.ToByteArray().Reverse();
         }
 
         /// <summary>
@@ -129,11 +133,11 @@ namespace Renci.SshNet.Security
         /// <param name="hostKey">The host key.</param>
         /// <param name="serverExchangeValue">The server exchange value.</param>
         /// <param name="signature">The signature.</param>
-        protected virtual void HandleServerDhReply(byte[] hostKey, BigInteger serverExchangeValue, byte[] signature)
+        protected virtual void HandleServerDhReply(byte[] hostKey, byte[] serverExchangeValue, byte[] signature)
         {
             _serverExchangeValue = serverExchangeValue;
             _hostKey = hostKey;
-            SharedKey = BigInteger.ModPow(serverExchangeValue, _privateExponent, _prime);
+            SharedKey = BigInteger.ModPow(serverExchangeValue.ToBigInteger(), _privateExponent, _prime).ToByteArray().Reverse();
             _signature = signature;
         }
     }

+ 18 - 1
src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeSha1.cs

@@ -1,4 +1,6 @@
-namespace Renci.SshNet.Security
+using Renci.SshNet.Abstractions;
+
+namespace Renci.SshNet.Security
 {
     /// <summary>
     /// Represents "diffie-hellman-group-exchange-sha1" algorithm implementation.
@@ -23,5 +25,20 @@
         {
             get { return 160; }
         }
+
+        /// <summary>
+        /// Hashes the specified data bytes.
+        /// </summary>
+        /// <param name="hashData">The hash data.</param>
+        /// <returns>
+        /// Hashed bytes
+        /// </returns>
+        protected override byte[] Hash(byte[] hashData)
+        {
+            using (var sha1 = CryptoAbstraction.CreateSHA1())
+            {
+                return sha1.ComputeHash(hashData, 0, hashData.Length);
+            }
+        }
     }
 }

+ 4 - 5
src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeShaBase.cs

@@ -19,7 +19,7 @@ namespace Renci.SshNet.Security
         /// </returns>
         protected override byte[] CalculateHash()
         {
-            var hashData = new GroupExchangeHashData
+            var groupExchangeHashData = new GroupExchangeHashData
                 {
                     ClientVersion = Session.ClientVersion,
                     ServerVersion = Session.ServerVersion,
@@ -34,9 +34,9 @@ namespace Renci.SshNet.Security
                     ClientExchangeValue = _clientExchangeValue,
                     ServerExchangeValue = _serverExchangeValue,
                     SharedKey = SharedKey,
-                }.GetBytes();
+                };
 
-            return Hash(hashData);
+            return Hash(groupExchangeHashData.GetBytes());
         }
 
         /// <summary>
@@ -54,8 +54,7 @@ namespace Renci.SshNet.Security
             Session.KeyExchangeDhGroupExchangeGroupReceived += Session_KeyExchangeDhGroupExchangeGroupReceived;
 
             // 1. client sends SSH_MSG_KEY_DH_GEX_REQUEST
-            SendMessage(new KeyExchangeDhGroupExchangeRequest(MinimumGroupSize, PreferredGroupSize,
-                MaximumProupSize));
+            SendMessage(new KeyExchangeDhGroupExchangeRequest(MinimumGroupSize, PreferredGroupSize, MaximumProupSize));
         }
 
         /// <summary>

+ 8 - 163
src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha1.cs

@@ -1,22 +1,12 @@
-using System;
-using Renci.SshNet.Common;
-using Renci.SshNet.Messages.Transport;
+using Renci.SshNet.Abstractions;
 
 namespace Renci.SshNet.Security
 {
     /// <summary>
     /// Represents "diffie-hellman-group1-sha1" algorithm implementation.
     /// </summary>
-    internal abstract class KeyExchangeDiffieHellmanGroupSha1 : KeyExchangeDiffieHellman
+    internal abstract class KeyExchangeDiffieHellmanGroupSha1 : KeyExchangeDiffieHellmanGroupShaBase
     {
-        /// <summary>
-        /// Gets the group prime.
-        /// </summary>
-        /// <value>
-        /// The group prime.
-        /// </value>
-        public abstract BigInteger GroupPrime { get; }
-
         /// <summary>
         /// Gets the size, in bits, of the computed hash code.
         /// </summary>
@@ -29,162 +19,17 @@ namespace Renci.SshNet.Security
         }
 
         /// <summary>
-        /// Calculates key exchange hash value.
+        /// Hashes the specified data bytes.
         /// </summary>
+        /// <param name="hashData">The hash data.</param>
         /// <returns>
-        /// Key exchange hash.
+        /// Hashed bytes
         /// </returns>
-        protected override byte[] CalculateHash()
-        {
-            var hashData = new _ExchangeHashData
-                {
-                    ClientVersion = Session.ClientVersion,
-                    ServerVersion = Session.ServerVersion,
-                    ClientPayload = _clientPayload,
-                    ServerPayload = _serverPayload,
-                    HostKey = _hostKey,
-                    ClientExchangeValue = _clientExchangeValue,
-                    ServerExchangeValue = _serverExchangeValue,
-                    SharedKey = SharedKey,
-                }.GetBytes();
-
-            return Hash(hashData);
-        }
-
-        /// <summary>
-        /// Starts key exchange algorithm
-        /// </summary>
-        /// <param name="session">The session.</param>
-        /// <param name="message">Key exchange init message.</param>
-        public override void Start(Session session, KeyExchangeInitMessage message)
-        {
-            base.Start(session, message);
-
-            Session.RegisterMessage("SSH_MSG_KEXDH_REPLY");
-
-            Session.KeyExchangeDhReplyMessageReceived += Session_KeyExchangeDhReplyMessageReceived;
-
-            _prime = GroupPrime;
-            _group = new BigInteger(new byte[] { 2 });
-
-            PopulateClientExchangeValue();
-
-            SendMessage(new KeyExchangeDhInitMessage(_clientExchangeValue));
-        }
-
-        /// <summary>
-        /// Finishes key exchange algorithm.
-        /// </summary>
-        public override void Finish()
-        {
-            base.Finish();
-
-            Session.KeyExchangeDhReplyMessageReceived -= Session_KeyExchangeDhReplyMessageReceived;
-        }
-
-        private void Session_KeyExchangeDhReplyMessageReceived(object sender, MessageEventArgs<KeyExchangeDhReplyMessage> 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();
-        }
-
-        private class _ExchangeHashData : SshData
+        protected override byte[] Hash(byte[] hashData)
         {
-            private byte[] _serverVersion;
-            private byte[] _clientVersion;
-            private byte[] _clientExchangeValue;
-            private byte[] _serverExchangeValue;
-            private byte[] _sharedKey;
-
-            public string ServerVersion
-            {
-                private get { return Utf8.GetString(_serverVersion, 0, _serverVersion.Length); }
-                set { _serverVersion = Utf8.GetBytes(value); }
-            }
-
-            public string ClientVersion
-            {
-                private get { return Utf8.GetString(_clientVersion, 0, _clientVersion.Length); }
-                set { _clientVersion = Utf8.GetBytes(value); }
-            }
-
-            public byte[] ClientPayload { get; set; }
-
-            public byte[] ServerPayload { get; set; }
-
-            public byte[] HostKey { get; set; }
-
-            public BigInteger ClientExchangeValue
-            {
-                private get { return _clientExchangeValue.ToBigInteger(); }
-                set { _clientExchangeValue = value.ToByteArray().Reverse(); }
-            }
-
-            public BigInteger ServerExchangeValue
-            {
-                private get { return _serverExchangeValue.ToBigInteger(); }
-                set { _serverExchangeValue = value.ToByteArray().Reverse(); }
-            }
-
-            public BigInteger SharedKey
-            {
-                private get { return _sharedKey.ToBigInteger(); }
-                set { _sharedKey = value.ToByteArray().Reverse(); }
-            }
-
-            /// <summary>
-            /// Gets the size of the message in bytes.
-            /// </summary>
-            /// <value>
-            /// The size of the messages in bytes.
-            /// </value>
-            protected override int BufferCapacity
-            {
-                get
-                {
-                    var capacity = base.BufferCapacity;
-                    capacity += 4; // ClientVersion length
-                    capacity += _clientVersion.Length; // ClientVersion
-                    capacity += 4; // ServerVersion length
-                    capacity += _serverVersion.Length; // ServerVersion
-                    capacity += 4; // ClientPayload length
-                    capacity += ClientPayload.Length; // ClientPayload
-                    capacity += 4; // ServerPayload length
-                    capacity += ServerPayload.Length; // ServerPayload
-                    capacity += 4; // HostKey length
-                    capacity += HostKey.Length; // HostKey
-                    capacity += 4; // ClientExchangeValue length
-                    capacity += _clientExchangeValue.Length; // ClientExchangeValue
-                    capacity += 4; // ServerExchangeValue length
-                    capacity += _serverExchangeValue.Length; // ServerExchangeValue
-                    capacity += 4; // SharedKey length
-                    capacity += _sharedKey.Length; // SharedKey
-                    return capacity;
-                }
-            }
-
-            protected override void LoadData()
-            {
-                throw new NotImplementedException();
-            }
-
-            protected override void SaveData()
+            using (var sha1 = CryptoAbstraction.CreateSHA1())
             {
-                WriteBinaryString(_clientVersion);
-                WriteBinaryString(_serverVersion);
-                WriteBinaryString(ClientPayload);
-                WriteBinaryString(ServerPayload);
-                WriteBinaryString(HostKey);
-                WriteBinaryString(_clientExchangeValue);
-                WriteBinaryString(_serverExchangeValue);
-                WriteBinaryString(_sharedKey);
+                return sha1.ComputeHash(hashData, 0, hashData.Length);
             }
         }
     }

+ 36 - 0
src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha256.cs

@@ -0,0 +1,36 @@
+using Renci.SshNet.Abstractions;
+
+namespace Renci.SshNet.Security
+{
+    /// <summary>
+    /// Base class for "diffie-hellman" SHA-256 group algorithm implementations.
+    /// </summary>
+    internal abstract class KeyExchangeDiffieHellmanGroupSha256 : KeyExchangeDiffieHellmanGroupShaBase
+    {
+        /// <summary>
+        /// Gets the size, in bits, of the computed hash code.
+        /// </summary>
+        /// <value>
+        /// The size, in bits, of the computed hash code.
+        /// </value>
+        protected override int HashSize
+        {
+            get { return 256; }
+        }
+
+        /// <summary>
+        /// Hashes the specified data bytes.
+        /// </summary>
+        /// <param name="hashData">The hash data.</param>
+        /// <returns>
+        /// Hashed bytes
+        /// </returns>
+        protected override byte[] Hash(byte[] hashData)
+        {
+            using (var sha256 = CryptoAbstraction.CreateSHA256())
+            {
+                return sha256.ComputeHash(hashData);
+            }
+        }
+    }
+}

+ 36 - 0
src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha512.cs

@@ -0,0 +1,36 @@
+using Renci.SshNet.Abstractions;
+
+namespace Renci.SshNet.Security
+{
+    /// <summary>
+    /// Base class for "diffie-hellman" SHA-512 group algorithm implementations.
+    /// </summary>
+    internal abstract class KeyExchangeDiffieHellmanGroupSha512 : KeyExchangeDiffieHellmanGroupShaBase
+    {
+        /// <summary>
+        /// Gets the size, in bits, of the computed hash code.
+        /// </summary>
+        /// <value>
+        /// The size, in bits, of the computed hash code.
+        /// </value>
+        protected override int HashSize
+        {
+            get { return 512; }
+        }
+
+        /// <summary>
+        /// Hashes the specified data bytes.
+        /// </summary>
+        /// <param name="hashData">The hash data.</param>
+        /// <returns>
+        /// Hashed bytes
+        /// </returns>
+        protected override byte[] Hash(byte[] hashData)
+        {
+            using (var sha512 = CryptoAbstraction.CreateSHA512())
+            {
+                return sha512.ComputeHash(hashData);
+            }
+        }
+    }
+}

+ 83 - 0
src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupShaBase.cs

@@ -0,0 +1,83 @@
+using Renci.SshNet.Common;
+using Renci.SshNet.Messages.Transport;
+
+namespace Renci.SshNet.Security
+{
+    internal abstract class KeyExchangeDiffieHellmanGroupShaBase : KeyExchangeDiffieHellman
+    {
+        /// <summary>
+        /// Gets the group prime.
+        /// </summary>
+        /// <value>
+        /// The group prime.
+        /// </value>
+        public abstract BigInteger GroupPrime { get; }
+
+        /// <summary>
+        /// Calculates key exchange hash value.
+        /// </summary>
+        /// <returns>
+        /// Key exchange hash.
+        /// </returns>
+        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());
+        }
+
+        /// <summary>
+        /// Starts key exchange algorithm
+        /// </summary>
+        /// <param name="session">The session.</param>
+        /// <param name="message">Key exchange init message.</param>
+        public override void Start(Session session, KeyExchangeInitMessage message)
+        {
+            base.Start(session, message);
+
+            Session.RegisterMessage("SSH_MSG_KEXDH_REPLY");
+
+            Session.KeyExchangeDhReplyMessageReceived += Session_KeyExchangeDhReplyMessageReceived;
+
+            _prime = GroupPrime;
+            _group = new BigInteger(new byte[] { 2 });
+
+            PopulateClientExchangeValue();
+
+            SendMessage(new KeyExchangeDhInitMessage(_clientExchangeValue));
+        }
+
+        /// <summary>
+        /// Finishes key exchange algorithm.
+        /// </summary>
+        public override void Finish()
+        {
+            base.Finish();
+
+            Session.KeyExchangeDhReplyMessageReceived -= Session_KeyExchangeDhReplyMessageReceived;
+        }
+
+        private void Session_KeyExchangeDhReplyMessageReceived(object sender, MessageEventArgs<KeyExchangeDhReplyMessage> 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();
+        }
+    }
+}

+ 14 - 107
src/Renci.SshNet/Security/KeyExchangeEC.cs

@@ -1,5 +1,4 @@
-using System;
-using System.Text;
+using System.Text;
 using Renci.SshNet.Messages.Transport;
 using Renci.SshNet.Common;
 using Renci.SshNet.Abstractions;
@@ -69,19 +68,19 @@ namespace Renci.SshNet.Security
         /// </returns>
         protected override byte[] CalculateHash()
         {
-            var hashData = new _ExchangeHashData
-            {
-                ClientVersion = Session.ClientVersion,
-                ServerVersion = Session.ServerVersion,
-                ClientPayload = _clientPayload,
-                ServerPayload = _serverPayload,
-                HostKey = _hostKey,
-                ClientExchangeValue = _clientExchangeValue,
-                ServerExchangeValue = _serverExchangeValue,
-                SharedKey = SharedKey,
-            }.GetBytes();
-
-            return Hash(hashData);
+            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());
         }
 
         /// <summary>
@@ -119,97 +118,5 @@ namespace Renci.SshNet.Security
             _serverPayload = message.GetBytes();
             _clientPayload = Session.ClientInitMessage.GetBytes();
         }
-
-        /// <summary>
-        /// Handles the server DH reply message.
-        /// </summary>
-        /// <param name="hostKey">The host key.</param>
-        /// <param name="serverExchangeValue">The server exchange value.</param>
-        /// <param name="signature">The signature.</param>
-        protected virtual void HandleServerEcdhReply(byte[] hostKey, byte[] serverExchangeValue, byte[] signature)
-        {
-        }
-
-        internal class _ExchangeHashData : SshData
-        {
-            private byte[] _serverVersion;
-            private byte[] _clientVersion;
-            private byte[] _sharedKey;
-
-            public string ServerVersion
-            {
-                private get { return Utf8.GetString(_serverVersion, 0, _serverVersion.Length); }
-                set { _serverVersion = Utf8.GetBytes(value); }
-            }
-
-            public string ClientVersion
-            {
-                private get { return Utf8.GetString(_clientVersion, 0, _clientVersion.Length); }
-                set { _clientVersion = Utf8.GetBytes(value); }
-            }
-
-            public byte[] ClientPayload { get; set; }
-
-            public byte[] ServerPayload { get; set; }
-
-            public byte[] HostKey { get; set; }
-
-            public byte[] ClientExchangeValue { get; set; }
-
-            public byte[] ServerExchangeValue { get; set; }
-
-            public BigInteger SharedKey
-            {
-                private get { return _sharedKey.ToBigInteger(); }
-                set { _sharedKey = value.ToByteArray().Reverse(); }
-            }
-            /// <summary>
-            /// Gets the size of the message in bytes.
-            /// </summary>
-            /// <value>
-            /// The size of the messages in bytes.
-            /// </value>
-            protected override int BufferCapacity
-            {
-                get
-                {
-                    var capacity = base.BufferCapacity;
-                    capacity += 4; // ClientVersion length
-                    capacity += _clientVersion.Length; // ClientVersion
-                    capacity += 4; // ServerVersion length
-                    capacity += _serverVersion.Length; // ServerVersion
-                    capacity += 4; // ClientPayload length
-                    capacity += ClientPayload.Length; // ClientPayload
-                    capacity += 4; // ServerPayload length
-                    capacity += ServerPayload.Length; // ServerPayload
-                    capacity += 4; // HostKey length
-                    capacity += HostKey.Length; // HostKey
-                    capacity += 4; // ClientExchangeValue length
-                    capacity += ClientExchangeValue.Length; // ClientExchangeValue
-                    capacity += 4; // ServerExchangeValue length
-                    capacity += ServerExchangeValue.Length; // ServerExchangeValue
-                    capacity += 4; // SharedKey length
-                    capacity += _sharedKey.Length; // SharedKey
-                    return capacity;
-                }
-            }
-
-            protected override void LoadData()
-            {
-                throw new NotImplementedException();
-            }
-
-            protected override void SaveData()
-            {
-                WriteBinaryString(_clientVersion);
-                WriteBinaryString(_serverVersion);
-                WriteBinaryString(ClientPayload);
-                WriteBinaryString(ServerPayload);
-                WriteBinaryString(HostKey);
-                WriteBinaryString(ClientExchangeValue);
-                WriteBinaryString(ServerExchangeValue);
-                WriteBinaryString(_sharedKey);
-           }
-        }
     }
 }

+ 2 - 3
src/Renci.SshNet/Security/KeyExchangeECCurve25519.cs

@@ -84,16 +84,15 @@ namespace Renci.SshNet.Security
         /// <param name="hostKey">The host key.</param>
         /// <param name="serverExchangeValue">The server exchange value.</param>
         /// <param name="signature">The signature.</param>
-        protected override void HandleServerEcdhReply(byte[] hostKey, byte[] serverExchangeValue, byte[] signature)
+        private void HandleServerEcdhReply(byte[] hostKey, byte[] serverExchangeValue, byte[] signature)
         {
             _serverExchangeValue = serverExchangeValue;
             _hostKey = hostKey;
-            _serverExchangeValue = serverExchangeValue;
             _signature = signature;
 
             var sharedKey = new byte[MontgomeryCurve25519.PublicKeySizeInBytes];
             MontgomeryOperations.scalarmult(sharedKey, 0, _privateKey, 0, serverExchangeValue, 0);
-            SharedKey = sharedKey.ToBigInteger2();
+            SharedKey = sharedKey.ToBigNum2();
         }
     }
 }

+ 2 - 3
src/Renci.SshNet/Security/KeyExchangeECDH.cs

@@ -83,11 +83,10 @@ namespace Renci.SshNet.Security
         /// <param name="hostKey">The host key.</param>
         /// <param name="serverExchangeValue">The server exchange value.</param>
         /// <param name="signature">The signature.</param>
-        protected override void HandleServerEcdhReply(byte[] hostKey, byte[] serverExchangeValue, byte[] signature)
+        private void HandleServerEcdhReply(byte[] hostKey, byte[] serverExchangeValue, byte[] signature)
         {
             _serverExchangeValue = serverExchangeValue;
             _hostKey = hostKey;
-            _serverExchangeValue = serverExchangeValue;
             _signature = signature;
 
             var cordSize = (serverExchangeValue.Length - 1) / 2;
@@ -101,7 +100,7 @@ namespace Renci.SshNet.Security
             var publicKey = new ECPublicKeyParameters("ECDH", q, DomainParameters);
 
             var k1 = KeyAgreement.CalculateAgreement(publicKey);
-            SharedKey = k1.ToByteArray().ToBigInteger2();
+            SharedKey = k1.ToByteArray().ToBigNum2();
         }
     }
 }

+ 84 - 0
src/Renci.SshNet/Security/KeyExchangeHash.cs

@@ -0,0 +1,84 @@
+using Renci.SshNet.Common;
+using System;
+using System.Linq;
+
+namespace Renci.SshNet.Security
+{
+    internal class KeyExchangeHashData : SshData
+    {
+        private byte[] _serverVersion;
+        private byte[] _clientVersion;
+
+        public string ServerVersion
+        {
+            private get { return Utf8.GetString(_serverVersion, 0, _serverVersion.Length); }
+            set { _serverVersion = Utf8.GetBytes(value); }
+        }
+
+        public string ClientVersion
+        {
+            private get { return Utf8.GetString(_clientVersion, 0, _clientVersion.Length); }
+            set { _clientVersion = Utf8.GetBytes(value); }
+        }
+
+        public byte[] ClientPayload { get; set; }
+
+        public byte[] ServerPayload { get; set; }
+
+        public byte[] HostKey { get; set; }
+
+        public byte[] ClientExchangeValue { get; set; }
+
+        public byte[] ServerExchangeValue { get; set; }
+
+        public byte[] SharedKey { get; set; }
+
+        /// <summary>
+        /// Gets the size of the message in bytes.
+        /// </summary>
+        /// <value>
+        /// The size of the messages in bytes.
+        /// </value>
+        protected override int BufferCapacity
+        {
+            get
+            {
+                var capacity = base.BufferCapacity;
+                capacity += 4; // ClientVersion length
+                capacity += _clientVersion.Length; // ClientVersion
+                capacity += 4; // ServerVersion length
+                capacity += _serverVersion.Length; // ServerVersion
+                capacity += 4; // ClientPayload length
+                capacity += ClientPayload.Length; // ClientPayload
+                capacity += 4; // ServerPayload length
+                capacity += ServerPayload.Length; // ServerPayload
+                capacity += 4; // HostKey length
+                capacity += HostKey.Length; // HostKey
+                capacity += 4; // ClientExchangeValue length
+                capacity += ClientExchangeValue.Length; // ClientExchangeValue
+                capacity += 4; // ServerExchangeValue length
+                capacity += ServerExchangeValue.Length; // ServerExchangeValue
+                capacity += 4; // SharedKey length
+                capacity += SharedKey.Length; // SharedKey
+                return capacity;
+            }
+        }
+
+        protected override void LoadData()
+        {
+            throw new NotImplementedException();
+        }
+
+        protected override void SaveData()
+        {
+            WriteBinaryString(_clientVersion);
+            WriteBinaryString(_serverVersion);
+            WriteBinaryString(ClientPayload);
+            WriteBinaryString(ServerPayload);
+            WriteBinaryString(HostKey);
+            WriteBinaryString(ClientExchangeValue);
+            WriteBinaryString(ServerExchangeValue);
+            WriteBinaryString(SharedKey);
+        }
+    }
+}