Browse Source

Support an acceptable group of up to 8192 bits for SHA-1 and SHA-256 Diffie-Hellman Group and Key Exchange (issue #1973 and #1777), and refactor corresponding classes to avoid code duplication.

Gert Driesen 11 years ago
parent
commit
8c4e3119ef

+ 1 - 0
Renci.SshClient/Build/nuget/SSH.NET.nuspec

@@ -17,6 +17,7 @@ New Features:
 
     * Improved accuracy of IsConnected on .NET
     * Added support for ssh.com (SSH-2) private keys (issue #1987)
+    * Support an acceptable group of up to 8192 bits for SHA-1 and SHA-256 Diffie-Hellman Group and Key Exchange (issue #1973 and #1777)
 
 Fixes:
 

+ 7 - 1
Renci.SshClient/Renci.SshNet.NET35/Renci.SshNet.NET35.csproj

@@ -648,6 +648,9 @@
     <Compile Include="..\Renci.SshNet\Security\Cryptography\SymmetricCipher.cs">
       <Link>Security\Cryptography\SymmetricCipher.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet\Security\GroupExchangeHashData.cs">
+      <Link>Security\GroupExchangeHashData.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\Security\HostAlgorithm.cs">
       <Link>Security\HostAlgorithm.cs</Link>
     </Compile>
@@ -669,6 +672,9 @@
     <Compile Include="..\Renci.SshNet\Security\KeyExchangeDiffieHellmanGroupExchangeSha256.cs">
       <Link>Security\KeyExchangeDiffieHellmanGroupExchangeSha256.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet\Security\KeyExchangeDiffieHellmanGroupExchangeShaBase.cs">
+      <Link>Security\KeyExchangeDiffieHellmanGroupExchangeShaBase.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\Security\KeyExchangeDiffieHellmanGroupSha1.cs">
       <Link>Security\KeyExchangeDiffieHellmanGroupSha1.cs</Link>
     </Compile>
@@ -889,7 +895,7 @@
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <ProjectExtensions>
     <VisualStudio>
-      <UserProperties ProjectLinkReference="2f5f8c90-0bd1-424f-997c-7bc6280919d1" ProjectLinkerExcludeFilter="\\?desktop(\\.*)?$;\\?silverlight(\\.*)?$;\.desktop;\.silverlight;\.xaml;^service references(\\.*)?$;\.clientconfig;^web references(\\.*)?$" />
+      <UserProperties ProjectLinkerExcludeFilter="\\?desktop(\\.*)?$;\\?silverlight(\\.*)?$;\.desktop;\.silverlight;\.xaml;^service references(\\.*)?$;\.clientconfig;^web references(\\.*)?$" ProjectLinkReference="2f5f8c90-0bd1-424f-997c-7bc6280919d1" />
     </VisualStudio>
   </ProjectExtensions>
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 

+ 7 - 1
Renci.SshClient/Renci.SshNet.Silverlight/Renci.SshNet.Silverlight.csproj

@@ -612,6 +612,9 @@
     <Compile Include="..\Renci.SshNet\Security\Cryptography\SymmetricCipher.cs">
       <Link>Security\Cryptography\SymmetricCipher.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet\Security\GroupExchangeHashData.cs">
+      <Link>Security\GroupExchangeHashData.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\Security\HostAlgorithm.cs">
       <Link>Security\HostAlgorithm.cs</Link>
     </Compile>
@@ -633,6 +636,9 @@
     <Compile Include="..\Renci.SshNet\Security\KeyExchangeDiffieHellmanGroupExchangeSha256.cs">
       <Link>Security\KeyExchangeDiffieHellmanGroupExchangeSha256.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet\Security\KeyExchangeDiffieHellmanGroupExchangeShaBase.cs">
+      <Link>Security\KeyExchangeDiffieHellmanGroupExchangeShaBase.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\Security\KeyExchangeDiffieHellmanGroupSha1.cs">
       <Link>Security\KeyExchangeDiffieHellmanGroupSha1.cs</Link>
     </Compile>
@@ -847,7 +853,7 @@
       <FlavorProperties GUID="{A1591282-1198-4647-A2B1-27E5FF5F6F3B}">
         <SilverlightProjectProperties />
       </FlavorProperties>
-      <UserProperties ProjectLinkerExcludeFilter="\\?desktop(\\.*)?$;\\?silverlight(\\.*)?$;\.desktop;\.silverlight;\.xaml;^service references(\\.*)?$;\.clientconfig;^web references(\\.*)?$" ProjectLinkReference="2f5f8c90-0bd1-424f-997c-7bc6280919d1" />
+      <UserProperties ProjectLinkReference="2f5f8c90-0bd1-424f-997c-7bc6280919d1" ProjectLinkerExcludeFilter="\\?desktop(\\.*)?$;\\?silverlight(\\.*)?$;\.desktop;\.silverlight;\.xaml;^service references(\\.*)?$;\.clientconfig;^web references(\\.*)?$" />
     </VisualStudio>
   </ProjectExtensions>
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 

+ 7 - 1
Renci.SshClient/Renci.SshNet.Silverlight5/Renci.SshNet.Silverlight5.csproj

@@ -621,6 +621,9 @@
     <Compile Include="..\Renci.SshNet\Security\Cryptography\SymmetricCipher.cs">
       <Link>Security\Cryptography\SymmetricCipher.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet\Security\GroupExchangeHashData.cs">
+      <Link>Security\GroupExchangeHashData.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\Security\HostAlgorithm.cs">
       <Link>Security\HostAlgorithm.cs</Link>
     </Compile>
@@ -642,6 +645,9 @@
     <Compile Include="..\Renci.SshNet\Security\KeyExchangeDiffieHellmanGroupExchangeSha256.cs">
       <Link>Security\KeyExchangeDiffieHellmanGroupExchangeSha256.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet\Security\KeyExchangeDiffieHellmanGroupExchangeShaBase.cs">
+      <Link>Security\KeyExchangeDiffieHellmanGroupExchangeShaBase.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\Security\KeyExchangeDiffieHellmanGroupSha1.cs">
       <Link>Security\KeyExchangeDiffieHellmanGroupSha1.cs</Link>
     </Compile>
@@ -859,7 +865,7 @@
       <FlavorProperties GUID="{A1591282-1198-4647-A2B1-27E5FF5F6F3B}">
         <SilverlightProjectProperties />
       </FlavorProperties>
-      <UserProperties ProjectLinkerExcludeFilter="\\?desktop(\\.*)?$;\\?silverlight(\\.*)?$;\.desktop;\.silverlight;\.xaml;^service references(\\.*)?$;\.clientconfig;^web references(\\.*)?$" ProjectLinkReference="2f5f8c90-0bd1-424f-997c-7bc6280919d1" />
+      <UserProperties ProjectLinkReference="2f5f8c90-0bd1-424f-997c-7bc6280919d1" ProjectLinkerExcludeFilter="\\?desktop(\\.*)?$;\\?silverlight(\\.*)?$;\.desktop;\.silverlight;\.xaml;^service references(\\.*)?$;\.clientconfig;^web references(\\.*)?$" />
     </VisualStudio>
   </ProjectExtensions>
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 

+ 6 - 0
Renci.SshClient/Renci.SshNet.WindowsPhone/Renci.SshNet.WindowsPhone.csproj

@@ -604,6 +604,9 @@
     <Compile Include="..\Renci.SshNet\Security\Cryptography\SymmetricCipher.cs">
       <Link>Security\Cryptography\SymmetricCipher.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet\Security\GroupExchangeHashData.cs">
+      <Link>Security\GroupExchangeHashData.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\Security\HostAlgorithm.cs">
       <Link>Security\HostAlgorithm.cs</Link>
     </Compile>
@@ -625,6 +628,9 @@
     <Compile Include="..\Renci.SshNet\Security\KeyExchangeDiffieHellmanGroupExchangeSha256.cs">
       <Link>Security\KeyExchangeDiffieHellmanGroupExchangeSha256.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet\Security\KeyExchangeDiffieHellmanGroupExchangeShaBase.cs">
+      <Link>Security\KeyExchangeDiffieHellmanGroupExchangeShaBase.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\Security\KeyExchangeDiffieHellmanGroupSha1.cs">
       <Link>Security\KeyExchangeDiffieHellmanGroupSha1.cs</Link>
     </Compile>

+ 7 - 1
Renci.SshClient/Renci.SshNet.WindowsPhone8/Renci.SshNet.WindowsPhone8.csproj

@@ -651,6 +651,9 @@
     <Compile Include="..\Renci.SshNet\Security\Cryptography\SymmetricCipher.cs">
       <Link>Security\Cryptography\SymmetricCipher.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet\Security\GroupExchangeHashData.cs">
+      <Link>Security\GroupExchangeHashData.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\Security\HostAlgorithm.cs">
       <Link>Security\HostAlgorithm.cs</Link>
     </Compile>
@@ -672,6 +675,9 @@
     <Compile Include="..\Renci.SshNet\Security\KeyExchangeDiffieHellmanGroupExchangeSha256.cs">
       <Link>Security\KeyExchangeDiffieHellmanGroupExchangeSha256.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet\Security\KeyExchangeDiffieHellmanGroupExchangeShaBase.cs">
+      <Link>Security\KeyExchangeDiffieHellmanGroupExchangeShaBase.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\Security\KeyExchangeDiffieHellmanGroupSha1.cs">
       <Link>Security\KeyExchangeDiffieHellmanGroupSha1.cs</Link>
     </Compile>
@@ -883,7 +889,7 @@
   <Import Project="$(MSBuildExtensionsPath)\Microsoft\$(TargetFrameworkIdentifier)\$(TargetFrameworkVersion)\Microsoft.$(TargetFrameworkIdentifier).CSharp.targets" />
   <ProjectExtensions>
     <VisualStudio>
-      <UserProperties ProjectLinkerExcludeFilter="\\?desktop(\\.*)?$;\\?silverlight(\\.*)?$;\.desktop;\.silverlight;\.xaml;^service references(\\.*)?$;\.clientconfig;^web references(\\.*)?$" ProjectLinkReference="2f5f8c90-0bd1-424f-997c-7bc6280919d1" />
+      <UserProperties ProjectLinkReference="2f5f8c90-0bd1-424f-997c-7bc6280919d1" ProjectLinkerExcludeFilter="\\?desktop(\\.*)?$;\\?silverlight(\\.*)?$;\.desktop;\.silverlight;\.xaml;^service references(\\.*)?$;\.clientconfig;^web references(\\.*)?$" />
     </VisualStudio>
   </ProjectExtensions>
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 

+ 2 - 0
Renci.SshClient/Renci.SshNet/Renci.SshNet.csproj

@@ -159,6 +159,8 @@
     <Compile Include="Security\Cryptography\Hashes\SHA512Hash.cs">
       <SubType>Code</SubType>
     </Compile>
+    <Compile Include="Security\GroupExchangeHashData.cs" />
+    <Compile Include="Security\KeyExchangeDiffieHellmanGroupExchangeShaBase.cs" />
     <Compile Include="Security\KeyExchangeEllipticCurveDiffieHellman.cs" />
     <Compile Include="ShellStream.NET40.cs" />
     <Compile Include="ExpectAsyncResult.cs" />

+ 56 - 0
Renci.SshClient/Renci.SshNet/Security/GroupExchangeHashData.cs

@@ -0,0 +1,56 @@
+using System;
+using Renci.SshNet.Common;
+
+namespace Renci.SshNet.Security
+{
+    internal class GroupExchangeHashData : SshData
+    {
+        public string ServerVersion { get; set; }
+
+        public string ClientVersion { get; set; }
+
+        public byte[] ClientPayload { get; set; }
+
+        public byte[] ServerPayload { get; set; }
+
+        public byte[] HostKey { get; set; }
+
+        public UInt32 MinimumGroupSize { get; set; }
+
+        public UInt32 PreferredGroupSize { get; set; }
+
+        public UInt32 MaximumGroupSize { get; set; }
+
+        public BigInteger Prime { get; set; }
+
+        public BigInteger SubGroup { get; set; }
+
+        public BigInteger ClientExchangeValue { get; set; }
+
+        public BigInteger ServerExchangeValue { get; set; }
+
+        public BigInteger SharedKey { get; set; }
+
+        protected override void LoadData()
+        {
+            throw new NotImplementedException();
+        }
+
+        protected override void SaveData()
+        {
+            this.Write(this.ClientVersion);
+            this.Write(this.ServerVersion);
+            this.WriteBinaryString(this.ClientPayload);
+            this.WriteBinaryString(this.ServerPayload);
+            this.WriteBinaryString(this.HostKey);
+            this.Write(this.MinimumGroupSize);
+            this.Write(this.PreferredGroupSize);
+            this.Write(this.MaximumGroupSize);
+            this.Write(this.Prime);
+            this.Write(this.SubGroup);
+            this.Write(this.ClientExchangeValue);
+            this.Write(this.ServerExchangeValue);
+            this.Write(this.SharedKey);
+        }
+    }
+}

+ 2 - 147
Renci.SshClient/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeSha1.cs

@@ -1,14 +1,9 @@
-using System;
-using Renci.SshNet.Messages.Transport;
-using Renci.SshNet.Messages;
-using Renci.SshNet.Common;
-
-namespace Renci.SshNet.Security
+namespace Renci.SshNet.Security
 {
     /// <summary>
     /// Represents "diffie-hellman-group-exchange-sha1" algorithm implementation.
     /// </summary>
-    internal class KeyExchangeDiffieHellmanGroupExchangeSha1 : KeyExchangeDiffieHellman
+    public class KeyExchangeDiffieHellmanGroupExchangeSha1 : KeyExchangeDiffieHellmanGroupExchangeShaBase
     {
         /// <summary>
         /// Gets algorithm name.
@@ -17,145 +12,5 @@ namespace Renci.SshNet.Security
         {
             get { return "diffie-hellman-group-exchange-sha1"; }
         }
-
-        /// <summary>
-        /// Calculates key exchange hash value.
-        /// </summary>
-        /// <returns>
-        /// Key exchange hash.
-        /// </returns>
-        protected override byte[] CalculateHash()
-        {
-            var hashData = new _ExchangeHashData
-            {
-                ClientVersion = this.Session.ClientVersion,
-                ServerVersion = this.Session.ServerVersion,
-                ClientPayload = this._clientPayload,
-                ServerPayload = this._serverPayload,
-                HostKey = this._hostKey,
-                MinimumGroupSize = 1024,
-                PreferredGroupSize = 1024,
-                MaximumGroupSize = 1024,
-                Prime = this._prime,
-                SubGroup = this._group,
-                ClientExchangeValue = this._clientExchangeValue,
-                ServerExchangeValue = this._serverExchangeValue,
-                SharedKey = this.SharedKey,
-            }.GetBytes();
-
-            return this.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);
-
-            this.Session.RegisterMessage("SSH_MSG_KEX_DH_GEX_GROUP");
-            this.Session.RegisterMessage("SSH_MSG_KEX_DH_GEX_REPLY");
-
-            this.Session.MessageReceived += Session_MessageReceived;
-
-            //  1. send SSH_MSG_KEY_DH_GEX_REQUEST
-            this.SendMessage(new KeyExchangeDhGroupExchangeRequest(1024, 1024, 1024));
-        }
-
-        /// <summary>
-        /// Finishes key exchange algorithm.
-        /// </summary>
-        public override void Finish()
-        {
-            base.Finish();
-
-            this.Session.MessageReceived -= Session_MessageReceived;
-        }
-
-        private void Session_MessageReceived(object sender, MessageEventArgs<Message> e)
-        {
-            var groupMessage = e.Message as KeyExchangeDhGroupExchangeGroup;
-
-            if (groupMessage != null)
-            {
-                //  Unregister message once received
-                this.Session.UnRegisterMessage("SSH_MSG_KEX_DH_GEX_GROUP");
-
-                //  2. Receive SSH_MSG_KEX_DH_GEX_GROUP
-                this._prime = groupMessage.SafePrime;
-                this._group = groupMessage.SubGroup;
-
-                this.PopulateClientExchangeValue();
-
-                //  3. Send SSH_MSG_KEX_DH_GEX_INIT
-                this.SendMessage(new KeyExchangeDhGroupExchangeInit(this._clientExchangeValue));
-
-            }
-            var replyMessage = e.Message as KeyExchangeDhGroupExchangeReply;
-
-            if (replyMessage != null)
-            {
-                //  Unregister message once received
-                this.Session.UnRegisterMessage("SSH_MSG_KEX_DH_GEX_REPLY");
-
-                this.HandleServerDhReply(replyMessage.HostKey, replyMessage.F, replyMessage.Signature);
-
-                //  When SSH_MSG_KEX_DH_GEX_REPLY received key exchange is completed
-                this.Finish();
-            }
-        }
-        
-        private class _ExchangeHashData : SshData
-        {
-            public string ServerVersion { get; set; }
-
-            public string ClientVersion { get; set; }
-
-            public byte[] ClientPayload { get; set; }
-
-            public byte[] ServerPayload { get; set; }
-
-            public byte[] HostKey { get; set; }
-
-            public UInt32 MinimumGroupSize { get; set; }
-
-            public UInt32 PreferredGroupSize { get; set; }
-
-            public UInt32 MaximumGroupSize { get; set; }
-
-            public BigInteger Prime { get; set; }
-
-            public BigInteger SubGroup { get; set; }
-
-            public BigInteger ClientExchangeValue { get; set; }
-
-            public BigInteger ServerExchangeValue { get; set; }
-
-            public BigInteger SharedKey { get; set; }
-
-            protected override void LoadData()
-            {
-                throw new NotImplementedException();
-            }
-
-            protected override void SaveData()
-            {
-                this.Write(this.ClientVersion);
-                this.Write(this.ServerVersion);
-                this.WriteBinaryString(this.ClientPayload);
-                this.WriteBinaryString(this.ServerPayload);
-                this.WriteBinaryString(this.HostKey);
-                this.Write(this.MinimumGroupSize);
-                this.Write(this.PreferredGroupSize);
-                this.Write(this.MaximumGroupSize);
-                this.Write(this.Prime);
-                this.Write(this.SubGroup);
-                this.Write(this.ClientExchangeValue);
-                this.Write(this.ServerExchangeValue);
-                this.Write(this.SharedKey);
-            }
-        }
     }
 }

+ 2 - 146
Renci.SshClient/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeSha256.cs

@@ -1,15 +1,11 @@
-using System;
-using Renci.SshNet.Messages.Transport;
-using Renci.SshNet.Messages;
-using Renci.SshNet.Common;
-using Renci.SshNet.Security.Cryptography;
+using Renci.SshNet.Security.Cryptography;
 
 namespace Renci.SshNet.Security
 {
     /// <summary>
     /// Represents "diffie-hellman-group-exchange-sha256" algorithm implementation.
     /// </summary>
-    public class KeyExchangeDiffieHellmanGroupExchangeSha256 : KeyExchangeDiffieHellman
+    public class KeyExchangeDiffieHellmanGroupExchangeSha256 : KeyExchangeDiffieHellmanGroupExchangeShaBase
     {
         /// <summary>
         /// Gets algorithm name.
@@ -19,63 +15,6 @@ namespace Renci.SshNet.Security
             get { return "diffie-hellman-group-exchange-sha256"; }
         }
 
-        /// <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);
-
-            this.Session.RegisterMessage("SSH_MSG_KEX_DH_GEX_GROUP");
-            this.Session.RegisterMessage("SSH_MSG_KEX_DH_GEX_REPLY");
-
-            this.Session.MessageReceived += Session_MessageReceived;
-
-            //  1. send SSH_MSG_KEY_DH_GEX_REQUEST
-            this.SendMessage(new KeyExchangeDhGroupExchangeRequest(1024,1024,1024));
-            
-        }
-
-        /// <summary>
-        /// Finishes key exchange algorithm.
-        /// </summary>
-        public override void Finish()
-        {
-            base.Finish();
-
-            this.Session.MessageReceived -= Session_MessageReceived;
-        }
-
-        /// <summary>
-        /// Calculates key exchange hash value.
-        /// </summary>
-        /// <returns>
-        /// Key exchange hash.
-        /// </returns>
-        protected override byte[] CalculateHash()
-        {
-            var hashData = new _ExchangeHashData
-            {
-                ClientVersion = this.Session.ClientVersion,
-                ServerVersion = this.Session.ServerVersion,
-                ClientPayload = this._clientPayload,
-                ServerPayload = this._serverPayload,
-                HostKey = this._hostKey,
-                MinimumGroupSize = 1024,
-                PreferredGroupSize = 1024,
-                MaximumGroupSize = 1024,
-                Prime = this._prime,
-                SubGroup = this._group,
-                ClientExchangeValue = this._clientExchangeValue,
-                ServerExchangeValue = this._serverExchangeValue,
-                SharedKey = this.SharedKey,
-            }.GetBytes();
-
-            return this.Hash(hashData);
-        }
-
         /// <summary>
         /// Hashes the specified data bytes.
         /// </summary>
@@ -90,88 +29,5 @@ namespace Renci.SshNet.Security
                 return md.ComputeHash(hashBytes);
             }
         }
