You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by gn...@apache.org on 2015/03/30 11:17:53 UTC

[4/6] mina-sshd git commit: [SSHD-436] Refactor kex factories

[SSHD-436] Refactor kex factories


Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/73551939
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/73551939
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/73551939

Branch: refs/heads/master
Commit: 73551939d8dd6f10bbc7fecefd3abc77df42f54d
Parents: 7ea0788
Author: Guillaume Nodet <gn...@apache.org>
Authored: Thu Mar 26 16:20:26 2015 +0100
Committer: Guillaume Nodet <gn...@apache.org>
Committed: Mon Mar 30 10:52:43 2015 +0200

----------------------------------------------------------------------
 .../main/java/org/apache/sshd/SshBuilder.java   | 152 +++++----
 .../client/kex/AbstractDHClientKeyExchange.java |  52 +++
 .../sshd/client/kex/AbstractDHGClient.java      | 144 ---------
 .../java/org/apache/sshd/client/kex/DHG1.java   |  55 ----
 .../java/org/apache/sshd/client/kex/DHG14.java  |  57 ----
 .../org/apache/sshd/client/kex/DHGClient.java   | 131 ++++++++
 .../java/org/apache/sshd/client/kex/DHGEX.java  | 195 ------------
 .../org/apache/sshd/client/kex/DHGEX256.java    |  58 ----
 .../org/apache/sshd/client/kex/DHGEXClient.java | 160 ++++++++++
 .../org/apache/sshd/client/kex/ECDHP256.java    |  53 ----
 .../org/apache/sshd/client/kex/ECDHP384.java    |  53 ----
 .../org/apache/sshd/client/kex/ECDHP521.java    |  53 ----
 .../apache/sshd/common/FactoryManagerUtils.java |  18 +-
 .../org/apache/sshd/common/NamedFactory.java    |  44 ++-
 .../org/apache/sshd/common/NamedResource.java   |  30 ++
 .../org/apache/sshd/common/ServiceFactory.java  |  26 +-
 .../org/apache/sshd/common/kex/AbstractDH.java  |  10 +-
 .../sshd/common/kex/BuiltinDHFactories.java     | 184 +++++++++++
 .../java/org/apache/sshd/common/kex/DH.java     | 118 -------
 .../org/apache/sshd/common/kex/DHFactory.java   |  34 ++
 .../java/org/apache/sshd/common/kex/DHG.java    | 119 +++++++
 .../java/org/apache/sshd/common/kex/ECDH.java   |   9 +-
 .../common/kex/dh/AbstractDHKeyExchange.java    |  67 ++++
 .../sshd/server/kex/AbstractDHGServer.java      | 151 ---------
 .../server/kex/AbstractDHServerKeyExchange.java |  50 +++
 .../java/org/apache/sshd/server/kex/DHG1.java   |  54 ----
 .../java/org/apache/sshd/server/kex/DHG14.java  |  58 ----
 .../java/org/apache/sshd/server/kex/DHGEX.java  | 314 -------------------
 .../org/apache/sshd/server/kex/DHGEX256.java    |  55 ----
 .../org/apache/sshd/server/kex/DHGEXServer.java | 283 +++++++++++++++++
 .../org/apache/sshd/server/kex/DHGServer.java   | 136 ++++++++
 .../org/apache/sshd/server/kex/ECDHP256.java    |  53 ----
 .../org/apache/sshd/server/kex/ECDHP384.java    |  53 ----
 .../org/apache/sshd/server/kex/ECDHP521.java    |  53 ----
 .../src/test/java/org/apache/sshd/KexTest.java  | 153 ---------
 .../src/test/java/org/apache/sshd/LoadTest.java |  79 ++---
 .../org/apache/sshd/client/kex/KexTest.java     | 147 +++++++++
 .../sshd/common/kex/BuiltinDHFactoriesTest.java |  44 +++
 38 files changed, 1621 insertions(+), 1884 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/73551939/sshd-core/src/main/java/org/apache/sshd/SshBuilder.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/SshBuilder.java b/sshd-core/src/main/java/org/apache/sshd/SshBuilder.java
index bac6163..e441457 100644
--- a/sshd-core/src/main/java/org/apache/sshd/SshBuilder.java
+++ b/sshd-core/src/main/java/org/apache/sshd/SshBuilder.java
@@ -24,6 +24,8 @@ import java.util.Collections;
 import java.util.List;
 
 import org.apache.sshd.client.ServerKeyVerifier;
+import org.apache.sshd.client.kex.DHGClient;
+import org.apache.sshd.client.kex.DHGEXClient;
 import org.apache.sshd.client.keyverifier.AcceptAllServerKeyVerifier;
 import org.apache.sshd.common.AbstractFactoryManager;
 import org.apache.sshd.common.Channel;
@@ -43,12 +45,14 @@ import org.apache.sshd.common.file.FileSystemFactory;
 import org.apache.sshd.common.file.nativefs.NativeFileSystemFactory;
 import org.apache.sshd.common.forward.DefaultTcpipForwarderFactory;
 import org.apache.sshd.common.forward.TcpipServerChannel;
+import org.apache.sshd.common.kex.BuiltinDHFactories;
 import org.apache.sshd.common.mac.HMACMD5;
 import org.apache.sshd.common.mac.HMACMD596;
 import org.apache.sshd.common.mac.HMACSHA1;
 import org.apache.sshd.common.mac.HMACSHA196;
 import org.apache.sshd.common.mac.HMACSHA256;
 import org.apache.sshd.common.mac.HMACSHA512;
+import org.apache.sshd.common.kex.DHFactory;
 import org.apache.sshd.common.random.BouncyCastleRandom;
 import org.apache.sshd.common.random.JceRandom;
 import org.apache.sshd.common.random.SingletonRandomFactory;
@@ -63,6 +67,8 @@ import org.apache.sshd.server.global.CancelTcpipForwardHandler;
 import org.apache.sshd.server.global.KeepAliveHandler;
 import org.apache.sshd.server.global.NoMoreSessionsHandler;
 import org.apache.sshd.server.global.TcpipForwardHandler;
+import org.apache.sshd.server.kex.DHGEXServer;
+import org.apache.sshd.server.kex.DHGServer;
 
 /**
  * A builder object for creating SshServer instances.
@@ -287,7 +293,7 @@ public class SshBuilder {
          * ciphers according to the <tt>ignoreUnsupported</tt> parameter
          * @see BuiltinCiphers#isSupported()
          */
