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:52 UTC

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

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/73551939/sshd-core/src/main/java/org/apache/sshd/server/kex/AbstractDHGServer.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/kex/AbstractDHGServer.java b/sshd-core/src/main/java/org/apache/sshd/server/kex/AbstractDHGServer.java
deleted file mode 100644
index e6a4023..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/server/kex/AbstractDHGServer.java
+++ /dev/null
@@ -1,151 +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.server.kex;
-
-import java.security.KeyPair;
-import java.security.PublicKey;
-
-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.session.AbstractSession;
-import org.apache.sshd.common.util.Buffer;
-import org.apache.sshd.common.util.BufferUtils;
-import org.apache.sshd.server.session.ServerSession;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * TODO Add javadoc
- *
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public abstract class AbstractDHGServer implements KeyExchange {
-
-    private final Logger log = LoggerFactory.getLogger(getClass());
-
-    private ServerSession 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;
-
-    public void init(AbstractSession s, byte[] V_S, byte[] V_C, byte[] I_S, byte[] I_C) throws Exception {
-        if (!(s instanceof ServerSession)) {
-            throw new IllegalStateException("Using a server side KeyExchange on a client");
-        }
-        session = (ServerSession) 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();
-        f = dh.getE();
-    }
-
-    protected abstract AbstractDH getDH() throws Exception;
-
-    public boolean next(Buffer buffer) throws Exception {
-        byte cmd = buffer.getByte();
-        if (cmd != SshConstants.SSH_MSG_KEXDH_INIT) {
-            throw new SshException(SshConstants.SSH2_DISCONNECT_KEY_EXCHANGE_FAILED, 
-                                   "Protocol error: expected packet " + SshConstants.SSH_MSG_KEXDH_INIT + ", got " + cmd);
-        }
-        log.debug("Received SSH_MSG_KEXDH_INIT");
-        e = buffer.getMPIntAsBytes();
-        dh.setF(e);
-        K = dh.getK();
-
-        byte[] K_S;
-        KeyPair kp = session.getHostKey();
-        String algo = session.getNegotiated(SshConstants.PROPOSAL_SERVER_HOST_KEY_ALGS);
-        Signature sig = NamedFactory.Utils.create(session.getFactoryManager().getSignatureFactories(), algo);
-        sig.init(kp.getPublic(), kp.getPrivate());
-
-        buffer = new Buffer();
-        buffer.putRawPublicKey(kp.getPublic());
-        K_S = buffer.getCompactData();
-
-        buffer.clear();
-        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();
-
-        byte[] sigH;
-        buffer.clear();
-        sig.update(H, 0, H.length);
-        buffer.putString(algo);
-        buffer.putString(sig.sign());
-        sigH = buffer.getCompactData();
-
-        if (log.isDebugEnabled()) {
-            log.debug("K_S:  {}", BufferUtils.printHex(K_S));
-            log.debug("f:    {}", BufferUtils.printHex(f));
-            log.debug("sigH: {}", BufferUtils.printHex(sigH));
-        }
-
-        // Send response
-        log.debug("Send SSH_MSG_KEXDH_REPLY");
-        buffer.clear();
-        buffer.rpos(5);
-        buffer.wpos(5);
-        buffer.putByte(SshConstants.SSH_MSG_KEXDH_REPLY);
-        buffer.putString(K_S);
-        buffer.putString(f);
-        buffer.putString(sigH);
-        session.writePacket(buffer);
-        return true;
-    }
-
-    public Digest getHash() {
-        return hash;
-    }
-
-    public byte[] getH() {
-        return H;
-    }
-
-    public byte[] getK() {
-        return K;
-    }
-
-    public PublicKey getServerKey() {
-        return session.getHostKey().getPublic();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/73551939/sshd-core/src/main/java/org/apache/sshd/server/kex/AbstractDHServerKeyExchange.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/kex/AbstractDHServerKeyExchange.java b/sshd-core/src/main/java/org/apache/sshd/server/kex/AbstractDHServerKeyExchange.java
new file mode 100644
index 0000000..6d1172b
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/server/kex/AbstractDHServerKeyExchange.java
@@ -0,0 +1,50 @@
+/*
+ * 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.server.kex;
+
+import java.security.PublicKey;
+
+import org.apache.sshd.common.kex.dh.AbstractDHKeyExchange;
+import org.apache.sshd.common.session.AbstractSession;
+import org.apache.sshd.server.session.ServerSession;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public abstract class AbstractDHServerKeyExchange extends AbstractDHKeyExchange {
+
+    protected ServerSession session;
+
+    protected AbstractDHServerKeyExchange() {
+        super();
+    }
+
+    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 ServerSession)) {
+            throw new IllegalStateException("Using a server side KeyExchange on a client");
+        }
+        session = (ServerSession) s;
+    }
+
+    public PublicKey getServerKey() {
+        return session.getHostKey().getPublic();
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/73551939/sshd-core/src/main/java/org/apache/sshd/server/kex/DHG1.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/kex/DHG1.java b/sshd-core/src/main/java/org/apache/sshd/server/kex/DHG1.java
deleted file mode 100644
index abe3474..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/server/kex/DHG1.java
+++ /dev/null
@@ -1,54 +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.server.kex;
-
-import org.apache.sshd.common.KeyExchange;
-import org.apache.sshd.common.NamedFactory;
-import org.apache.sshd.common.kex.AbstractDH;
-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 AbstractDHGServer {
-
-    public static class Factory implements NamedFactory<KeyExchange> {
-
-        public String getName() {
-            return "diffie-hellman-group1-sha1";
-        }
-
-        public KeyExchange create() {
-            return new DHG1();
-        }
-
-    }
-
-    @Override
-    protected AbstractDH 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/server/kex/DHG14.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/kex/DHG14.java b/sshd-core/src/main/java/org/apache/sshd/server/kex/DHG14.java
deleted file mode 100644
index 2a7b925..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/server/kex/DHG14.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.server.kex;
-
-import org.apache.sshd.common.KeyExchange;
-import org.apache.sshd.common.NamedFactory;
-import org.apache.sshd.common.kex.AbstractDH;
-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.
- *
- * TODO Add javadoc
- *
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class DHG14 extends AbstractDHGServer {
-
-    public static class Factory implements NamedFactory<KeyExchange> {
-
-        public String getName() {
-            return "diffie-hellman-group14-sha1";
-        }
-
-        public KeyExchange create() {
-            return new DHG14();
-        }
-
-    }
-
-    @Override
-    protected AbstractDH 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/server/kex/DHGEX.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/kex/DHGEX.java b/sshd-core/src/main/java/org/apache/sshd/server/kex/DHGEX.java
deleted file mode 100644
index ef777d6..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/server/kex/DHGEX.java
+++ /dev/null
@@ -1,314 +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.server.kex;
-
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.math.BigInteger;
-import java.net.URL;
-import java.security.KeyPair;
-import java.security.PublicKey;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.sshd.common.Digest;
-import org.apache.sshd.common.FactoryManagerUtils;
-import org.apache.sshd.common.KeyExchange;
-import org.apache.sshd.common.NamedFactory;
-import org.apache.sshd.common.Random;
-import org.apache.sshd.common.Signature;
-import org.apache.sshd.common.SshConstants;
-import org.apache.sshd.common.SshException;
-import org.apache.sshd.common.digest.SHA1;
-import org.apache.sshd.common.kex.DH;
-import org.apache.sshd.common.kex.DHGroupData;
-import org.apache.sshd.common.session.AbstractSession;
-import org.apache.sshd.common.util.Buffer;
-import org.apache.sshd.common.util.BufferUtils;
-import org.apache.sshd.common.util.GenericUtils;
-import org.apache.sshd.common.util.SecurityUtils;
-import org.apache.sshd.server.ServerFactoryManager;
-import org.apache.sshd.server.session.ServerSession;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Server side Diffie Hellman Group Exchange
- *
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class DHGEX implements KeyExchange {
-
-    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 ServerSession session;
-    private byte[] V_S;
-    private byte[] V_C;
-    private byte[] I_S;
-    private byte[] I_C;
-    private Digest hash;
-    private DH dh;
-    private byte[] e;
-    private byte[] f;
-    private byte[] K;
-    private byte[] H;
-
-    int min;
-    int prf;
-    int max;
-    private byte expected;
-    boolean oldRequest;
-
-    public void init(AbstractSession s, byte[] V_S, byte[] V_C, byte[] I_S, byte[] I_C) throws Exception {
-        if (!(s instanceof ServerSession)) {
-            throw new IllegalStateException("Using a server side KeyExchange on a client");
-        }
-        session = (ServerSession) s;
-        this.V_S = V_S;
-        this.V_C = V_C;
-        this.I_S = I_S;
-        this.I_C = I_C;
-
-        expected = SshConstants.SSH_MSG_KEX_DH_GEX_REQUEST;
-    }
-
-    public boolean next(Buffer buffer) throws Exception {
-        byte cmd = buffer.getByte();
-
-        if (cmd == SshConstants.SSH_MSG_KEX_DH_GEX_REQUEST_OLD && expected == SshConstants.SSH_MSG_KEX_DH_GEX_REQUEST) {
-            log.debug("Received SSH_MSG_KEX_DH_GEX_REQUEST_OLD");
-            oldRequest = true;
-            min = 1024;
-            prf = buffer.getInt();
-            max = 8192;
-
-            if (max < min || prf < min || max < prf) {
-                throw new SshException(SshConstants.SSH2_DISCONNECT_KEY_EXCHANGE_FAILED,
-                        "Protocol error: bad parameters " + min + " !< " + prf + " !< " + max);
-            }
-            dh = chooseDH(min, prf, max);
-            f = dh.getE();
-            hash = dh.getHash();
-            hash.init();
-
-            log.debug("Send SSH_MSG_KEX_DH_GEX_GROUP");
-            buffer = session.createBuffer(SshConstants.SSH_MSG_KEX_DH_GEX_GROUP);
-            buffer.putMPInt(dh.getP());
-            buffer.putMPInt(dh.getG());
-            session.writePacket(buffer);
-
-            expected = SshConstants.SSH_MSG_KEX_DH_GEX_INIT;
-            return false;
-        }
-        if (cmd == SshConstants.SSH_MSG_KEX_DH_GEX_REQUEST && expected == SshConstants.SSH_MSG_KEX_DH_GEX_REQUEST) {
-            log.debug("Received SSH_MSG_KEX_DH_GEX_REQUEST");
-            min = buffer.getInt();
-            prf = buffer.getInt();
-            max = buffer.getInt();
-            if (max < min || prf < min || max < prf) {
-                throw new SshException(SshConstants.SSH2_DISCONNECT_KEY_EXCHANGE_FAILED,
-                        "Protocol error: bad parameters " + min + " !< " + prf + " !< " + max);
-            }
-            dh = chooseDH(min, prf, max);
-            f = dh.getE();
-            hash = dh.getHash();
-            hash.init();
-
-            log.debug("Send SSH_MSG_KEX_DH_GEX_GROUP");
-            buffer = session.createBuffer(SshConstants.SSH_MSG_KEX_DH_GEX_GROUP);
-            buffer.putMPInt(dh.getP());
-            buffer.putMPInt(dh.getG());
-            session.writePacket(buffer);
-
-            expected = SshConstants.SSH_MSG_KEX_DH_GEX_INIT;
-            return false;
-        }
-        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_INIT) {
-            log.debug("Received SSH_MSG_KEX_DH_GEX_INIT");
-            e = buffer.getMPIntAsBytes();
-            dh.setF(e);
-            K = dh.getK();
-
-
-            byte[] K_S;
-            KeyPair kp = session.getHostKey();
-            String algo = session.getNegotiated(SshConstants.PROPOSAL_SERVER_HOST_KEY_ALGS);
-            Signature sig = NamedFactory.Utils.create(session.getFactoryManager().getSignatureFactories(), algo);
-            sig.init(kp.getPublic(), kp.getPrivate());
-
-            buffer = new Buffer();
-            buffer.putRawPublicKey(kp.getPublic());
-            K_S = buffer.getCompactData();
-
-            buffer.clear();
-            buffer.putString(V_C);
-            buffer.putString(V_S);
-            buffer.putString(I_C);
-            buffer.putString(I_S);
-            buffer.putString(K_S);
-            if (oldRequest) {
-                buffer.putInt(prf);
-            } else {
-                buffer.putInt(min);
-                buffer.putInt(prf);
-                buffer.putInt(max);
-            }
-            buffer.putMPInt(dh.getP());
-            buffer.putMPInt(dh.getG());
-            buffer.putMPInt(e);
-            buffer.putMPInt(f);
-            buffer.putMPInt(K);
-            hash.update(buffer.array(), 0, buffer.available());
-            H = hash.digest();
-
-            byte[] sigH;
-            buffer.clear();
-            sig.update(H, 0, H.length);
-            buffer.putString(algo);
-            buffer.putString(sig.sign());
-            sigH = buffer.getCompactData();
-
-            if (log.isDebugEnabled()) {
-                log.debug("K_S:  {}", BufferUtils.printHex(K_S));
-                log.debug("f:    {}", BufferUtils.printHex(f));
-                log.debug("sigH: {}", BufferUtils.printHex(sigH));
-            }
-
-            // Send response
-            log.debug("Send SSH_MSG_KEX_DH_GEX_REPLY");
-            buffer.clear();
-            buffer.rpos(5);
-            buffer.wpos(5);
-            buffer.putByte(SshConstants.SSH_MSG_KEX_DH_GEX_REPLY);
-            buffer.putString(K_S);
-            buffer.putString(f);
-            buffer.putString(sigH);
-            session.writePacket(buffer);
-            return true;
-        }
-
-        return false;
-    }
-
-    private DH chooseDH(int min, int prf, int max) throws Exception {
-        List<Moduli.DhGroup> groups = loadModuliGroups();
-
-        min = Math.max(min, 1024);
-        prf = Math.max(prf, 1024);
-        // Keys of size > 1024 are not support by default with JCE, so only enable
-        // those if BouncyCastle is registered
-        prf = Math.min(prf, SecurityUtils.isBouncyCastleRegistered() ? 8192 : 1024);
-        max = Math.min(max, 8192);
-        int bestSize = 0;
-        List<Moduli.DhGroup> selected = new ArrayList<Moduli.DhGroup>();
-        for (Moduli.DhGroup group : groups) {
-            if (group.size < min || group.size > max) {
-                continue;
-            }
-            if ((group.size > prf && group.size < bestSize) || (group.size > bestSize && bestSize < prf)) {
-                bestSize = group.size;
-                selected.clear();
-            }
-            if (group.size == bestSize) {
-                selected.add(group);
-            }
-        }
-        if (selected.isEmpty()) {
-            log.warn("No suitable primes found, defaulting to DHG1");
-            return getDH(new BigInteger(DHGroupData.getP1()), new BigInteger(DHGroupData.getG()));
-        }
-        Random random = session.getFactoryManager().getRandomFactory().create();
-        int which = random.random(selected.size());
-        Moduli.DhGroup group = selected.get(which);
-        return getDH(group.p, group.g);
-    }
-
-    protected List<Moduli.DhGroup> loadModuliGroups() throws IOException {
-        List<Moduli.DhGroup> groups = null;
-        URL moduli;
-        String moduliStr = FactoryManagerUtils.getString(session, ServerFactoryManager.MODULI_URL);
-        if (!GenericUtils.isEmpty(moduliStr)) {
-            try {
-                moduli = new URL(moduliStr);
-                groups = Moduli.parseModuli(moduli);
-            } catch (IOException e) {   // OK - use internal moduli
-                log.warn("Error (" + e.getClass().getSimpleName() + ") loading external moduli from " + moduliStr + ": " + e.getMessage());
-            }
-        }
-
-        if (groups == null) {
-            moduliStr = "/org/apache/sshd/moduli";
-            try {
-                if ((moduli = getClass().getResource(moduliStr)) == null) {
-                    throw new FileNotFoundException("Missing internal moduli file");
-                }
-
-                moduliStr = moduli.toExternalForm();
-                groups = Moduli.parseModuli(moduli);
-            } catch (IOException e) {
-                log.warn("Error (" + e.getClass().getSimpleName() + ") loading internal moduli from " + moduliStr + ": " + e.getMessage());
-                throw e;    // this time we MUST throw the exception
-            }
-        }
-
-        log.debug("Loaded moduli groups from {}", moduliStr);
-        return groups;
-    }
-
-    protected DH getDH(BigInteger p, BigInteger g) throws Exception {
-        DH dh = new DH(new SHA1.Factory());
-        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 session.getHostKey().getPublic();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/73551939/sshd-core/src/main/java/org/apache/sshd/server/kex/DHGEX256.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/kex/DHGEX256.java b/sshd-core/src/main/java/org/apache/sshd/server/kex/DHGEX256.java
deleted file mode 100644
index a6dd41e..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/server/kex/DHGEX256.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.server.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;
-
-/**
- * Server side Diffie Hellman Group Exchange
- *
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class DHGEX256 extends DHGEX {
-
-    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/server/kex/DHGEXServer.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/kex/DHGEXServer.java b/sshd-core/src/main/java/org/apache/sshd/server/kex/DHGEXServer.java
new file mode 100644
index 0000000..5473d65
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/server/kex/DHGEXServer.java
@@ -0,0 +1,283 @@
+/*
+ * 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.server.kex;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.net.URL;
+import java.security.KeyPair;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.sshd.common.FactoryManagerUtils;
+import org.apache.sshd.common.KeyExchange;
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.Random;
+import org.apache.sshd.common.Signature;
+import org.apache.sshd.common.SshConstants;
+import org.apache.sshd.common.SshException;
+import org.apache.sshd.common.kex.DHG;
+import org.apache.sshd.common.kex.DHFactory;
+import org.apache.sshd.common.kex.DHGroupData;
+import org.apache.sshd.common.session.AbstractSession;
+import org.apache.sshd.common.util.Buffer;
+import org.apache.sshd.common.util.BufferUtils;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.SecurityUtils;
+import org.apache.sshd.server.ServerFactoryManager;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class DHGEXServer extends AbstractDHServerKeyExchange {
+
+    protected final DHFactory factory;
+    protected DHG dh;
+    protected int min;
+    protected int prf;
+    protected int max;
+    protected byte expected;
+    protected boolean oldRequest;
+
+    public static NamedFactory<KeyExchange> newFactory(final DHFactory factory) {
+        return new NamedFactory<KeyExchange>() {
+            @Override
+            public KeyExchange create() {
+                return new DHGEXServer(factory);
+            }
+
+            @Override
+            public String getName() {
+                return factory.getName();
+            }
+
+            @Override
+            public String toString() {
+                return NamedFactory.class.getSimpleName()
+                        + "<" + KeyExchange.class.getSimpleName() + ">"
+                        + "[" + getName() + "]";
+            }
+        };
+    }
+
+    protected DHGEXServer(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);
+        expected = SshConstants.SSH_MSG_KEX_DH_GEX_REQUEST;
+    }
+
+    public boolean next(Buffer buffer) throws Exception {
+        byte cmd = buffer.getByte();
+
+        if (cmd == SshConstants.SSH_MSG_KEX_DH_GEX_REQUEST_OLD && expected == SshConstants.SSH_MSG_KEX_DH_GEX_REQUEST) {
+            log.debug("Received SSH_MSG_KEX_DH_GEX_REQUEST_OLD");
+            oldRequest = true;
+            min = 1024;
+            prf = buffer.getInt();
+            max = 8192;
+
+            if (max < min || prf < min || max < prf) {
+                throw new SshException(SshConstants.SSH2_DISCONNECT_KEY_EXCHANGE_FAILED,
+                        "Protocol error: bad parameters " + min + " !< " + prf + " !< " + max);
+            }
+            dh = chooseDH(min, prf, max);
+            f = dh.getE();
+            hash = dh.getHash();
+            hash.init();
+
+            log.debug("Send SSH_MSG_KEX_DH_GEX_GROUP");
+            buffer = session.createBuffer(SshConstants.SSH_MSG_KEX_DH_GEX_GROUP);
+            buffer.putMPInt(dh.getP());
+            buffer.putMPInt(dh.getG());
+            session.writePacket(buffer);
+
+            expected = SshConstants.SSH_MSG_KEX_DH_GEX_INIT;
+            return false;
+        }
+        if (cmd == SshConstants.SSH_MSG_KEX_DH_GEX_REQUEST && expected == SshConstants.SSH_MSG_KEX_DH_GEX_REQUEST) {
+            log.debug("Received SSH_MSG_KEX_DH_GEX_REQUEST");
+            min = buffer.getInt();
+            prf = buffer.getInt();
+            max = buffer.getInt();
+            if (prf < min || max < prf) {
+                throw new SshException(SshConstants.SSH2_DISCONNECT_KEY_EXCHANGE_FAILED,
+                        "Protocol error: bad parameters " + min + " !< " + prf + " !< " + max);
+            }
+            dh = chooseDH(min, prf, max);
+            f = dh.getE();
+            hash = dh.getHash();
+            hash.init();
+
+            log.debug("Send SSH_MSG_KEX_DH_GEX_GROUP");
+            buffer = session.createBuffer(SshConstants.SSH_MSG_KEX_DH_GEX_GROUP);
+            buffer.putMPInt(dh.getP());
+            buffer.putMPInt(dh.getG());
+            session.writePacket(buffer);
+
+            expected = SshConstants.SSH_MSG_KEX_DH_GEX_INIT;
+            return false;
+        }
+        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_INIT) {
+            log.debug("Received SSH_MSG_KEX_DH_GEX_INIT");
+            e = buffer.getMPIntAsBytes();
+            dh.setF(e);
+            K = dh.getK();
+
+
+            byte[] K_S;
+            KeyPair kp = session.getHostKey();
+            String algo = session.getNegotiated(SshConstants.PROPOSAL_SERVER_HOST_KEY_ALGS);
+            Signature sig = NamedFactory.Utils.create(session.getFactoryManager().getSignatureFactories(), algo);
+            sig.init(kp.getPublic(), kp.getPrivate());
+
+            buffer = new Buffer();
+            buffer.putRawPublicKey(kp.getPublic());
+            K_S = buffer.getCompactData();
+
+            buffer.clear();
+            buffer.putString(V_C);
+            buffer.putString(V_S);
+            buffer.putString(I_C);
+            buffer.putString(I_S);
+            buffer.putString(K_S);
+            if (oldRequest) {
+                buffer.putInt(prf);
+            } else {
+                buffer.putInt(min);
+                buffer.putInt(prf);
+                buffer.putInt(max);
+            }
+            buffer.putMPInt(dh.getP());
+            buffer.putMPInt(dh.getG());
+            buffer.putMPInt(e);
+            buffer.putMPInt(f);
+            buffer.putMPInt(K);
+            hash.update(buffer.array(), 0, buffer.available());
+            H = hash.digest();
+
+            byte[] sigH;
+            buffer.clear();
+            sig.update(H, 0, H.length);
+            buffer.putString(algo);
+            buffer.putString(sig.sign());
+            sigH = buffer.getCompactData();
+
+            if (log.isDebugEnabled()) {
+                log.debug("K_S:  {}", BufferUtils.printHex(K_S));
+                log.debug("f:    {}", BufferUtils.printHex(f));
+                log.debug("sigH: {}", BufferUtils.printHex(sigH));
+            }
+
+            // Send response
+            log.debug("Send SSH_MSG_KEX_DH_GEX_REPLY");
+            buffer.clear();
+            buffer.rpos(5);
+            buffer.wpos(5);
+            buffer.putByte(SshConstants.SSH_MSG_KEX_DH_GEX_REPLY);
+            buffer.putString(K_S);
+            buffer.putString(f);
+            buffer.putString(sigH);
+            session.writePacket(buffer);
+            return true;
+        }
+
+        return false;
+    }
+
+    private DHG chooseDH(int min, int prf, int max) throws Exception {
+        List<Moduli.DhGroup> groups = loadModuliGroups();
+
+        min = Math.max(min, 1024);
+        prf = Math.max(prf, 1024);
+        // Keys of size > 1024 are not support by default with JCE, so only enable
+        // those if BouncyCastle is registered
+        prf = Math.min(prf, SecurityUtils.isBouncyCastleRegistered() ? 8192 : 1024);
+        max = Math.min(max, 8192);
+        int bestSize = 0;
+        List<Moduli.DhGroup> selected = new ArrayList<>();
+        for (Moduli.DhGroup group : groups) {
+            if (group.size < min || group.size > max) {
+                continue;
+            }
+            if ((group.size > prf && group.size < bestSize) || (group.size > bestSize && bestSize < prf)) {
+                bestSize = group.size;
+                selected.clear();
+            }
+            if (group.size == bestSize) {
+                selected.add(group);
+            }
+        }
+        if (selected.isEmpty()) {
+            log.warn("No suitable primes found, defaulting to DHG1");
+            return getDH(new BigInteger(DHGroupData.getP1()), new BigInteger(DHGroupData.getG()));
+        }
+        Random random = session.getFactoryManager().getRandomFactory().create();
+        int which = random.random(selected.size());
+        Moduli.DhGroup group = selected.get(which);
+        return getDH(group.p, group.g);
+    }
+
+    protected List<Moduli.DhGroup> loadModuliGroups() throws IOException {
+        List<Moduli.DhGroup> groups = null;
+        URL moduli;
+        String moduliStr = FactoryManagerUtils.getString(session, ServerFactoryManager.MODULI_URL);
+        if (!GenericUtils.isEmpty(moduliStr)) {
+            try {
+                moduli = new URL(moduliStr);
+                groups = Moduli.parseModuli(moduli);
+            } catch (IOException e) {   // OK - use internal moduli
+                log.warn("Error (" + e.getClass().getSimpleName() + ") loading external moduli from " + moduliStr + ": " + e.getMessage());
+            }
+        }
+
+        if (groups == null) {
+            moduliStr = "/org/apache/sshd/moduli";
+            try {
+                if ((moduli = getClass().getResource(moduliStr)) == null) {
+                    throw new FileNotFoundException("Missing internal moduli file");
+                }
+
+                moduliStr = moduli.toExternalForm();
+                groups = Moduli.parseModuli(moduli);
+            } catch (IOException e) {
+                log.warn("Error (" + e.getClass().getSimpleName() + ") loading internal moduli from " + moduliStr + ": " + e.getMessage());
+                throw e;    // this time we MUST throw the exception
+            }
+        }
+
+        log.debug("Loaded moduli groups from {}", moduliStr);
+        return groups;
+    }
+
+    protected DHG getDH(BigInteger p, BigInteger g) throws Exception {
+        return (DHG) factory.create(p, g);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/73551939/sshd-core/src/main/java/org/apache/sshd/server/kex/DHGServer.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/kex/DHGServer.java b/sshd-core/src/main/java/org/apache/sshd/server/kex/DHGServer.java
new file mode 100644
index 0000000..13df5c2
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/server/kex/DHGServer.java
@@ -0,0 +1,136 @@
+/*
+ * 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.server.kex;
+
+import java.security.KeyPair;
+
+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.BufferUtils;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class DHGServer extends AbstractDHServerKeyExchange {
+
+    protected final DHFactory factory;
+    protected AbstractDH dh;
+
+    public static NamedFactory<KeyExchange> newFactory(final DHFactory factory) {
+        return new NamedFactory<KeyExchange>() {
+            @Override
+            public KeyExchange create() {
+                return new DHGServer(factory);
+            }
+
+            @Override
+            public String getName() {
+                return factory.getName();
+            }
+
+            @Override
+            public String toString() {
+                return NamedFactory.class.getSimpleName()
+                        + "<" + KeyExchange.class.getSimpleName() + ">"
+                        + "[" + getName() + "]";
+            }
+        };
+    }
+
+    protected DHGServer(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);
+        dh = factory.create();
+        hash = dh.getHash();
+        hash.init();
+        f = dh.getE();
+    }
+
+    public boolean next(Buffer buffer) throws Exception {
+        byte cmd = buffer.getByte();
+        if (cmd != SshConstants.SSH_MSG_KEXDH_INIT) {
+            throw new SshException(SshConstants.SSH2_DISCONNECT_KEY_EXCHANGE_FAILED, 
+                                   "Protocol error: expected packet " + SshConstants.SSH_MSG_KEXDH_INIT + ", got " + cmd);
+        }
+        log.debug("Received SSH_MSG_KEXDH_INIT");
+        e = buffer.getMPIntAsBytes();
+        dh.setF(e);
+        K = dh.getK();
+
+        byte[] K_S;
+        KeyPair kp = session.getHostKey();
+        String algo = session.getNegotiated(SshConstants.PROPOSAL_SERVER_HOST_KEY_ALGS);
+        Signature sig = NamedFactory.Utils.create(session.getFactoryManager().getSignatureFactories(), algo);
+        sig.init(kp.getPublic(), kp.getPrivate());
+
+        buffer = new Buffer();
+        buffer.putRawPublicKey(kp.getPublic());
+        K_S = buffer.getCompactData();
+
+        buffer.clear();
+        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();
+
+        byte[] sigH;
+        buffer.clear();
+        sig.update(H, 0, H.length);
+        buffer.putString(algo);
+        buffer.putString(sig.sign());
+        sigH = buffer.getCompactData();
+
+        if (log.isDebugEnabled()) {
+            log.debug("K_S:  {}", BufferUtils.printHex(K_S));
+            log.debug("f:    {}", BufferUtils.printHex(f));
+            log.debug("sigH: {}", BufferUtils.printHex(sigH));
+        }
+
+        // Send response
+        log.debug("Send SSH_MSG_KEXDH_REPLY");
+        buffer.clear();
+        buffer.rpos(5);
+        buffer.wpos(5);
+        buffer.putByte(SshConstants.SSH_MSG_KEXDH_REPLY);
+        buffer.putString(K_S);
+        buffer.putString(f);
+        buffer.putString(sigH);
+        session.writePacket(buffer);
+        return true;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/73551939/sshd-core/src/main/java/org/apache/sshd/server/kex/ECDHP256.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/kex/ECDHP256.java b/sshd-core/src/main/java/org/apache/sshd/server/kex/ECDHP256.java
deleted file mode 100644
index 7da6c9a..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/server/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.server.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 AbstractDHGServer {
-
-    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/server/kex/ECDHP384.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/kex/ECDHP384.java b/sshd-core/src/main/java/org/apache/sshd/server/kex/ECDHP384.java
deleted file mode 100644
index 093cba7..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/server/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.server.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 AbstractDHGServer {
-
-    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/server/kex/ECDHP521.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/kex/ECDHP521.java b/sshd-core/src/main/java/org/apache/sshd/server/kex/ECDHP521.java
deleted file mode 100644
index 674e95b..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/server/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.server.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 AbstractDHGServer {
-
-    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/test/java/org/apache/sshd/KexTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/KexTest.java b/sshd-core/src/test/java/org/apache/sshd/KexTest.java
deleted file mode 100644
index 2b866e5..0000000
--- a/sshd-core/src/test/java/org/apache/sshd/KexTest.java
+++ /dev/null
@@ -1,153 +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;
-
-import java.io.ByteArrayOutputStream;
-import java.io.OutputStream;
-import java.io.PipedInputStream;
-import java.io.PipedOutputStream;
-import java.util.Collections;
-
-import org.apache.sshd.client.kex.DHG1;
-import org.apache.sshd.client.kex.DHG14;
-import org.apache.sshd.client.kex.DHGEX;
-import org.apache.sshd.client.kex.DHGEX256;
-import org.apache.sshd.client.kex.ECDHP256;
-import org.apache.sshd.client.kex.ECDHP384;
-import org.apache.sshd.client.kex.ECDHP521;
-import org.apache.sshd.common.KeyExchange;
-import org.apache.sshd.common.NamedFactory;
-import org.apache.sshd.common.util.SecurityUtils;
-import org.apache.sshd.util.BaseTest;
-import org.apache.sshd.util.BogusPasswordAuthenticator;
-import org.apache.sshd.util.EchoShellFactory;
-import org.apache.sshd.util.TeeOutputStream;
-import org.apache.sshd.util.Utils;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertTrue;
-
-/**
- * Test key exchange algorithms.
- *
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class KexTest extends BaseTest {
-
-    private SshServer sshd;
-    private int port;
-
-    @Before
-    public void setUp() throws Exception {
-        sshd = SshServer.setUpDefaultServer();
-        sshd.setKeyPairProvider(Utils.createTestHostKeyProvider());
-        sshd.setShellFactory(new EchoShellFactory());
-        sshd.setPasswordAuthenticator(new BogusPasswordAuthenticator());
-        sshd.start();
-        port  = sshd.getPort();
-    }
-
-    @After
-    public void tearDown() throws Exception {
-        sshd.stop(true);
-    }
-
-    @Test
-    public void testDHGEX256() throws Exception {
-        testClient(new DHGEX256.Factory());
-    }
-
-    @Test
-    public void testDHGEX() throws Exception {
-        testClient(new DHGEX.Factory());
-    }
-
-    @Test
-    public void testDHG14() throws Exception {
-        if (SecurityUtils.isBouncyCastleRegistered()) {
-            testClient(new DHG14.Factory());
-        }
-    }
-
-    @Test
-    public void testDHG1() throws Exception {
-        testClient(new DHG1.Factory());
-    }
-
-    @Test
-    public void testECDHP521() throws Exception {
-        testClient(new ECDHP521.Factory());
-    }
-
-    @Test
-    public void testECDHP384() throws Exception {
-        testClient(new ECDHP384.Factory());
-    }
-
-    @Test
-    public void testECDHP256() throws Exception {
-        testClient(new ECDHP256.Factory());
-    }
-
-    private void testClient(NamedFactory<KeyExchange> kex) throws Exception {
-        SshClient client = SshClient.setUpDefaultClient();
-        ByteArrayOutputStream sent = new ByteArrayOutputStream();
-        ByteArrayOutputStream out = new ByteArrayOutputStream();
-        try {
-            client.setKeyExchangeFactories(Collections.singletonList(kex));
-            client.start();
-            ClientSession session = client.connect("smx", "localhost", port).await().getSession();
-            session.addPasswordIdentity("smx");
-            session.auth().verify();
-            ClientChannel channel = session.createChannel(ClientChannel.CHANNEL_SHELL);
-
-            PipedOutputStream pipedIn = new PipedOutputStream();
-            channel.setIn(new PipedInputStream(pipedIn));
-            OutputStream teeOut = new TeeOutputStream(sent, pipedIn);
-            ByteArrayOutputStream err = new ByteArrayOutputStream();
-            channel.setOut(out);
-            channel.setErr(err);
-            assertTrue(channel.open().await().isOpened());
-
-            teeOut.write("this is my command\n".getBytes());
-            teeOut.flush();
-
-            StringBuilder sb = new StringBuilder();
-            for (int i = 0; i < 10; i++) {
-                sb.append("0123456789");
-            }
-            sb.append("\n");
-            teeOut.write(sb.toString().getBytes());
-
-            teeOut.write("exit\n".getBytes());
-            teeOut.flush();
-
-            channel.waitFor(ClientChannel.CLOSED, 0);
-
-            channel.close(false);
-        } finally {
-            client.stop();
-        }
-
-        assertArrayEquals(sent.toByteArray(), out.toByteArray());
-    }
-}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/73551939/sshd-core/src/test/java/org/apache/sshd/LoadTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/LoadTest.java b/sshd-core/src/test/java/org/apache/sshd/LoadTest.java
index cd73484..6489265 100644
--- a/sshd-core/src/test/java/org/apache/sshd/LoadTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/LoadTest.java
@@ -18,18 +18,23 @@
  */
 package org.apache.sshd;
 
+import static org.junit.Assert.assertArrayEquals;
+
 import java.io.ByteArrayOutputStream;
 import java.io.OutputStream;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Map;
 import java.util.concurrent.CountDownLatch;
 
-import org.apache.sshd.client.kex.DHG1;
-import org.apache.sshd.common.Cipher;
-import org.apache.sshd.common.KeyExchange;
+import org.apache.sshd.client.kex.DHGClient;
+import org.apache.sshd.common.FactoryManager;
+import org.apache.sshd.common.FactoryManagerUtils;
 import org.apache.sshd.common.NamedFactory;
-import org.apache.sshd.common.cipher.BlowfishCBC;
+import org.apache.sshd.common.cipher.BuiltinCiphers;
+import org.apache.sshd.common.kex.AbstractDH;
+import org.apache.sshd.common.kex.BuiltinDHFactories;
 import org.apache.sshd.util.BaseTest;
 import org.apache.sshd.util.BogusPasswordAuthenticator;
 import org.apache.sshd.util.EchoShellFactory;
@@ -38,8 +43,6 @@ import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
-import static org.junit.Assert.assertArrayEquals;
-
 public class LoadTest extends BaseTest {
 
     private SshServer sshd;
@@ -84,7 +87,7 @@ public class LoadTest extends BaseTest {
     }
 
     protected void test(final String msg, final int nbThreads, final int nbSessionsPerThread) throws Exception {
-        final List<Throwable> errors = new ArrayList<Throwable>();
+        final List<Throwable> errors = new ArrayList<>();
         final CountDownLatch latch = new CountDownLatch(nbThreads);
         for (int i = 0; i < nbThreads; i++) {
             Runnable r = new Runnable() {
@@ -109,37 +112,41 @@ public class LoadTest extends BaseTest {
     }
 
     protected void runClient(String msg) throws Exception {
-        SshClient client = SshClient.setUpDefaultClient();
-        try {
-            client.getProperties().put(SshClient.MAX_PACKET_SIZE, Integer.toString(1024 * 16));
-            client.getProperties().put(SshClient.WINDOW_SIZE, Integer.toString(1024 * 8));
-            client.setKeyExchangeFactories(Arrays.<NamedFactory<KeyExchange>>asList(
-                    new DHG1.Factory()));
-            client.setCipherFactories(Arrays.<NamedFactory<Cipher>>asList(
-                    new BlowfishCBC.Factory()));
+        try(SshClient client = SshClient.setUpDefaultClient()) {
+            Map<String,String>  props=client.getProperties();
+            FactoryManagerUtils.updateProperty(props, FactoryManager.MAX_PACKET_SIZE, 1024 * 16);
+            FactoryManagerUtils.updateProperty(props, FactoryManager.WINDOW_SIZE, 1024 * 8);
+            client.setKeyExchangeFactories(Arrays.asList(
+                    DHGClient.newFactory(BuiltinDHFactories.dhg1)));
+            client.setCipherFactories(Arrays.asList(BuiltinCiphers.blowfishcbc.create()));
             client.start();
-            ClientSession session = client.connect("sshd", "localhost", port).await().getSession();
-            session.addPasswordIdentity("sshd");
-            session.auth().verify();
-
-            ClientChannel channel = session.createChannel(ClientChannel.CHANNEL_SHELL);
-            ByteArrayOutputStream out = new ByteArrayOutputStream();
-            ByteArrayOutputStream err = new ByteArrayOutputStream();
-            channel.setOut(out);
-            channel.setErr(err);
-            channel.open().await();
-            OutputStream pipedIn = channel.getInvertedIn();
-
-            msg += "\nexit\n";
-            pipedIn.write(msg.getBytes());
-            pipedIn.flush();
-
-            channel.waitFor(ClientChannel.CLOSED, 0);
+            try {
+                ClientSession session = client.connect("sshd", "localhost", port).await().getSession();
+                session.addPasswordIdentity("sshd");
+                session.auth().verify();
+    
+                ByteArrayOutputStream out = new ByteArrayOutputStream();
+                ByteArrayOutputStream err = new ByteArrayOutputStream();
+                ClientChannel channel = session.createChannel(ClientChannel.CHANNEL_SHELL);
+                channel.setOut(out);
+                channel.setErr(err);
+                try {
+                    channel.open().await();
+                    OutputStream pipedIn = channel.getInvertedIn();
+        
+                    msg += "\nexit\n";
+                    pipedIn.write(msg.getBytes());
+                    pipedIn.flush();
+        
+                    channel.waitFor(ClientChannel.CLOSED, 0);
+                } finally {    
+                    channel.close(false);
+                }
 
-            channel.close(false);
-            assertArrayEquals(msg.getBytes(), out.toByteArray());
-        } finally {
-            client.stop();
+                assertArrayEquals("Mismatched message data", msg.getBytes(), out.toByteArray());
+            } finally {
+                client.stop();
+            }
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/73551939/sshd-core/src/test/java/org/apache/sshd/client/kex/KexTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/kex/KexTest.java b/sshd-core/src/test/java/org/apache/sshd/client/kex/KexTest.java
new file mode 100644
index 0000000..848dd20
--- /dev/null
+++ b/sshd-core/src/test/java/org/apache/sshd/client/kex/KexTest.java
@@ -0,0 +1,147 @@
+/*
+ * 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 static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+import java.io.PipedInputStream;
+import java.io.PipedOutputStream;
+import java.util.Collections;
+
+import org.apache.sshd.ClientChannel;
+import org.apache.sshd.ClientSession;
+import org.apache.sshd.SshBuilder;
+import org.apache.sshd.SshClient;
+import org.apache.sshd.SshServer;
+import org.apache.sshd.common.KeyExchange;
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.kex.BuiltinDHFactories;
+import org.apache.sshd.common.kex.DHFactory;
+import org.apache.sshd.util.BaseTest;
+import org.apache.sshd.util.BogusPasswordAuthenticator;
+import org.apache.sshd.util.EchoShellFactory;
+import org.apache.sshd.util.TeeOutputStream;
+import org.apache.sshd.util.Utils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Test client key exchange algorithms.
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class KexTest extends BaseTest {
+
+    private SshServer sshd;
+    private int port;
+
+    @Before
+    public void setUp() throws Exception {
+        sshd = SshServer.setUpDefaultServer();
+        sshd.setKeyPairProvider(Utils.createTestHostKeyProvider());
+        sshd.setShellFactory(new EchoShellFactory());
+        sshd.setPasswordAuthenticator(new BogusPasswordAuthenticator());
+        sshd.start();
+        port  = sshd.getPort();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        sshd.stop(true);
+    }
+
+    @Test
+    public void testClientKeyExchanges() throws Exception {
+        Exception   err=null;
+
+        for (BuiltinDHFactories f : BuiltinDHFactories.VALUES) {
+            if (!f.isSupported()) {
+                System.out.println("Skip KEX=" + f.getName() + " - unsupported");
+                continue;
+            }
+            
+            try {
+                testClient(f);
+            } catch(Exception e) {
+                System.err.println(e.getClass().getSimpleName() + " while test KEX=" + f.getName() + ": " + e.getMessage());
+                err = e;
+            }
+        }
+        
+        if (err != null) {
+            throw err;
+        }
+    }
+
+    private void testClient(DHFactory factory) throws Exception {
+        testClient(SshBuilder.ClientBuilder.getKeyExchangeFactory(factory));
+    }
+
+    private void testClient(NamedFactory<KeyExchange> kex) throws Exception {
+        System.out.println("testClient - KEX=" + kex.getName());
+
+        ByteArrayOutputStream sent = new ByteArrayOutputStream();
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        try(SshClient client = SshClient.setUpDefaultClient()) {
+            client.setKeyExchangeFactories(Collections.singletonList(kex));
+            client.start();
+            
+            try {
+                ClientSession session = client.connect("smx", "localhost", port).await().getSession();
+                session.addPasswordIdentity("smx");
+                session.auth().verify();
+                ClientChannel channel = session.createChannel(ClientChannel.CHANNEL_SHELL);
+                
+                try(PipedOutputStream pipedIn = new PipedOutputStream();
+                    ByteArrayOutputStream err = new ByteArrayOutputStream();
+                    OutputStream teeOut = new TeeOutputStream(sent, pipedIn)) {
+
+                    channel.setIn(new PipedInputStream(pipedIn));
+                    channel.setOut(out);
+                    channel.setErr(err);
+                    assertTrue(channel.open().await().isOpened());
+        
+                    teeOut.write("this is my command\n".getBytes());
+                    teeOut.flush();
+        
+                    StringBuilder sb = new StringBuilder();
+                    for (int i = 0; i < 10; i++) {
+                        sb.append("0123456789");
+                    }
+                    sb.append("\n");
+                    teeOut.write(sb.toString().getBytes());
+        
+                    teeOut.write("exit\n".getBytes());
+                    teeOut.flush();
+        
+                    channel.waitFor(ClientChannel.CLOSED, 0);
+                } finally {    
+                    channel.close(false);
+                }
+            } finally {
+                client.stop();
+            }
+        }
+
+        assertArrayEquals(kex.getName(), sent.toByteArray(), out.toByteArray());
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/73551939/sshd-core/src/test/java/org/apache/sshd/common/kex/BuiltinDHFactoriesTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/common/kex/BuiltinDHFactoriesTest.java b/sshd-core/src/test/java/org/apache/sshd/common/kex/BuiltinDHFactoriesTest.java
new file mode 100644
index 0000000..6a53dd3
--- /dev/null
+++ b/sshd-core/src/test/java/org/apache/sshd/common/kex/BuiltinDHFactoriesTest.java
@@ -0,0 +1,44 @@
+/*
+ * 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 org.apache.sshd.util.BaseTest;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class BuiltinDHFactoriesTest extends BaseTest {
+
+    public BuiltinDHFactoriesTest() {
+        super();
+    }
+
+    @Test
+    public void testFromName() {
+        for (BuiltinDHFactories expected : BuiltinDHFactories.VALUES) {
+            String name = expected.getName();
+            BuiltinDHFactories actual = BuiltinDHFactories.fromFactoryName(name);
+            Assert.assertSame(name, expected, actual);
+        }
+    }
+
+}