-
-        private void Session_MessageReceived(object sender, MessageEventArgs<Message> e)
-        {
-            var groupMessage = e.Message as KeyExchangeDhGroupExchangeGroup;
-
-            if (groupMessage != null)
-            {
-                //  Unregister message once received
-                this.Session.UnRegisterMessage("SSH_MSG_KEX_DH_GEX_GROUP");
-
-                //  2. Receive SSH_MSG_KEX_DH_GEX_GROUP
-                this._prime = groupMessage.SafePrime;
-                this._group = groupMessage.SubGroup;
-
-                this.PopulateClientExchangeValue();
-
-                //  3. Send SSH_MSG_KEX_DH_GEX_INIT
-                this.SendMessage(new KeyExchangeDhGroupExchangeInit(this._clientExchangeValue));
-            }
-            var replyMessage = e.Message as KeyExchangeDhGroupExchangeReply;
-
-            if (replyMessage != null)
-            {
-                //  Unregister message once received
-                this.Session.UnRegisterMessage("SSH_MSG_KEX_DH_GEX_REPLY");
-
-                this.HandleServerDhReply(replyMessage.HostKey, replyMessage.F, replyMessage.Signature);
-
-                //  When SSH_MSG_KEX_DH_GEX_REPLY received key exchange is completed
-                this.Finish();
-            }
-        }
-
-        private class _ExchangeHashData : SshData
-        {
-            public string ServerVersion { get; set; }
-
-            public string ClientVersion { get; set; }
-
-            public byte[] ClientPayload { get; set; }
-
-            public byte[] ServerPayload { get; set; }
-
-            public byte[] HostKey { get; set; }
-
-            public UInt32 MinimumGroupSize { get; set; }
-
-            public UInt32 PreferredGroupSize { get; set; }
-
-            public UInt32 MaximumGroupSize { get; set; }
-
-            public BigInteger Prime { get; set; }
-
-            public BigInteger SubGroup { get; set; }
-
-            public BigInteger ClientExchangeValue { get; set; }
-
-            public BigInteger ServerExchangeValue { get; set; }
-
-            public BigInteger SharedKey { get; set; }
-
-            protected override void LoadData()
-            {
-                throw new NotImplementedException();
-            }
-
-            protected override void SaveData()
-            {
-                this.Write(this.ClientVersion);
-                this.Write(this.ServerVersion);
-                this.WriteBinaryString(this.ClientPayload);
-                this.WriteBinaryString(this.ServerPayload);
-                this.WriteBinaryString(this.HostKey);
-                this.Write(this.MinimumGroupSize);
-                this.Write(this.PreferredGroupSize);
-                this.Write(this.MaximumGroupSize);
-                this.Write(this.Prime);
-                this.Write(this.SubGroup);
-                this.Write(this.ClientExchangeValue);
-                this.Write(this.ServerExchangeValue);
-                this.Write(this.SharedKey);
-            }
-        }
     }
 }