-        protected static List<NamedFactory<Cipher>> setUpDefaultCiphers(boolean ignoreUnsupported) {
+        public static List<NamedFactory<Cipher>> setUpDefaultCiphers(boolean ignoreUnsupported) {
             List<NamedFactory<Cipher>> avail = new ArrayList<NamedFactory<Cipher>>(DEFAULT_CIPHERS_PREFERENCE.size());
             for (BuiltinCiphers c : DEFAULT_CIPHERS_PREFERENCE) {
                 if (ignoreUnsupported || c.isSupported()) {
@@ -297,6 +303,26 @@ public class SshBuilder {
 
             return avail;
         }
+        
+        /**
+         * The default {@link BuiltinDHFactories} setup in order of preference
+         * as specified by <A HREF="https://www.freebsd.org/cgi/man.cgi?query=ssh_config&sektion=5">
+         * ssh_config(5)</A> 
+         */
+        public static final List<BuiltinDHFactories> DEFAULT_KEX_PREFERENCE=
+                Collections.unmodifiableList(
+                        Arrays.asList(
+                                BuiltinDHFactories.ecdhp521,
+                                BuiltinDHFactories.ecdhp384,
+                                BuiltinDHFactories.ecdhp256,
+                                
+                                BuiltinDHFactories.dhgex256,
+                                BuiltinDHFactories.dhgex,
+                                
+                                BuiltinDHFactories.dhg14,
+                                BuiltinDHFactories.dhg1
+                        ));
+
     }
 
     /**
@@ -314,35 +340,8 @@ public class SshBuilder {
         @Override
         protected ClientBuilder fillWithDefaultValues() {
             super.fillWithDefaultValues();
-            if (SecurityUtils.isBouncyCastleRegistered()) {
-                if (keyExchangeFactories == null) {
-                    keyExchangeFactories = Arrays.asList(
-                            new org.apache.sshd.client.kex.DHGEX256.Factory(),
-                            new org.apache.sshd.client.kex.DHGEX.Factory(),
-                            new org.apache.sshd.client.kex.ECDHP256.Factory(),
-                            new org.apache.sshd.client.kex.ECDHP384.Factory(),
-                            new org.apache.sshd.client.kex.ECDHP521.Factory(),
-                            new org.apache.sshd.client.kex.DHG14.Factory(),
-                            new org.apache.sshd.client.kex.DHG1.Factory());
-                }
-            // EC keys are not supported until OpenJDK 7
-            } else if (SecurityUtils.hasEcc()) {
-                if (keyExchangeFactories == null) {
-                    keyExchangeFactories = Arrays.asList(
-                            new org.apache.sshd.client.kex.DHGEX256.Factory(),
-                            new org.apache.sshd.client.kex.DHGEX.Factory(),
-                            new org.apache.sshd.client.kex.ECDHP256.Factory(),
-                            new org.apache.sshd.client.kex.ECDHP384.Factory(),
-                            new org.apache.sshd.client.kex.ECDHP521.Factory(),
-                            new org.apache.sshd.client.kex.DHG1.Factory());
-                }
-            } else {
-                if (keyExchangeFactories == null) {
-                    keyExchangeFactories = Arrays.asList(
-                            new org.apache.sshd.client.kex.DHGEX256.Factory(),
-                            new org.apache.sshd.client.kex.DHGEX.Factory(),
-                            new org.apache.sshd.client.kex.DHG1.Factory());
-                }
+            if (keyExchangeFactories == null) {
+                keyExchangeFactories = setUpDefaultKeyExchanges(false);
             }
             if (channelFactories == null) {
                 channelFactories = Arrays.<NamedFactory<Channel>>asList(
@@ -363,6 +362,37 @@ public class SshBuilder {
             client.setServerKeyVerifier(serverKeyVerifier);
             return client;
         }
+
+        /**
+         * @param ignoreUnsupported If {@code true} then all the default
+         * key exchanges are included, regardless of whether they are currently
+         * supported by the JCE. Otherwise, only the supported ones out of the
+         * list are included
+         * @return A {@link List} of the default {@link NamedFactory}
+         * instances of the {@link KeyExchange}s according to the preference
+         * order defined by {@link #DEFAULT_KEX_PREFERENCE}.
+         * <B>Note:</B> the list may be filtered to exclude unsupported JCE
+         * key exchanges according to the <tt>ignoreUnsupported</tt> parameter
+         * @see BuiltinDHFactories#isSupported()
+         */
+        public static List<NamedFactory<KeyExchange>> setUpDefaultKeyExchanges(boolean ignoreUnsupported) {
+            List<NamedFactory<KeyExchange>> avail = new ArrayList<>(DEFAULT_KEX_PREFERENCE.size());
+            for (BuiltinDHFactories f : BuiltinDHFactories.VALUES) {
+                if (ignoreUnsupported || f.isSupported()) {
+                    avail.add(getKeyExchangeFactory(f));
+                }
+            }
+            return avail;
+        }
+
+        public static NamedFactory<KeyExchange> getKeyExchangeFactory(DHFactory factory) {
+            if (factory.isGroupExchange()) {
+                return DHGEXClient.newFactory(factory);
+            } else {
+                return DHGClient.newFactory(factory);
+            }
+        }
+
     }
 
     /**
@@ -373,35 +403,8 @@ public class SshBuilder {
         @Override
         protected ServerBuilder fillWithDefaultValues() {
             super.fillWithDefaultValues();
-            if (SecurityUtils.isBouncyCastleRegistered()) {
-                if (keyExchangeFactories == null) {
-                    keyExchangeFactories = Arrays.asList(
-                            new org.apache.sshd.server.kex.DHGEX256.Factory(),
-                            new org.apache.sshd.server.kex.DHGEX.Factory(),
-                            new org.apache.sshd.server.kex.ECDHP256.Factory(),
-                            new org.apache.sshd.server.kex.ECDHP384.Factory(),
-                            new org.apache.sshd.server.kex.ECDHP521.Factory(),
-                            new org.apache.sshd.server.kex.DHG14.Factory(),
-                            new org.apache.sshd.server.kex.DHG1.Factory());
-                }
-            // EC keys are not supported until OpenJDK 7
-            } else if (SecurityUtils.hasEcc()) {
-                if (keyExchangeFactories == null) {
-                    keyExchangeFactories = Arrays.asList(
-                            new org.apache.sshd.server.kex.DHGEX256.Factory(),
-                            new org.apache.sshd.server.kex.DHGEX.Factory(),
-                            new org.apache.sshd.server.kex.ECDHP256.Factory(),
-                            new org.apache.sshd.server.kex.ECDHP384.Factory(),
-                            new org.apache.sshd.server.kex.ECDHP521.Factory(),
-                            new org.apache.sshd.server.kex.DHG1.Factory());
-                }
-            } else {
-                if (keyExchangeFactories == null) {
-                    keyExchangeFactories = Arrays.asList(
-                            new org.apache.sshd.server.kex.DHGEX256.Factory(),
-                            new org.apache.sshd.server.kex.DHGEX.Factory(),
-                            new org.apache.sshd.server.kex.DHG1.Factory());
-                }
+            if (keyExchangeFactories == null) {
+                keyExchangeFactories = setUpDefaultKeyExchanges(false);
             }
             if (channelFactories == null) {
                 channelFactories = Arrays.asList(
@@ -420,6 +423,37 @@ public class SshBuilder {
             }
             return me();
         }
+
+        /**
+         * @param ignoreUnsupported If {@code true} then all the default
+         * key exchanges are included, regardless of whether they are currently
+         * supported by the JCE. Otherwise, only the supported ones out of the
+         * list are included
+         * @return A {@link List} of the default {@link NamedFactory}
+         * instances of the {@link KeyExchange}s according to the preference
+         * order defined by {@link #DEFAULT_KEX_PREFERENCE}.
+         * <B>Note:</B> the list may be filtered to exclude unsupported JCE
+         * key exchanges according to the <tt>ignoreUnsupported</tt> parameter
+         * @see BuiltinDHFactories#isSupported()
+         */
+        public static List<NamedFactory<KeyExchange>> setUpDefaultKeyExchanges(boolean ignoreUnsupported) {
+            List<NamedFactory<KeyExchange>> avail = new ArrayList<>(DEFAULT_KEX_PREFERENCE.size());
+            for (BuiltinDHFactories f : BuiltinDHFactories.VALUES) {
+                if (ignoreUnsupported || f.isSupported()) {
+                    avail.add(getKeyExchangeFactory(f));
+                }
+            }
+            return avail;
+        }
+
+        public static NamedFactory<KeyExchange> getKeyExchangeFactory(DHFactory factory) {
+            if (factory.isGroupExchange()) {
+                return DHGEXServer.newFactory(factory);
+            } else {
+                return DHGServer.newFactory(factory);
+            }
+        }
+
     }
 
 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/73551939/sshd-core/src/main/java/org/apache/sshd/client/kex/AbstractDHClientKeyExchange.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/kex/AbstractDHClientKeyExchange.java b/sshd-core/src/main/java/org/apache/sshd/client/kex/AbstractDHClientKeyExchange.java
new file mode 100644
index 0000000..077f159
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/kex/AbstractDHClientKeyExchange.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sshd.client.kex;
+
+import java.security.PublicKey;
+
+import org.apache.sshd.client.session.ClientSessionImpl;
+import org.apache.sshd.common.kex.dh.AbstractDHKeyExchange;
+import org.apache.sshd.common.session.AbstractSession;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public abstract class AbstractDHClientKeyExchange extends AbstractDHKeyExchange {
+
+    protected ClientSessionImpl session;
+    protected PublicKey serverKey;
+
+    protected AbstractDHClientKeyExchange() {
+        super();
+    }
+
+    @Override
+    public void init(AbstractSession s, byte[] V_S, byte[] V_C, byte[] I_S, byte[] I_C) throws Exception {
+        super.init(s, V_S, V_C, I_S, I_C);
+        if (!(s instanceof ClientSessionImpl)) {
+            throw new IllegalStateException("Using a client side KeyExchange on a server");
+        }
+        session = (ClientSessionImpl) s;
+    }
+
+    public PublicKey getServerKey() {
+        return serverKey;
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/73551939/sshd-core/src/main/java/org/apache/sshd/client/kex/AbstractDHGClient.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/kex/AbstractDHGClient.java b/sshd-core/src/main/java/org/apache/sshd/client/kex/AbstractDHGClient.java
deleted file mode 100644
index 68d6dd4..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/client/kex/AbstractDHGClient.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.sshd.client.kex;
-
-import java.security.PublicKey;
-
-import org.apache.sshd.client.session.ClientSessionImpl;
-import org.apache.sshd.common.Digest;
-import org.apache.sshd.common.KeyExchange;
-import org.apache.sshd.common.NamedFactory;
-import org.apache.sshd.common.Signature;
-import org.apache.sshd.common.SshConstants;
-import org.apache.sshd.common.SshException;
-import org.apache.sshd.common.kex.AbstractDH;
-import org.apache.sshd.common.kex.DH;
-import org.apache.sshd.common.session.AbstractSession;
-import org.apache.sshd.common.util.Buffer;
-import org.apache.sshd.common.util.KeyUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Base class for DHG key exchange algorithms.
- * Implementations will only have to configure the required data on the
- * {@link DH} class in the {@link #getDH()} method.
- *
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public abstract class AbstractDHGClient implements KeyExchange {
-
-    private final Logger log = LoggerFactory.getLogger(getClass());
-
-    private ClientSessionImpl session;
-    private byte[] V_S;
-    private byte[] V_C;
-    private byte[] I_S;
-    private byte[] I_C;
-    private Digest hash;
-    private AbstractDH dh;
-    private byte[] e;
-    private byte[] f;
-    private byte[] K;
-    private byte[] H;
-    private PublicKey serverKey;
-
-    public void init(AbstractSession s, byte[] V_S, byte[] V_C, byte[] I_S, byte[] I_C) throws Exception {
-        if (!(s instanceof ClientSessionImpl)) {
-            throw new IllegalStateException("Using a client side KeyExchange on a server");
-        }
-        session = (ClientSessionImpl) s;
-        this.V_S = V_S;
-        this.V_C = V_C;
-        this.I_S = I_S;
-        this.I_C = I_C;
-        dh = getDH();
-        hash =  dh.getHash();
-        hash.init();
-        e = dh.getE();
-
-        log.debug("Send SSH_MSG_KEXDH_INIT");
-        Buffer buffer = s.createBuffer(SshConstants.SSH_MSG_KEXDH_INIT);
-        buffer.putMPInt(e);
-        session.writePacket(buffer);
-    }
-
-    protected abstract AbstractDH getDH() throws Exception;
-
-    public boolean next(Buffer buffer) throws Exception {
-        byte cmd = buffer.getByte();
-        if (cmd != SshConstants.SSH_MSG_KEXDH_REPLY) {
-            throw new SshException(SshConstants.SSH2_DISCONNECT_KEY_EXCHANGE_FAILED,
-                                   "Protocol error: expected packet SSH_MSG_KEXDH_REPLY, got " + cmd);
-        }
-
-        log.debug("Received SSH_MSG_KEXDH_REPLY");
-        
-        byte[] K_S = buffer.getBytes();
-        f = buffer.getMPIntAsBytes();
-        byte[] sig = buffer.getBytes();
-        dh.setF(f);
-        K = dh.getK();
-
-        buffer = new Buffer(K_S);
-        serverKey = buffer.getRawPublicKey();
-        final String keyAlg = KeyUtils.getKeyType(serverKey);
-        if (keyAlg == null) {
-            throw new SshException("Unsupported server key type");
-        }
-
-        buffer = new Buffer();
-        buffer.putString(V_C);
-        buffer.putString(V_S);
-        buffer.putString(I_C);
-        buffer.putString(I_S);
-        buffer.putString(K_S);
-        buffer.putMPInt(e);
-        buffer.putMPInt(f);
-        buffer.putMPInt(K);
-        hash.update(buffer.array(), 0, buffer.available());
-        H = hash.digest();
-
-        Signature verif = NamedFactory.Utils.create(session.getFactoryManager().getSignatureFactories(), keyAlg);
-        verif.init(serverKey, null);
-        verif.update(H, 0, H.length);
-        if (!verif.verify(sig)) {
-            throw new SshException(SshConstants.SSH2_DISCONNECT_KEY_EXCHANGE_FAILED,
-                                   "KeyExchange signature verification failed");
-        }
-        return true;
-    }
-
-    public Digest getHash() {
-        return hash;
-    }
-
-    public byte[] getH() {
-        return H;
-    }
-
-    public byte[] getK() {
-        return K;
-    }
-
-    public PublicKey getServerKey() {
-        return serverKey;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/73551939/sshd-core/src/main/java/org/apache/sshd/client/kex/DHG1.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/kex/DHG1.java b/sshd-core/src/main/java/org/apache/sshd/client/kex/DHG1.java
deleted file mode 100644
index 5359d03..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/client/kex/DHG1.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.sshd.client.kex;
-
-import org.apache.sshd.common.KeyExchange;
-import org.apache.sshd.common.NamedFactory;
-import org.apache.sshd.common.kex.DH;
-import org.apache.sshd.common.kex.DHGroupData;
-
-/**
- * TODO Add javadoc
- *
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class DHG1 extends AbstractDHGClient {
-
-    /**
-     * Named factory for DHG1 key exchange
-     */
-    public static class Factory implements NamedFactory<KeyExchange> {
-
-        public String getName() {
-            return "diffie-hellman-group1-sha1";
-        }
-
-        public KeyExchange create() {
-            return new DHG1();
-        }
-
-    }
-
-    protected DH getDH() throws Exception {
-        DH dh = new DH();
-        dh.setG(DHGroupData.getG());
-        dh.setP(DHGroupData.getP1());
-        return dh;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/73551939/sshd-core/src/main/java/org/apache/sshd/client/kex/DHG14.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/kex/DHG14.java b/sshd-core/src/main/java/org/apache/sshd/client/kex/DHG14.java
deleted file mode 100644
index 6c47e9d..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/client/kex/DHG14.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.sshd.client.kex;
-
-import org.apache.sshd.common.KeyExchange;
-import org.apache.sshd.common.NamedFactory;
-import org.apache.sshd.common.kex.DH;
-import org.apache.sshd.common.kex.DHGroupData;
-
-/**
- * DHG14 does not work with the default JCE implementation provided by Sun
- * because it does not support 2048 bits encryption.
- * It requires BouncyCastle to be used.
- *
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class DHG14 extends AbstractDHGClient {
-
-    /**
-     * Named factory for DHG14 key exchange
-     */
-    public static class Factory implements NamedFactory<KeyExchange> {
-
-        public String getName() {
-            return "diffie-hellman-group14-sha1";
-        }
-
-        public KeyExchange create() {
-            return new DHG14();
-        }
-
-    }
-
-    protected DH getDH() throws Exception {
-        DH dh = new DH();
-        dh.setG(DHGroupData.getG());
-        dh.setP(DHGroupData.getP14());
-        return dh;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/73551939/sshd-core/src/main/java/org/apache/sshd/client/kex/DHGClient.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/kex/DHGClient.java b/sshd-core/src/main/java/org/apache/sshd/client/kex/DHGClient.java
new file mode 100644
index 0000000..69bea58
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/kex/DHGClient.java
@@ -0,0 +1,131 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sshd.client.kex;
+
+import org.apache.sshd.common.KeyExchange;
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.Signature;
+import org.apache.sshd.common.SshConstants;
+import org.apache.sshd.common.SshException;
+import org.apache.sshd.common.kex.AbstractDH;
+import org.apache.sshd.common.kex.DHFactory;
+import org.apache.sshd.common.session.AbstractSession;
+import org.apache.sshd.common.util.Buffer;
+import org.apache.sshd.common.util.KeyUtils;
+
+/**
+ * Base class for DHG key exchange algorithms.
+ * Implementations will only have to configure the required data on the
+ * {@link org.apache.sshd.common.kex.DHG} class in the {@link #getDH()} method.
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class DHGClient extends AbstractDHClientKeyExchange {
+
+    protected final DHFactory factory;
+    protected AbstractDH dh;
+
+    public static final NamedFactory<KeyExchange> newFactory(final DHFactory delegate) {
+        return new NamedFactory<KeyExchange>() {
+            @Override
+            public String getName() {
+                return delegate.getName();
+            }
+
+            @Override
+            public KeyExchange create() {
+                return new DHGClient(delegate);
+            }
+
+            @Override
+            public String toString() {
+                return NamedFactory.class.getSimpleName()
+                        + "<" + KeyExchange.class.getSimpleName() + ">"
+                        + "[" + getName() + "]";
+            }
+        };
+    }
+
+    protected DHGClient(DHFactory factory) {
+        super();
+        this.factory = factory;
+    }
+
+    public void init(AbstractSession s, byte[] V_S, byte[] V_C, byte[] I_S, byte[] I_C) throws Exception {
+        super.init(s, V_S, V_C, I_S, I_C);
+        dh = getDH();
+        hash =  dh.getHash();
+        hash.init();
+        e = dh.getE();
+
+        log.debug("Send SSH_MSG_KEXDH_INIT");
+        Buffer buffer = s.createBuffer(SshConstants.SSH_MSG_KEXDH_INIT);
+        buffer.putMPInt(e);
+        session.writePacket(buffer);
+    }
+
+    protected AbstractDH getDH() throws Exception {
+        return factory.create();
+    }
+
+    public boolean next(Buffer buffer) throws Exception {
+        byte cmd = buffer.getByte();
+        if (cmd != SshConstants.SSH_MSG_KEXDH_REPLY) {
+            throw new SshException(SshConstants.SSH2_DISCONNECT_KEY_EXCHANGE_FAILED,
+                                   "Protocol error: expected packet SSH_MSG_KEXDH_REPLY, got " + cmd);
+        }
+
+        log.debug("Received SSH_MSG_KEXDH_REPLY");
+        
+        byte[] K_S = buffer.getBytes();
+        f = buffer.getMPIntAsBytes();
+        byte[] sig = buffer.getBytes();
+        dh.setF(f);
+        K = dh.getK();
+
+        buffer = new Buffer(K_S);
+        serverKey = buffer.getRawPublicKey();
+        final String keyAlg = KeyUtils.getKeyType(serverKey);
+        if (keyAlg == null) {
+            throw new SshException("Unsupported server key type");
+        }
+
+        buffer = new Buffer();
+        buffer.putString(V_C);
+        buffer.putString(V_S);
+        buffer.putString(I_C);
+        buffer.putString(I_S);
+        buffer.putString(K_S);
+        buffer.putMPInt(e);
+        buffer.putMPInt(f);
+        buffer.putMPInt(K);
+        hash.update(buffer.array(), 0, buffer.available());
+        H = hash.digest();
+
+        Signature verif = NamedFactory.Utils.create(session.getFactoryManager().getSignatureFactories(), keyAlg);
+        verif.init(serverKey, null);
+        verif.update(H, 0, H.length);
+        if (!verif.verify(sig)) {
+            throw new SshException(SshConstants.SSH2_DISCONNECT_KEY_EXCHANGE_FAILED,
+                                   "KeyExchange signature verification failed");
+        }
+        return true;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/73551939/sshd-core/src/main/java/org/apache/sshd/client/kex/DHGEX.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/kex/DHGEX.java b/sshd-core/src/main/java/org/apache/sshd/client/kex/DHGEX.java
deleted file mode 100644
index c493a34..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/client/kex/DHGEX.java
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.sshd.client.kex;
-
-import java.math.BigInteger;
-import java.security.PublicKey;
-
-import org.apache.sshd.client.session.ClientSessionImpl;
-import org.apache.sshd.common.Digest;
-import org.apache.sshd.common.KeyExchange;
-import org.apache.sshd.common.NamedFactory;
-import org.apache.sshd.common.Signature;
-import org.apache.sshd.common.SshConstants;
-import org.apache.sshd.common.SshException;
-import org.apache.sshd.common.kex.AbstractDH;
-import org.apache.sshd.common.kex.DH;
-import org.apache.sshd.common.session.AbstractSession;
-import org.apache.sshd.common.util.Buffer;
-import org.apache.sshd.common.util.KeyUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Client side Diffie Hellman Group Exchange
- *
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class DHGEX implements KeyExchange {
-
-    /**
-     * Named factory for DHGEX key exchange
-     */
-    public static class Factory implements NamedFactory<KeyExchange> {
-
-        public String getName() {
-            return "diffie-hellman-group-exchange-sha1";
-        }
-
-        public KeyExchange create() {
-            return new DHGEX();
-        }
-
-    }
-
-    private final Logger log = LoggerFactory.getLogger(getClass());
-
-    private ClientSessionImpl session;
-    private byte[] V_S;
-    private byte[] V_C;
-    private byte[] I_S;
-    private byte[] I_C;
-    private Digest hash;
-    private AbstractDH dh;
-    private byte[] p;
-    private byte[] g;
-    private byte[] e;
-    private byte[] f;
-    private byte[] K;
-    private byte[] H;
-    private PublicKey serverKey;
-    private byte expected;
-
-    int min = 1024;
-    int prf = 4096;
-    int max = 8192;
-
-    public void init(AbstractSession s, byte[] V_S, byte[] V_C, byte[] I_S, byte[] I_C) throws Exception {
-        if (!(s instanceof ClientSessionImpl)) {
-            throw new IllegalStateException("Using a client side KeyExchange on a server");
-        }
-        session = (ClientSessionImpl) s;
-        this.V_S = V_S;
-        this.V_C = V_C;
-        this.I_S = I_S;
-        this.I_C = I_C;
-
-        log.debug("Send SSH_MSG_KEX_DH_GEX_REQUEST");
-        Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_KEX_DH_GEX_REQUEST);
-        buffer.putInt(min);
-        buffer.putInt(prf);
-        buffer.putInt(max);
-        session.writePacket(buffer);
-
-        expected = SshConstants.SSH_MSG_KEX_DH_GEX_GROUP;
-    }
-
-    public boolean next(Buffer buffer) throws Exception {
-        byte cmd = buffer.getByte();
-        if (cmd != expected) {
-            throw new SshException(SshConstants.SSH2_DISCONNECT_KEY_EXCHANGE_FAILED,
-                    "Protocol error: expected packet " + expected + ", got " + cmd);
-        }
-
-        if (cmd == SshConstants.SSH_MSG_KEX_DH_GEX_GROUP) {
-            log.debug("Received SSH_MSG_KEX_DH_GEX_GROUP");
-            p = buffer.getMPIntAsBytes();
-            g = buffer.getMPIntAsBytes();
-
-            dh = getDH(new BigInteger(p), new BigInteger(g));
-            hash =  dh.getHash();
-            hash.init();
-            e = dh.getE();
-
-            log.debug("Send SSH_MSG_KEX_DH_GEX_INIT");
-            buffer = session.createBuffer(SshConstants.SSH_MSG_KEX_DH_GEX_INIT);
-            buffer.putMPInt(e);
-            session.writePacket(buffer);
-            expected = SshConstants.SSH_MSG_KEX_DH_GEX_REPLY;
-            return false;
-        }
-
-        if (cmd == SshConstants.SSH_MSG_KEX_DH_GEX_REPLY) {
-            log.debug("Received SSH_MSG_KEX_DH_GEX_REPLY");
-            byte[] K_S = buffer.getBytes();
-            f = buffer.getMPIntAsBytes();
-            byte[] sig = buffer.getBytes();
-            dh.setF(f);
-            K = dh.getK();
-
-            buffer = new Buffer(K_S);
-            serverKey = buffer.getRawPublicKey();
-            final String keyAlg = KeyUtils.getKeyType(serverKey);
-            if (keyAlg == null) {
-                throw new SshException("Unsupported server key type");
-            }
-
-            buffer = new Buffer();
-            buffer.putString(V_C);
-            buffer.putString(V_S);
-            buffer.putString(I_C);
-            buffer.putString(I_S);
-            buffer.putString(K_S);
-            buffer.putInt(min);
-            buffer.putInt(prf);
-            buffer.putInt(max);
-            buffer.putMPInt(p);
-            buffer.putMPInt(g);
-            buffer.putMPInt(e);
-            buffer.putMPInt(f);
-            buffer.putMPInt(K);
-            hash.update(buffer.array(), 0, buffer.available());
-            H = hash.digest();
-
-            Signature verif = NamedFactory.Utils.create(session.getFactoryManager().getSignatureFactories(), keyAlg);
-            verif.init(serverKey, null);
-            verif.update(H, 0, H.length);
-            if (!verif.verify(sig)) {
-                throw new SshException(SshConstants.SSH2_DISCONNECT_KEY_EXCHANGE_FAILED,
-                        "KeyExchange signature verification failed");
-            }
-            return true;
-        }
-
-        throw new IllegalStateException();
-    }
-
-    protected DH getDH(BigInteger p, BigInteger g) throws Exception {
-        DH dh = new DH();
-        dh.setP(p);
-        dh.setG(g);
-        return dh;
-    }
-
-    public Digest getHash() {
-        return hash;
-    }
-
-    public byte[] getH() {
-        return H;
-    }
-
-    public byte[] getK() {
-        return K;
-    }
-
-    public PublicKey getServerKey() {
-        return serverKey;
-    }
-}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/73551939/sshd-core/src/main/java/org/apache/sshd/client/kex/DHGEX256.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/kex/DHGEX256.java b/sshd-core/src/main/java/org/apache/sshd/client/kex/DHGEX256.java
deleted file mode 100644
index a9582af..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/client/kex/DHGEX256.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.sshd.client.kex;
-
-import java.math.BigInteger;
-
-import org.apache.sshd.common.KeyExchange;
-import org.apache.sshd.common.NamedFactory;
-import org.apache.sshd.common.digest.SHA256;
-import org.apache.sshd.common.kex.DH;
-
-/**
- * Client side Diffie Hellman Group Exchange
- *
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class DHGEX256 extends DHGEX {
-
-    /**
-     * Named factory for DHGEX key exchange
-     */
-    public static class Factory implements NamedFactory<KeyExchange> {
-
-        public String getName() {
-            return "diffie-hellman-group-exchange-sha256";
-        }
-
-        public KeyExchange create() {
-            return new DHGEX256();
-        }
-
-    }
-
-    @Override
-    protected DH getDH(BigInteger p, BigInteger g) throws Exception {
-        DH dh = new DH(new SHA256.Factory());
-        dh.setP(p);
-        dh.setG(g);
-        return dh;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/73551939/sshd-core/src/main/java/org/apache/sshd/client/kex/DHGEXClient.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/kex/DHGEXClient.java b/sshd-core/src/main/java/org/apache/sshd/client/kex/DHGEXClient.java
new file mode 100644
index 0000000..38fca91
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/kex/DHGEXClient.java
@@ -0,0 +1,160 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sshd.client.kex;
+
+import java.math.BigInteger;
+
+import org.apache.sshd.common.KeyExchange;
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.Signature;
+import org.apache.sshd.common.SshConstants;
+import org.apache.sshd.common.SshException;
+import org.apache.sshd.common.kex.AbstractDH;
+import org.apache.sshd.common.kex.DHFactory;
+import org.apache.sshd.common.session.AbstractSession;
+import org.apache.sshd.common.util.Buffer;
+import org.apache.sshd.common.util.KeyUtils;
+
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class DHGEXClient extends AbstractDHClientKeyExchange {
+
+    protected final DHFactory factory;
+    protected byte expected;
+    protected int min = 1024;
+    protected int prf = 4096;
+    protected int max = 8192;
+    protected AbstractDH dh;
+    protected byte[] p;
+    protected byte[] g;
+
+    public static final NamedFactory<KeyExchange> newFactory(final DHFactory delegate) {
+        return new NamedFactory<KeyExchange>() {
+            public String getName() {
+                return delegate.getName();
+            }
+
+            public KeyExchange create() {
+                return new DHGEXClient(delegate);
+            }
+
+            @Override
+            public String toString() {
+                return NamedFactory.class.getSimpleName()
+                        + "<" + KeyExchange.class.getSimpleName() + ">"
+                        + "[" + getName() + "]";
+            }
+        };
+    }
+    protected DHGEXClient(DHFactory factory) {
+        super();
+        this.factory = factory;
+    }
+
+    @Override
+    public void init(AbstractSession s, byte[] V_S, byte[] V_C, byte[] I_S, byte[] I_C) throws Exception {
+        super.init(s, V_S, V_C, I_S, I_C);
+        log.debug("Send SSH_MSG_KEX_DH_GEX_REQUEST");
+        Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_KEX_DH_GEX_REQUEST);
+        buffer.putInt(min);
+        buffer.putInt(prf);
+        buffer.putInt(max);
+        session.writePacket(buffer);
+
+        expected = SshConstants.SSH_MSG_KEX_DH_GEX_GROUP;
+    }
+
+    public boolean next(Buffer buffer) throws Exception {
+        byte cmd = buffer.getByte();
+        if (cmd != expected) {
+            throw new SshException(SshConstants.SSH2_DISCONNECT_KEY_EXCHANGE_FAILED,
+                    "Protocol error: expected packet " + expected + ", got " + cmd);
+        }
+
+        if (cmd == SshConstants.SSH_MSG_KEX_DH_GEX_GROUP) {
+            log.debug("Received SSH_MSG_KEX_DH_GEX_GROUP");
+            p = buffer.getMPIntAsBytes();
+            g = buffer.getMPIntAsBytes();
+
+            dh = getDH(new BigInteger(p), new BigInteger(g));
+            hash = dh.getHash();
+            hash.init();
+            e = dh.getE();
+
+            log.debug("Send SSH_MSG_KEX_DH_GEX_INIT");
+            buffer = session.createBuffer(SshConstants.SSH_MSG_KEX_DH_GEX_INIT);
+            buffer.putMPInt(e);
+            session.writePacket(buffer);
+            expected = SshConstants.SSH_MSG_KEX_DH_GEX_REPLY;
+            return false;
+        }
+
+        if (cmd == SshConstants.SSH_MSG_KEX_DH_GEX_REPLY) {
+            log.debug("Received SSH_MSG_KEX_DH_GEX_REPLY");
+            byte[] K_S = buffer.getBytes();
+            f = buffer.getMPIntAsBytes();
+            byte[] sig = buffer.getBytes();
+            dh.setF(f);
+            K = dh.getK();
+
+            buffer = new Buffer(K_S);
+            serverKey = buffer.getRawPublicKey();
+            final String keyAlg = KeyUtils.getKeyType(serverKey);
+            if (keyAlg == null) {
+                throw new SshException("Unsupported server key type");
+            }
+
+            buffer = new Buffer();
+            buffer.putString(V_C);
+            buffer.putString(V_S);
+            buffer.putString(I_C);
+            buffer.putString(I_S);
+            buffer.putString(K_S);
+            buffer.putInt(min);
+            buffer.putInt(prf);
+            buffer.putInt(max);
+            buffer.putMPInt(p);
+            buffer.putMPInt(g);
+            buffer.putMPInt(e);
+            buffer.putMPInt(f);
+            buffer.putMPInt(K);
+            hash.update(buffer.array(), 0, buffer.available());
+            H = hash.digest();
+
+            Signature verif = NamedFactory.Utils.create(session.getFactoryManager().getSignatureFactories(), keyAlg);
+            verif.init(serverKey, null);
+            verif.update(H, 0, H.length);
+            if (!verif.verify(sig)) {
+                throw new SshException(SshConstants.SSH2_DISCONNECT_KEY_EXCHANGE_FAILED,
+                        "KeyExchange signature verification failed");
+            }
+            return true;
+        }
+
+        throw new IllegalStateException("Unknown command value: " + cmd);
+    }
+
+    protected AbstractDH getDH(BigInteger p, BigInteger g) throws Exception {
+        return factory.create(p, g);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/73551939/sshd-core/src/main/java/org/apache/sshd/client/kex/ECDHP256.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/kex/ECDHP256.java b/sshd-core/src/main/java/org/apache/sshd/client/kex/ECDHP256.java
deleted file mode 100644
index e14738e..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/client/kex/ECDHP256.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.sshd.client.kex;
-
-import org.apache.sshd.common.KeyExchange;
-import org.apache.sshd.common.NamedFactory;
-import org.apache.sshd.common.cipher.ECCurves;
-import org.apache.sshd.common.kex.AbstractDH;
-import org.apache.sshd.common.kex.ECDH;
-
-/**
- * Elliptic Curve Diffie-Hellman with NIST P-256 curve.
- *
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class ECDHP256 extends AbstractDHGClient {
-
-    public static class Factory implements NamedFactory<KeyExchange> {
-
-        public String getName() {
-            return "ecdh-sha2-nistp256";
-        }
-
-        public KeyExchange create() {
-            return new ECDHP256();
-        }
-
-    }
-
-    @Override
-    protected AbstractDH getDH() throws Exception {
-        ECDH ecdh = new ECDH();
-        ecdh.setCurveParameters(ECCurves.EllipticCurves.nistp256);
-        return ecdh;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/73551939/sshd-core/src/main/java/org/apache/sshd/client/kex/ECDHP384.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/kex/ECDHP384.java b/sshd-core/src/main/java/org/apache/sshd/client/kex/ECDHP384.java
deleted file mode 100644
index cb05e47..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/client/kex/ECDHP384.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.sshd.client.kex;
-
-import org.apache.sshd.common.KeyExchange;
-import org.apache.sshd.common.NamedFactory;
-import org.apache.sshd.common.cipher.ECCurves;
-import org.apache.sshd.common.kex.AbstractDH;
-import org.apache.sshd.common.kex.ECDH;
-
-/**
- * Elliptic Curve Diffie-Hellman with NIST P-256 curve.
- *
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class ECDHP384 extends AbstractDHGClient {
-
-    public static class Factory implements NamedFactory<KeyExchange> {
-
-        public String getName() {
-            return "ecdh-sha2-nistp384";
-        }
-
-        public KeyExchange create() {
-            return new ECDHP384();
-        }
-
-    }
-
-    @Override
-    protected AbstractDH getDH() throws Exception {
-        ECDH ecdh = new ECDH();
-        ecdh.setCurveParameters(ECCurves.EllipticCurves.nistp384);
-        return ecdh;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/73551939/sshd-core/src/main/java/org/apache/sshd/client/kex/ECDHP521.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/kex/ECDHP521.java b/sshd-core/src/main/java/org/apache/sshd/client/kex/ECDHP521.java
deleted file mode 100644
index 9e36951..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/client/kex/ECDHP521.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.sshd.client.kex;
-
-import org.apache.sshd.common.KeyExchange;
-import org.apache.sshd.common.NamedFactory;
-import org.apache.sshd.common.cipher.ECCurves;
-import org.apache.sshd.common.kex.AbstractDH;
-import org.apache.sshd.common.kex.ECDH;
-
-/**
- * Elliptic Curve Diffie-Hellman with NIST P-256 curve.
- *
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class ECDHP521 extends AbstractDHGClient {
-
-    public static class Factory implements NamedFactory<KeyExchange> {
-
-        public String getName() {
-            return "ecdh-sha2-nistp521";
-        }
-
-        public KeyExchange create() {
-            return new ECDHP521();
-        }
-
-    }
-
-    @Override
-    protected AbstractDH getDH() throws Exception {
-        ECDH ecdh = new ECDH();
-        ecdh.setCurveParameters(ECCurves.EllipticCurves.nistp521);
-        return ecdh;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/73551939/sshd-core/src/main/java/org/apache/sshd/common/FactoryManagerUtils.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/FactoryManagerUtils.java b/sshd-core/src/main/java/org/apache/sshd/common/FactoryManagerUtils.java
index 6dde364..ece21bc 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/FactoryManagerUtils.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/FactoryManagerUtils.java
@@ -106,15 +106,15 @@ public class FactoryManagerUtils {
     }
 
     public static final String updateProperty(Session session, String name, long value) {
-        return updateProperty(session, name, String.valueOf(value));
+        return updateProperty(session, name, Long.toString(value));
     }
 
     public static final String updateProperty(FactoryManager manager, String name, long value) {
-        return updateProperty(manager, name, String.valueOf(value));
+        return updateProperty(manager, name, Long.toString(value));
     }
 
     public static final String updateProperty(Map<String, String> props, String name, long value) {
-        return updateProperty(props, name, String.valueOf(value));
+        return updateProperty(props, name, Long.toString(value));
     }
 
     public static final int getIntProperty(Session session, String name, int defaultValue) {
@@ -152,15 +152,15 @@ public class FactoryManagerUtils {
     }
 
     public static final String updateProperty(Session session, String name, int value) {
-        return updateProperty(session, name, String.valueOf(value));
+        return updateProperty(session, name, Integer.toString(value));
     }
 
     public static final String updateProperty(FactoryManager manager, String name, int value) {
-        return updateProperty(manager, name, String.valueOf(value));
+        return updateProperty(manager, name, Integer.toString(value));
     }
 
     public static final String updateProperty(Map<String, String> props, String name, int value) {
-        return updateProperty(props, name, String.valueOf(value));
+        return updateProperty(props, name, Integer.toString(value));
     }
 
     public static final boolean getBooleanProperty(Session session, String name, boolean defaultValue) {
@@ -198,15 +198,15 @@ public class FactoryManagerUtils {
     }
 
     public static final String updateProperty(Session session, String name, boolean value) {
-        return updateProperty(session, name, String.valueOf(value));
+        return updateProperty(session, name, Boolean.toString(value));
     }
 
     public static final String updateProperty(FactoryManager manager, String name, boolean value) {
-        return updateProperty(manager, name, String.valueOf(value));
+        return updateProperty(manager, name, Boolean.toString(value));
     }
 
     public static final String updateProperty(Map<String, String> props, String name, boolean value) {
-        return updateProperty(props, name, String.valueOf(value));
+        return updateProperty(props, name, Boolean.toString(value));
     }
 
     public static final String getString(Session session, String name) {

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/73551939/sshd-core/src/main/java/org/apache/sshd/common/NamedFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/NamedFactory.java b/sshd-core/src/main/java/org/apache/sshd/common/NamedFactory.java
index ba8d60f..6850b8d 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/NamedFactory.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/NamedFactory.java
@@ -33,14 +33,7 @@ import org.apache.sshd.common.util.GenericUtils;
  *
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
-public interface NamedFactory<T> extends Factory<T> {
-
-    /**
-     * Name of this factory
-     * @return the name of this factory
-     */
-    String getName();
-
+public interface NamedFactory<T> extends Factory<T>, NamedResource {
     /**
      * Utility class to help using NamedFactories
      */
@@ -72,15 +65,13 @@ public interface NamedFactory<T> extends Factory<T> {
          * @param <T> type of object to create
          * @return a newly created object or <code>null</code> if the factory is not in the list
          */
-        public static <T> T create(List<NamedFactory<T>> factories, String name) {
-            if (factories != null) {
-                for (NamedFactory<T> f : factories) {
-                    if (f.getName().equals(name)) {
-                        return f.create();
-                    }
-                }
+        public static <T> T create(Collection<? extends NamedFactory<T>> factories, String name) {
+            NamedFactory<? extends T>   f=get(factories, name);
+            if (f != null) {
+                return f.create();
+            } else {
+                return null;
             }
-            return null;
         }
 
         /**
@@ -90,7 +81,7 @@ public interface NamedFactory<T> extends Factory<T> {
          * @param <T> type of object to create
          * @return a comma separated list of factory names
          */
-        public static <T> String getNames(List<NamedFactory<T>> factories) {
+        public static <T> String getNames(Collection<? extends NamedFactory<T>> factories) {
             StringBuilder sb = new StringBuilder();
             for (NamedFactory<T> f : factories) {
                 if (sb.length() > 0) {
@@ -109,14 +100,12 @@ public interface NamedFactory<T> extends Factory<T> {
          * @param <T> type of object to create
          * @return the factory removed from the list or <code>null</code> if not in the list
          */
-        public static <T> NamedFactory<T> remove(List<NamedFactory<T>> factories, String name) {
-            for (NamedFactory<T> f : factories) {
-                if (f.getName().equals(name)) {
-                    factories.remove(f);
-                    return f;
-                }
+        public static <T> NamedFactory<T> remove(Collection<? extends NamedFactory<T>> factories, String name) {
+            NamedFactory<T> f=get(factories, name);
+            if (f != null) {
+                factories.remove(f);
             }
-            return null;
+            return f;
         }
 
         /**
@@ -127,7 +116,11 @@ public interface NamedFactory<T> extends Factory<T> {
          * @param <T> type of object create by the factories
          * @return a factory or <code>null</code> if not found in the list
          */
-        public static <T> NamedFactory<T> get(List<NamedFactory<T>> factories, String name) {
+        public static <T> NamedFactory<T> get(Collection<? extends NamedFactory<T>> factories, String name) {
+            if (GenericUtils.isEmpty(factories)) {
+                return null;
+            }
+
             for (NamedFactory<T> f : factories) {
                 if (f.getName().equals(name)) {
                     return f;
@@ -135,7 +128,6 @@ public interface NamedFactory<T> extends Factory<T> {
             }
             return null;
         }
-
     }
 
 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/73551939/sshd-core/src/main/java/org/apache/sshd/common/NamedResource.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/NamedResource.java b/sshd-core/src/main/java/org/apache/sshd/common/NamedResource.java
new file mode 100644
index 0000000..85f78a8
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/NamedResource.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sshd.common;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public interface NamedResource {
+    /**
+     * @return The resource name
+     */
+    String getName();
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/73551939/sshd-core/src/main/java/org/apache/sshd/common/ServiceFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/ServiceFactory.java b/sshd-core/src/main/java/org/apache/sshd/common/ServiceFactory.java
index b70b963..d74989c 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/ServiceFactory.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/ServiceFactory.java
@@ -19,16 +19,11 @@
 package org.apache.sshd.common;
 
 import java.io.IOException;
-import java.util.List;
+import java.util.Collection;
 
-public interface ServiceFactory {
-
-    /**
-     * Name of this factory
-     * @return
-     */
-    String getName();
+import org.apache.sshd.common.util.GenericUtils;
 
+public interface ServiceFactory extends NamedResource {
     Service create(Session session) throws IOException;
 
     /**
@@ -44,14 +39,17 @@ public interface ServiceFactory {
          * @param name the factory name to use
          * @return a newly created object or <code>null</code> if the factory is not in the list
          */
-        public static Service create(List<ServiceFactory> factories, String name, Session session) throws IOException {
-            if (factories != null) {
-                for (ServiceFactory f : factories) {
-                    if (f.getName().equals(name)) {
-                        return f.create(session);
-                    }
+        public static Service create(Collection<? extends ServiceFactory> factories, String name, Session session) throws IOException {
+            if (GenericUtils.isEmpty(factories)) {
+                return null;
+            }
+
+            for (ServiceFactory f : factories) {
+                if (f.getName().equals(name)) {
+                    return f.create(session);
                 }
             }
+
             return null;
         }
     }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/73551939/sshd-core/src/main/java/org/apache/sshd/common/kex/AbstractDH.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/kex/AbstractDH.java b/sshd-core/src/main/java/org/apache/sshd/common/kex/AbstractDH.java
index 05a0680..6e66a20 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/kex/AbstractDH.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/kex/AbstractDH.java
@@ -27,18 +27,12 @@ import org.apache.sshd.common.Digest;
  * 
  */
 public abstract class AbstractDH {
+
     protected BigInteger K; // shared secret key
     private byte[] K_array;
 
     protected AbstractDH() {
-    }
-
-    public static AbstractDH getInstance(String algo) throws Exception {
-        if (algo.startsWith("ecdh-sha2-")) {
-            return new ECDH();
-        } else {
-            return new DH();
-        }
+        super();
     }
 
     public abstract void setF(byte[] e);

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/73551939/sshd-core/src/main/java/org/apache/sshd/common/kex/BuiltinDHFactories.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/kex/BuiltinDHFactories.java b/sshd-core/src/main/java/org/apache/sshd/common/kex/BuiltinDHFactories.java
new file mode 100644
index 0000000..b2c63cd
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/kex/BuiltinDHFactories.java
@@ -0,0 +1,184 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sshd.common.kex;
+
+import java.math.BigInteger;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.Set;
+
+import org.apache.sshd.common.cipher.ECCurves;
+import org.apache.sshd.common.digest.SHA1;
+import org.apache.sshd.common.digest.SHA256;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.SecurityUtils;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public enum BuiltinDHFactories implements DHFactory {
+
+    dhg1(Constants.DIFFIE_HELLMAN_GROUP1_SHA1) {
+        @Override
+        public DHG create(Object... params) throws Exception {
+            if (params != null && params.length > 0) {
+                throw new IllegalArgumentException("No accepted parameters for " + getName());
+            }
+            return new DHG(new SHA1.Factory(), new BigInteger(DHGroupData.getP1()), new BigInteger(DHGroupData.getG()));
+        }
+    },
+    dhg14(Constants.DIFFIE_HELLMAN_GROUP14_SHA1) {
+        @Override
+        public DHG create(Object... params) throws Exception {
+            if (params != null && params.length > 0) {
+                throw new IllegalArgumentException("No accepted parameters for " + getName());
+            }
+            return new DHG(new SHA1.Factory(), new BigInteger(DHGroupData.getP14()), new BigInteger(DHGroupData.getG()));
+        }
+        @Override
+        public boolean isSupported() {
+            return SecurityUtils.isBouncyCastleRegistered();
+        }
+    },
+    dhgex(Constants.DIFFIE_HELLMAN_GROUP_EXCHANGE_SHA1) {
+        @Override
+        public DHG create(Object... params) throws Exception {
+            if (params == null || params.length != 2
+                    || !(params[0] instanceof BigInteger) || !(params[1] instanceof BigInteger)) {
+                throw new IllegalArgumentException("Bad parameters for " + getName());
+            }
+            return new DHG(new SHA1.Factory(), (BigInteger) params[0], (BigInteger) params[1]);
+        }
+        @Override
+        public boolean isGroupExchange() {
+            return true;
+        }
+    },
+    dhgex256(Constants.DIFFIE_HELLMAN_GROUP_EXCHANGE_SHA256) {
+        @Override
+        public AbstractDH create(Object... params) throws Exception {
+            if (params == null || params.length != 2
+                    || !(params[0] instanceof BigInteger) || !(params[1] instanceof BigInteger)) {
+                throw new IllegalArgumentException("Bad parameters for " + getName());
+            }
+            return new DHG(new SHA256.Factory(), (BigInteger) params[0], (BigInteger) params[1]);
+        }
+        @Override
+        public boolean isSupported() {  // avoid "Prime size must be multiple of 64, and can only range from 512 to 2048 (inclusive)"
+            return SecurityUtils.isBouncyCastleRegistered();
+        }
+        @Override
+        public boolean isGroupExchange() {
+            return true;
+        }
+    },
+    ecdhp256(Constants.ECDH_SHA2_NISTP256) {
+        @Override
+        public ECDH create(Object... params) throws Exception {
+            if (params != null && params.length > 0) {
+                throw new IllegalArgumentException("No accepted parameters for " + getName());
+            }
+            return new ECDH(ECCurves.EllipticCurves.nistp256);
+        }
+        @Override
+        public boolean isSupported() {
+            return SecurityUtils.hasEcc();
+        }
+    },
+    ecdhp384(Constants.ECDH_SHA2_NISTP384) {
+        @Override
+        public ECDH create(Object... params) throws Exception {
+            if (params != null && params.length > 0) {
+                throw new IllegalArgumentException("No accepted parameters for " + getName());
+            }
+            return new ECDH(ECCurves.EllipticCurves.nistp384);
+        }
+        @Override
+        public boolean isSupported() {
+            return SecurityUtils.hasEcc();
+        }
+    },
+    ecdhp521(Constants.ECDH_SHA2_NISTP521) {
+        @Override
+        public ECDH create(Object... params) throws Exception {
+            if (params != null && params.length > 0) {
+                throw new IllegalArgumentException("No accepted parameters for " + getName());
+            }
+            return new ECDH(ECCurves.EllipticCurves.nistp521);
+        }
+        @Override
+        public boolean isSupported() {
+            return SecurityUtils.hasEcc();
+        }
+    };
+
+    private final String factoryName;
+
+    @Override
+    public final String getName() {
+        return factoryName;
+    }
+
+    public boolean isSupported() {
+        return true;
+    }
+
+    BuiltinDHFactories(String name) {
+        factoryName = name;
+    }
+
+    public static final Set<BuiltinDHFactories> VALUES =
+            Collections.unmodifiableSet(EnumSet.allOf(BuiltinDHFactories.class));
+
+    /**
+     * @param name The factory name - ignored if {@code null}/empty
+     * @return The matching {@link BuiltinDHFactories} (case <U>insensitive</U>)
+     * or {@code null} if no match found
+     */
+    public static final BuiltinDHFactories fromFactoryName(String name) {
+        if (GenericUtils.isEmpty(name)) {
+            return null;
+        }
+
+        for (BuiltinDHFactories f : VALUES) {
+            if (name.equalsIgnoreCase(f.getName())) {
+                return f;
+            }
+        }
+
+        return null;
+    }
+
+    @Override
+    public boolean isGroupExchange() {
+        return false;
+    }
+
+    public static class Constants {
+        public static final String DIFFIE_HELLMAN_GROUP1_SHA1 = "diffie-hellman-group1-sha1";
+        public static final String DIFFIE_HELLMAN_GROUP14_SHA1 = "diffie-hellman-group14-sha1";
+        public static final String DIFFIE_HELLMAN_GROUP_EXCHANGE_SHA1 = "diffie-hellman-group-exchange-sha1";
+        public static final String DIFFIE_HELLMAN_GROUP_EXCHANGE_SHA256 = "diffie-hellman-group-exchange-sha256";
+        public static final String ECDH_SHA2_NISTP256 = "ecdh-sha2-nistp256";
+        public static final String ECDH_SHA2_NISTP384 = "ecdh-sha2-nistp384";
+        public static final String ECDH_SHA2_NISTP521 = "ecdh-sha2-nistp521";
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/73551939/sshd-core/src/main/java/org/apache/sshd/common/kex/DH.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/kex/DH.java b/sshd-core/src/main/java/org/apache/sshd/common/kex/DH.java
deleted file mode 100644
index 7b2bc89..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/common/kex/DH.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.sshd.common.kex;
-
-import java.math.BigInteger;
-import java.security.KeyFactory;
-import java.security.KeyPair;
-import java.security.KeyPairGenerator;
-import java.security.PublicKey;
-
-import javax.crypto.KeyAgreement;
-import javax.crypto.spec.DHParameterSpec;
-import javax.crypto.spec.DHPublicKeySpec;
-
-import org.apache.sshd.common.Digest;
-import org.apache.sshd.common.Factory;
-import org.apache.sshd.common.digest.SHA1;
-import org.apache.sshd.common.util.SecurityUtils;
-
-/**
- * Diffie-Hellman key generator.
- *
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class DH extends AbstractDH {
-
-    private BigInteger p;
-    private BigInteger g;
-    private BigInteger e;  // my public key
-    private byte[] e_array;
-    private BigInteger f;  // your public key
-    private KeyPairGenerator myKpairGen;
-    private KeyAgreement myKeyAgree;
-    private Factory<Digest> factory;
-
-    public DH() throws Exception {
-        this(new SHA1.Factory());
-    }
-
-    public DH(Factory<Digest> factory) throws Exception {
-        myKpairGen = SecurityUtils.getKeyPairGenerator("DH");
-        myKeyAgree = SecurityUtils.getKeyAgreement("DH");
-        this.factory = factory;
-    }
-
-    public byte[] getE() throws Exception {
-        if (e == null) {
-            DHParameterSpec dhSkipParamSpec = new DHParameterSpec(p, g);
-            myKpairGen.initialize(dhSkipParamSpec);
-            KeyPair myKpair = myKpairGen.generateKeyPair();
-            myKeyAgree.init(myKpair.getPrivate());
-            e = ((javax.crypto.interfaces.DHPublicKey) (myKpair.getPublic())).getY();
-            e_array = e.toByteArray();
-        }
-        return e_array;
-    }
-
-    protected byte[] calculateK() throws Exception {
-        KeyFactory myKeyFac = SecurityUtils.getKeyFactory("DH");
-        DHPublicKeySpec keySpec = new DHPublicKeySpec(f, p, g);
-        PublicKey yourPubKey = myKeyFac.generatePublic(keySpec);
-        myKeyAgree.doPhase(yourPubKey, true);
-        return stripLeadingZeroes(myKeyAgree.generateSecret());
-    }
-
-    public void setP(byte[] p) {
-        setP(new BigInteger(p));
-    }
-
-    public void setG(byte[] g) {
-        setG(new BigInteger(g));
-    }
-
-    public void setF(byte[] f) {
-        setF(new BigInteger(f));
-    }
-
-    public BigInteger getP() {
-        return p;
-    }
-
-    public void setP(BigInteger p) {
-        this.p = p;
-    }
-
-    public BigInteger getG() {
-        return g;
-    }
-
-    public void setG(BigInteger g) {
-        this.g = g;
-    }
-
-    public void setF(BigInteger f) {
-        this.f = f;
-    }
-
-    @Override
-    public Digest getHash() throws Exception {
-        return factory.create();
-    }
-}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/73551939/sshd-core/src/main/java/org/apache/sshd/common/kex/DHFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/kex/DHFactory.java b/sshd-core/src/main/java/org/apache/sshd/common/kex/DHFactory.java
new file mode 100644
index 0000000..ad80eca
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/kex/DHFactory.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sshd.common.kex;
+
+import java.math.BigInteger;
+
+import org.apache.sshd.common.NamedResource;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public interface DHFactory extends NamedResource {
+
+    boolean isGroupExchange();
+
+    AbstractDH create(Object... params) throws Exception;
+
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/73551939/sshd-core/src/main/java/org/apache/sshd/common/kex/DHG.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/kex/DHG.java b/sshd-core/src/main/java/org/apache/sshd/common/kex/DHG.java
new file mode 100644
index 0000000..2658eb1
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/kex/DHG.java
@@ -0,0 +1,119 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sshd.common.kex;
+
+import java.math.BigInteger;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PublicKey;
+
+import javax.crypto.KeyAgreement;
+import javax.crypto.spec.DHParameterSpec;
+import javax.crypto.spec.DHPublicKeySpec;
+
+import org.apache.sshd.common.Digest;
+import org.apache.sshd.common.Factory;
+import org.apache.sshd.common.util.SecurityUtils;
+
+/**
+ * Diffie-Hellman key generator.
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class DHG extends AbstractDH {
+
+    private BigInteger p;
+    private BigInteger g;
+    private BigInteger e;  // my public key
+    private byte[] e_array;
+    private BigInteger f;  // your public key
+    private KeyPairGenerator myKpairGen;
+    private KeyAgreement myKeyAgree;
+    private Factory<Digest> factory;
+
+    public DHG(Factory<Digest> digestFactory) throws Exception {
+        this(digestFactory, null, null);
+    }
+
+    public DHG(Factory<Digest> digestFactory, BigInteger pValue, BigInteger gValue) throws Exception {
+        myKpairGen = SecurityUtils.getKeyPairGenerator("DH");
+        myKeyAgree = SecurityUtils.getKeyAgreement("DH");
+        factory = digestFactory;
+        p = pValue;
+        g = gValue;
+    }
+
+    public byte[] getE() throws Exception {
+        if (e == null) {
+            DHParameterSpec dhSkipParamSpec = new DHParameterSpec(p, g);
+            myKpairGen.initialize(dhSkipParamSpec);
+            KeyPair myKpair = myKpairGen.generateKeyPair();
+            myKeyAgree.init(myKpair.getPrivate());
+            e = ((javax.crypto.interfaces.DHPublicKey) (myKpair.getPublic())).getY();
+            e_array = e.toByteArray();
+        }
+        return e_array;
+    }
+
+    protected byte[] calculateK() throws Exception {
+        KeyFactory myKeyFac = SecurityUtils.getKeyFactory("DH");
+        DHPublicKeySpec keySpec = new DHPublicKeySpec(f, p, g);
+        PublicKey yourPubKey = myKeyFac.generatePublic(keySpec);
+        myKeyAgree.doPhase(yourPubKey, true);
+        return stripLeadingZeroes(myKeyAgree.generateSecret());
+    }
+
+    public void setP(byte[] p) {
+        setP(new BigInteger(p));
+    }
+
+    public void setG(byte[] g) {
+        setG(new BigInteger(g));
+    }
+
+    public void setF(byte[] f) {
+        setF(new BigInteger(f));
+    }
+
+    public BigInteger getP() {
+        return p;
+    }
+
+    public void setP(BigInteger p) {
+        this.p = p;
+    }
+
+    public BigInteger getG() {
+        return g;
+    }
+
+    public void setG(BigInteger g) {
+        this.g = g;
+    }
+
+    public void setF(BigInteger f) {
+        this.f = f;
+    }
+
+    @Override
+    public Digest getHash() throws Exception {
+        return factory.create();
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/73551939/sshd-core/src/main/java/org/apache/sshd/common/kex/ECDH.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/kex/ECDH.java b/sshd-core/src/main/java/org/apache/sshd/common/kex/ECDH.java
index bd63570..fbb7090 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/kex/ECDH.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/kex/ECDH.java
@@ -48,8 +48,13 @@ public class ECDH extends AbstractDH {
     private KeyAgreement myKeyAgree;
 
     public ECDH() throws Exception {
+        this(null);
+    }
+
+    public ECDH(ECParameterSpec paramSpec) throws Exception {
         myKpairGen = SecurityUtils.getKeyPairGenerator("EC");
         myKeyAgree = SecurityUtils.getKeyAgreement("ECDH");
+        params = paramSpec;
     }
 
     @Override
@@ -73,8 +78,8 @@ public class ECDH extends AbstractDH {
         return stripLeadingZeroes(myKeyAgree.generateSecret());
     }
 
-    public void setCurveParameters(ECParameterSpec params) {
-        this.params = params;
+    public void setCurveParameters(ECParameterSpec paramSpec) {
+        params = paramSpec;
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/73551939/sshd-core/src/main/java/org/apache/sshd/common/kex/dh/AbstractDHKeyExchange.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/kex/dh/AbstractDHKeyExchange.java b/sshd-core/src/main/java/org/apache/sshd/common/kex/dh/AbstractDHKeyExchange.java
new file mode 100644
index 0000000..17d3a00
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/kex/dh/AbstractDHKeyExchange.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sshd.common.kex.dh;
+
+import org.apache.sshd.common.Digest;
+import org.apache.sshd.common.KeyExchange;
+import org.apache.sshd.common.session.AbstractSession;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public abstract class AbstractDHKeyExchange implements KeyExchange {
+
+    protected final Logger log = LoggerFactory.getLogger(getClass());
+    protected byte[] V_S;
+    protected byte[] V_C;
+    protected byte[] I_S;
+    protected byte[] I_C;
+    protected Digest hash;
+    protected byte[] e;
+    protected byte[] f;
+    protected byte[] K;
+    protected byte[] H;
+
+    protected AbstractDHKeyExchange() {
+        super();
+    }
+
+    public void init(AbstractSession s, byte[] V_S, byte[] V_C, byte[] I_S, byte[] I_C) throws Exception {
+        this.V_S = V_S;
+        this.V_C = V_C;
+        this.I_S = I_S;
+        this.I_C = I_C;
+    }
+
+    public Digest getHash() {
+        return hash;
+    }
+
+    public byte[] getH() {
+        return H;
+    }
+
+    public byte[] getK() {
+        return K;
+    }
+
+}