+ 102 - 0
Renci.SshClient/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeShaBase.cs

@@ -0,0 +1,102 @@
+using Renci.SshNet.Messages;
+using Renci.SshNet.Messages.Transport;
+
+namespace Renci.SshNet.Security
+{
+    public abstract class KeyExchangeDiffieHellmanGroupExchangeShaBase : KeyExchangeDiffieHellman
+    {
+        private const int MinimumGroupSize = 1024;
+        private const int PreferredGroupSize = 1024;
+        private const int MaximumProupSize = 8192;
+
+        /// <summary>
+        /// Calculates key exchange hash value.
+        /// </summary>
+        /// <returns>
+        /// Key exchange hash.
+        /// </returns>
+        protected override byte[] CalculateHash()
+        {
+            var hashData = 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,
+                }.GetBytes();
+
+            return this.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_KEX_DH_GEX_GROUP");
+            Session.RegisterMessage("SSH_MSG_KEX_DH_GEX_REPLY");
+
+            Session.MessageReceived += Session_MessageReceived;
+
+            //  1. send SSH_MSG_KEY_DH_GEX_REQUEST
+            SendMessage(new KeyExchangeDhGroupExchangeRequest(MinimumGroupSize, PreferredGroupSize,
+                MaximumProupSize));
+        }
+
+        /// <summary>
+        /// Finishes key exchange algorithm.
+        /// </summary>
+        public override void Finish()
+        {
+            base.Finish();
+
+            Session.MessageReceived -= Session_MessageReceived;
+        }
+
+        private void Session_MessageReceived(object sender, MessageEventArgs<Message> e)
+        {
+            var groupMessage = e.Message as KeyExchangeDhGroupExchangeGroup;
+            if (groupMessage != null)
+            {
+                //  Unregister message once received
+                Session.UnRegisterMessage("SSH_MSG_KEX_DH_GEX_GROUP");
+
+                //  2. Receive SSH_MSG_KEX_DH_GEX_GROUP
+                _prime = groupMessage.SafePrime;
+                _group = groupMessage.SubGroup;
+
+                PopulateClientExchangeValue();
+
+                //  3. Send SSH_MSG_KEX_DH_GEX_INIT
+                SendMessage(new KeyExchangeDhGroupExchangeInit(_clientExchangeValue));
+            }
+            else
+            {
+                var replyMessage = e.Message as KeyExchangeDhGroupExchangeReply;
+                if (replyMessage != null)
+                {
+                    //  Unregister message once received
+                    Session.UnRegisterMessage("SSH_MSG_KEX_DH_GEX_REPLY");
+
+                    HandleServerDhReply(replyMessage.HostKey, replyMessage.F, replyMessage.Signature);
+
+                    //  When SSH_MSG_KEX_DH_GEX_REPLY received key exchange is completed
+                    Finish();
+                }
+            }
+        }
+    }
+}