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 2014/01/23 22:06:01 UTC

[2/2] git commit: [SSHD-272] Add RFC 5656 (ECDSA and ECDH) support

[SSHD-272] Add RFC 5656 (ECDSA and ECDH) support

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

Branch: refs/heads/master
Commit: 1706dca42d52883ca028aa8e943b73729cb20ff1
Parents: ab7e788
Author: Guillaume Nodet <gn...@apache.org>
Authored: Thu Jan 23 22:05:47 2014 +0100
Committer: Guillaume Nodet <gn...@apache.org>
Committed: Thu Jan 23 22:05:47 2014 +0100

----------------------------------------------------------------------
 .../main/java/org/apache/sshd/SshClient.java    |  33 +++-
 .../main/java/org/apache/sshd/SshServer.java    |  34 +++-
 .../org/apache/sshd/agent/local/AgentImpl.java  |  22 ++-
 .../sshd/client/kex/AbstractDHGClient.java      |  35 ++--
 .../java/org/apache/sshd/client/kex/DHG1.java   |   4 +-
 .../java/org/apache/sshd/client/kex/DHG14.java  |   4 +-
 .../org/apache/sshd/client/kex/ECDHP256.java    |  53 +++++
 .../org/apache/sshd/client/kex/ECDHP384.java    |  53 +++++
 .../org/apache/sshd/client/kex/ECDHP521.java    |  53 +++++
 .../org/apache/sshd/common/KeyPairProvider.java |  23 ++-
 .../org/apache/sshd/common/cipher/ECCurves.java | 195 +++++++++++++++++++
 .../org/apache/sshd/common/digest/SHA256.java   |  52 +++++
 .../org/apache/sshd/common/digest/SHA384.java   |  52 +++++
 .../org/apache/sshd/common/digest/SHA512.java   |  52 +++++
 .../org/apache/sshd/common/kex/AbstractDH.java  |  59 ++++++
 .../java/org/apache/sshd/common/kex/DH.java     |  28 +--
 .../java/org/apache/sshd/common/kex/ECDH.java   |  89 +++++++++
 .../keyprovider/AbstractKeyPairProvider.java    |  17 ++
 .../common/signature/AbstractSignatureDSA.java  |  91 +++++++++
 .../sshd/common/signature/SignatureDSA.java     |  65 +------
 .../sshd/common/signature/SignatureECDSA.java   | 180 +++++++++++++++++
 .../org/apache/sshd/common/util/Buffer.java     |  69 +++++++
 .../apache/sshd/common/util/SecurityUtils.java  |  13 ++
 .../sshd/server/kex/AbstractDHGServer.java      |  22 +--
 .../java/org/apache/sshd/server/kex/DHG1.java   |   6 +-
 .../java/org/apache/sshd/server/kex/DHG14.java  |   6 +-
 .../org/apache/sshd/server/kex/ECDHP256.java    |  53 +++++
 .../org/apache/sshd/server/kex/ECDHP384.java    |  53 +++++
 .../org/apache/sshd/server/kex/ECDHP521.java    |  53 +++++
 .../AbstractGeneratorHostKeyProvider.java       |  14 +-
 .../test/java/org/apache/sshd/AgentTest.java    |   6 +-
 .../PEMGeneratorHostKeyProviderTest.java        |  80 +++++++-
 .../SimpleGeneratorHostKeyProviderTest.java     |  80 +++++++-
 .../test/java/org/apache/sshd/util/Utils.java   |   5 +-
 34 files changed, 1527 insertions(+), 127 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1706dca4/sshd-core/src/main/java/org/apache/sshd/SshClient.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/SshClient.java b/sshd-core/src/main/java/org/apache/sshd/SshClient.java
index 7cbba98..28ac5fa 100644
--- a/sshd-core/src/main/java/org/apache/sshd/SshClient.java
+++ b/sshd-core/src/main/java/org/apache/sshd/SshClient.java
@@ -45,6 +45,9 @@ import org.apache.sshd.client.future.ConnectFuture;
 import org.apache.sshd.client.future.DefaultConnectFuture;
 import org.apache.sshd.client.kex.DHG1;
 import org.apache.sshd.client.kex.DHG14;
+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.client.keyverifier.AcceptAllServerKeyVerifier;
 import org.apache.sshd.client.session.ClientSessionImpl;
 import org.apache.sshd.common.AbstractFactoryManager;
@@ -84,6 +87,7 @@ import org.apache.sshd.common.random.JceRandom;
 import org.apache.sshd.common.random.SingletonRandomFactory;
 import org.apache.sshd.common.session.AbstractSession;
 import org.apache.sshd.common.signature.SignatureDSA;
+import org.apache.sshd.common.signature.SignatureECDSA;
 import org.apache.sshd.common.signature.SignatureRSA;
 import org.apache.sshd.common.util.NoCloseInputStream;
 import org.apache.sshd.common.util.NoCloseOutputStream;
@@ -279,12 +283,38 @@ public class SshClient extends AbstractFactoryManager implements ClientFactoryMa
         // DHG14 uses 2048 bits key which are not supported by the default JCE provider
         if (SecurityUtils.isBouncyCastleRegistered()) {
             client.setKeyExchangeFactories(Arrays.<NamedFactory<KeyExchange>>asList(
+                    new ECDHP256.Factory(),
+                    new ECDHP384.Factory(),
+                    new ECDHP521.Factory(),
                     new DHG14.Factory(),
                     new DHG1.Factory()));
+            client.setSignatureFactories(Arrays.<NamedFactory<Signature>>asList(
+                    new SignatureDSA.Factory(),
+                    new SignatureRSA.Factory(),
+                    new SignatureECDSA.NISTP256Factory(),
+                    new SignatureECDSA.NISTP384Factory(),
+                    new SignatureECDSA.NISTP521Factory()));
             client.setRandomFactory(new SingletonRandomFactory(new BouncyCastleRandom.Factory()));
+        // EC keys are not supported until OpenJDK 7
+        } else if (SecurityUtils.hasEcc()) {
+            client.setKeyExchangeFactories(Arrays.<NamedFactory<KeyExchange>>asList(
+                    new ECDHP256.Factory(),
+                    new ECDHP384.Factory(),
+                    new ECDHP521.Factory(),
+                    new DHG1.Factory()));
+            client.setSignatureFactories(Arrays.<NamedFactory<Signature>>asList(
+                    new SignatureDSA.Factory(),
+                    new SignatureRSA.Factory(),
+                    new SignatureECDSA.NISTP256Factory(),
+                    new SignatureECDSA.NISTP384Factory(),
+                    new SignatureECDSA.NISTP521Factory()));
+            client.setRandomFactory(new SingletonRandomFactory(new JceRandom.Factory()));
         } else {
             client.setKeyExchangeFactories(Arrays.<NamedFactory<KeyExchange>>asList(
                     new DHG1.Factory()));
+            client.setSignatureFactories(Arrays.<NamedFactory<Signature>>asList(
+                    new SignatureDSA.Factory(),
+                    new SignatureRSA.Factory()));
             client.setRandomFactory(new SingletonRandomFactory(new JceRandom.Factory()));
         }
         setUpDefaultCiphers(client);
@@ -302,9 +332,6 @@ public class SshClient extends AbstractFactoryManager implements ClientFactoryMa
                 new HMACMD5.Factory(),
                 new HMACSHA196.Factory(),
                 new HMACMD596.Factory()));
-        client.setSignatureFactories(Arrays.<NamedFactory<Signature>>asList(
-                new SignatureDSA.Factory(),
-                new SignatureRSA.Factory()));
         client.setChannelFactories(Arrays.<NamedFactory<Channel>>asList(
                 new TcpipServerChannel.ForwardedTcpipFactory()));
         client.setServerKeyVerifier(AcceptAllServerKeyVerifier.INSTANCE);

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1706dca4/sshd-core/src/main/java/org/apache/sshd/SshServer.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/SshServer.java b/sshd-core/src/main/java/org/apache/sshd/SshServer.java
index f2c5b72..7ea0870 100644
--- a/sshd-core/src/main/java/org/apache/sshd/SshServer.java
+++ b/sshd-core/src/main/java/org/apache/sshd/SshServer.java
@@ -79,6 +79,7 @@ import org.apache.sshd.common.random.JceRandom;
 import org.apache.sshd.common.random.SingletonRandomFactory;
 import org.apache.sshd.common.session.AbstractSession;
 import org.apache.sshd.common.signature.SignatureDSA;
+import org.apache.sshd.common.signature.SignatureECDSA;
 import org.apache.sshd.common.signature.SignatureRSA;
 import org.apache.sshd.common.util.OsUtils;
 import org.apache.sshd.common.util.SecurityUtils;
@@ -97,6 +98,9 @@ import org.apache.sshd.server.channel.ChannelSession;
 import org.apache.sshd.server.command.ScpCommandFactory;
 import org.apache.sshd.server.kex.DHG1;
 import org.apache.sshd.server.kex.DHG14;
+import org.apache.sshd.server.kex.ECDHP256;
+import org.apache.sshd.server.kex.ECDHP384;
+import org.apache.sshd.server.kex.ECDHP521;
 import org.apache.sshd.server.keyprovider.PEMGeneratorHostKeyProvider;
 import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
 import org.apache.sshd.server.session.ServerSession;
@@ -418,14 +422,41 @@ public class SshServer extends AbstractFactoryManager implements ServerFactoryMa
     public static SshServer setUpDefaultServer() {
         SshServer sshd = new SshServer();
         // DHG14 uses 2048 bits key which are not supported by the default JCE provider
+        // EC keys are not supported until OpenJDK 8
         if (SecurityUtils.isBouncyCastleRegistered()) {
             sshd.setKeyExchangeFactories(Arrays.<NamedFactory<KeyExchange>>asList(
+                    new ECDHP256.Factory(),
+                    new ECDHP384.Factory(),
+                    new ECDHP521.Factory(),
                     new DHG14.Factory(),
                     new DHG1.Factory()));
+            sshd.setSignatureFactories(Arrays.<NamedFactory<Signature>>asList(
+                    new SignatureECDSA.NISTP256Factory(),
+                    new SignatureECDSA.NISTP384Factory(),
+                    new SignatureECDSA.NISTP521Factory(),
+                    new SignatureDSA.Factory(),
+                    new SignatureRSA.Factory()));
             sshd.setRandomFactory(new SingletonRandomFactory(new BouncyCastleRandom.Factory()));
+        // EC keys are not supported until OpenJDK 7
+        } else if (SecurityUtils.hasEcc()) {
+            sshd.setKeyExchangeFactories(Arrays.<NamedFactory<KeyExchange>>asList(
+                    new ECDHP256.Factory(),
+                    new ECDHP384.Factory(),
+                    new ECDHP521.Factory(),
+                    new DHG1.Factory()));
+            sshd.setSignatureFactories(Arrays.<NamedFactory<Signature>>asList(
+                    new SignatureECDSA.NISTP256Factory(),
+                    new SignatureECDSA.NISTP384Factory(),
+                    new SignatureECDSA.NISTP521Factory(),
+                    new SignatureDSA.Factory(),
+                    new SignatureRSA.Factory()));
+            sshd.setRandomFactory(new SingletonRandomFactory(new JceRandom.Factory()));
         } else {
             sshd.setKeyExchangeFactories(Arrays.<NamedFactory<KeyExchange>>asList(
                     new DHG1.Factory()));
+            sshd.setSignatureFactories(Arrays.<NamedFactory<Signature>>asList(
+                    new SignatureDSA.Factory(),
+                    new SignatureRSA.Factory()));
             sshd.setRandomFactory(new SingletonRandomFactory(new JceRandom.Factory()));
         }
         setUpDefaultCiphers(sshd);
@@ -446,9 +477,6 @@ public class SshServer extends AbstractFactoryManager implements ServerFactoryMa
         sshd.setChannelFactories(Arrays.<NamedFactory<Channel>>asList(
                 new ChannelSession.Factory(),
                 new TcpipServerChannel.DirectTcpipFactory()));
-        sshd.setSignatureFactories(Arrays.<NamedFactory<Signature>>asList(
-                new SignatureDSA.Factory(),
-                new SignatureRSA.Factory()));
         sshd.setFileSystemFactory(new NativeFileSystemFactory());
         sshd.setTcpipForwarderFactory(new DefaultTcpipForwarderFactory());
         return sshd;

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1706dca4/sshd-core/src/main/java/org/apache/sshd/agent/local/AgentImpl.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/agent/local/AgentImpl.java b/sshd-core/src/main/java/org/apache/sshd/agent/local/AgentImpl.java
index 61706ed..179d9f2 100644
--- a/sshd-core/src/main/java/org/apache/sshd/agent/local/AgentImpl.java
+++ b/sshd-core/src/main/java/org/apache/sshd/agent/local/AgentImpl.java
@@ -23,7 +23,9 @@ import java.security.KeyPair;
 import java.security.PublicKey;
 import java.security.interfaces.DSAParams;
 import java.security.interfaces.DSAPublicKey;
+import java.security.interfaces.ECPublicKey;
 import java.security.interfaces.RSAPublicKey;
+import java.security.spec.ECParameterSpec;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -31,6 +33,7 @@ import org.apache.sshd.agent.SshAgent;
 import org.apache.sshd.common.Signature;
 import org.apache.sshd.common.SshException;
 import org.apache.sshd.common.signature.SignatureDSA;
+import org.apache.sshd.common.signature.SignatureECDSA;
 import org.apache.sshd.common.signature.SignatureRSA;
 
 /**
@@ -62,10 +65,15 @@ public class AgentImpl implements SshAgent {
         }
         try {
             Signature verif;
-            if (kp.getFirst().getPublic() instanceof RSAPublicKey) {
+            if (kp.getFirst().getPublic() instanceof DSAPublicKey) {
+                verif = new SignatureDSA();
+            } else if (kp.getFirst().getPublic() instanceof ECPublicKey) {
+                ECPublicKey pubKey = (ECPublicKey) kp.getFirst().getPublic();
+                verif = SignatureECDSA.getByCurveSize(pubKey.getParams());
+            } else if (kp.getFirst().getPublic() instanceof RSAPublicKey) {
                 verif = new SignatureRSA();
             } else {
-                verif = new SignatureDSA();
+                throw new SshException("Unsupported key type");
             }
             verif.init(kp.getFirst().getPublic(), kp.getFirst().getPrivate());
             verif.update(data, 0, data.length);
@@ -128,6 +136,16 @@ public class AgentImpl implements SshAgent {
                         && p1.getG().equals(p2.getG())
                         && p1.getP().equals(p2.getP())
                         && p1.getQ().equals(p2.getQ());
+        } else if (k1 instanceof ECPublicKey && k2 instanceof ECPublicKey) {
+            ECPublicKey e1 = (ECPublicKey) k1;
+            ECPublicKey e2 = (ECPublicKey) k2;
+            ECParameterSpec p1 = e1.getParams();
+            ECParameterSpec p2 = e2.getParams();
+            return p1.getCofactor() == p2.getCofactor()
+                        && p1.getOrder().equals(p2.getOrder())
+                        && e1.getW().equals(e2.getW())
+                        && p1.getGenerator().equals(p2.getGenerator())
+                        && p1.getCurve().equals(p2.getCurve());
         } else if (k1 instanceof RSAPublicKey && k2 instanceof RSAPublicKey) {
             RSAPublicKey r1 = (RSAPublicKey) k1;
             RSAPublicKey r2 = (RSAPublicKey) k2;

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1706dca4/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
index d263f87..c4d32b8 100644
--- 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
@@ -19,6 +19,8 @@
 package org.apache.sshd.client.kex;
 
 import java.security.PublicKey;
+import java.security.interfaces.DSAPublicKey;
+import java.security.interfaces.ECPublicKey;
 import java.security.interfaces.RSAPublicKey;
 
 import org.apache.sshd.client.session.ClientSessionImpl;
@@ -29,7 +31,8 @@ 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.digest.SHA1;
+import org.apache.sshd.common.cipher.ECCurves;
+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;
@@ -52,8 +55,8 @@ public abstract class AbstractDHGClient implements KeyExchange {
     private byte[] V_C;
     private byte[] I_S;
     private byte[] I_C;
-    private Digest sha;
-    private DH dh;
+    private Digest hash;
+    private AbstractDH dh;
     private byte[] e;
     private byte[] f;
     private byte[] K;
@@ -69,10 +72,9 @@ public abstract class AbstractDHGClient implements KeyExchange {
         this.V_C = V_C;
         this.I_S = I_S;
         this.I_C = I_C;
-        sha = new SHA1();
-        sha.init();
-        dh = new DH();
-        initDH(dh);
+        dh = getDH();
+        hash =  dh.getHash();
+        hash.init();
         e = dh.getE();
 
         log.info("Send SSH_MSG_KEXDH_INIT");
@@ -81,7 +83,7 @@ public abstract class AbstractDHGClient implements KeyExchange {
         session.writePacket(buffer);
     }
 
-    protected abstract void initDH(DH dh);
+    protected abstract AbstractDH getDH() throws Exception;
 
     public boolean next(Buffer buffer) throws Exception {
         SshConstants.Message cmd = buffer.getCommand();
@@ -100,7 +102,16 @@ public abstract class AbstractDHGClient implements KeyExchange {
 
         buffer = new Buffer(K_S);
         serverKey = buffer.getRawPublicKey();
-        String keyAlg = (serverKey instanceof RSAPublicKey) ? KeyPairProvider.SSH_RSA : KeyPairProvider.SSH_DSS;
+        final String keyAlg;
+        if (serverKey instanceof RSAPublicKey) {
+            keyAlg = KeyPairProvider.SSH_RSA;
+        } else if (serverKey instanceof DSAPublicKey) {
+            keyAlg = KeyPairProvider.SSH_DSS;
+        } else if (serverKey instanceof ECPublicKey) {
+            keyAlg = ECCurves.ECDSA_SHA2_PREFIX + ECCurves.getCurveName(((ECPublicKey) serverKey).getParams());
+        } else {
+            throw new SshException("Unsupported server key type");
+        }
 
         buffer = new Buffer();
         buffer.putString(V_C);
@@ -111,8 +122,8 @@ public abstract class AbstractDHGClient implements KeyExchange {
         buffer.putMPInt(e);
         buffer.putMPInt(f);
         buffer.putMPInt(K);
-        sha.update(buffer.array(), 0, buffer.available());
-        H = sha.digest();
+        hash.update(buffer.array(), 0, buffer.available());
+        H = hash.digest();
 
         Signature verif = NamedFactory.Utils.create(session.getFactoryManager().getSignatureFactories(), keyAlg);
         verif.init(serverKey, null);
@@ -125,7 +136,7 @@ public abstract class AbstractDHGClient implements KeyExchange {
     }
 
     public Digest getHash() {
-        return sha;
+        return hash;
     }
 
     public byte[] getH() {

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1706dca4/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
index d5c22a7..5359d03 100644
--- 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
@@ -45,9 +45,11 @@ public class DHG1 extends AbstractDHGClient {
 
     }
 
-    protected void initDH(DH dh) {
+    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/1706dca4/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
index 0098b01..6c47e9d 100644
--- 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
@@ -47,9 +47,11 @@ public class DHG14 extends AbstractDHGClient {
 
     }
 
-    protected void initDH(DH dh) {
+    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/1706dca4/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
new file mode 100644
index 0000000..e14738e
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/kex/ECDHP256.java
@@ -0,0 +1,53 @@
+/*
+ * 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/1706dca4/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
new file mode 100644
index 0000000..cb05e47
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/kex/ECDHP384.java
@@ -0,0 +1,53 @@
+/*
+ * 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/1706dca4/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
new file mode 100644
index 0000000..9e36951
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/kex/ECDHP521.java
@@ -0,0 +1,53 @@
+/*
+ * 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/1706dca4/sshd-core/src/main/java/org/apache/sshd/common/KeyPairProvider.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/KeyPairProvider.java b/sshd-core/src/main/java/org/apache/sshd/common/KeyPairProvider.java
index d143ee9..63b87c2 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/KeyPairProvider.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/KeyPairProvider.java
@@ -39,10 +39,27 @@ public interface KeyPairProvider {
     String SSH_DSS = "ssh-dss";
 
     /**
-     * Load a key of the specified type which can be "ssh-rsa" or "ssh-dss".
-     * If there is no key of this type, return <code>null</code>
+     * SSH identifier for EC keys in NIST curve P-256
+     */
+    String ECDSA_SHA2_NISTP256 = "ecdsa-sha2-nistp256";
+
+    /**
+     * SSH identifier for EC keys in NIST curve P-384
+     */
+    String ECDSA_SHA2_NISTP384 = "ecdsa-sha2-nistp384";
+
+    /**
+     * SSH identifier for EC keys in NIST curve P-521
+     */
+    String ECDSA_SHA2_NISTP521 = "ecdsa-sha2-nistp521";
+
+    /**
+     * Load a key of the specified type which can be "ssh-rsa", "ssh-dss", or
+     * "ecdsa-sha2-nistp{256,384,521}". If there is no key of this type, return
+     * <code>null</code>
      *
-     * @param type the type of key to load
+     * @param type
+     *            the type of key to load
      * @return a valid key pair or <code>null</code>
      */
     KeyPair loadKey(String type);

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1706dca4/sshd-core/src/main/java/org/apache/sshd/common/cipher/ECCurves.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/cipher/ECCurves.java b/sshd-core/src/main/java/org/apache/sshd/common/cipher/ECCurves.java
new file mode 100644
index 0000000..7c7a951
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/cipher/ECCurves.java
@@ -0,0 +1,195 @@
+/*
+ * 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.cipher;
+
+import java.math.BigInteger;
+import java.security.spec.ECFieldFp;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.ECPoint;
+import java.security.spec.EllipticCurve;
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.apache.sshd.common.Digest;
+import org.apache.sshd.common.digest.SHA256;
+import org.apache.sshd.common.digest.SHA384;
+import org.apache.sshd.common.digest.SHA512;
+
+/**
+ * Utilities for working with elliptic curves.
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class ECCurves {
+    public static final String ECDSA_SHA2_PREFIX = "ecdsa-sha2-";
+
+    public static final String NISTP256 = "nistp256";
+
+    public static final String NISTP384 = "nistp384";
+
+    public static final String NISTP521 = "nistp521";
+
+    private static final Map<Integer, String> CURVE_SIZES = new TreeMap<Integer, String>();
+    static {
+        CURVE_SIZES.put(256, NISTP256);
+        CURVE_SIZES.put(384, NISTP384);
+        CURVE_SIZES.put(521, NISTP521);
+    }
+
+    public static String getCurveName(ECParameterSpec params) {
+        int fieldSize = getCurveSize(params);
+        final String curveName = getCurveName(fieldSize);
+        if (curveName == null) {
+            throw new RuntimeException("invalid curve size " + fieldSize);
+        }
+        return curveName;
+    }
+
+    public static String getCurveName(int fieldSize) {
+        String curveName = CURVE_SIZES.get(fieldSize);
+        if (curveName == null) {
+            return null;
+        }
+        return curveName;
+    }
+
+    public static int getCurveSize(ECParameterSpec params) {
+        return params.getCurve().getField().getFieldSize();
+    }
+
+    public static Digest getDigestForParams(ECParameterSpec params) {
+        int size = getCurveSize(params);
+        if (size <= 256) {
+            return new SHA256();
+        } else if (size <= 384) {
+            return new SHA384();
+        } else {
+            return new SHA512();
+        }
+    }
+
+    /**
+     * Decode an OctetString to EllipticCurvePoint according to SECG 2.3.4
+     */
+    public static ECPoint decodeECPoint(byte[] M, EllipticCurve curve) {
+        if (M.length == 0) {
+            return null;
+        }
+
+        // M has len 2 ceil(log_2(q)/8) + 1 ?
+        int elementSize = (curve.getField().getFieldSize() + 7) / 8;
+        if (M.length != 2 * elementSize + 1) {
+            return null;
+        }
+
+        // step 3.2
+        if (M[0] != 0x04) {
+            return null;
+        }
+
+        // Step 3.3
+        byte[] xp = new byte[elementSize];
+        System.arraycopy(M, 1, xp, 0, elementSize);
+
+        // Step 3.4
+        byte[] yp = new byte[elementSize];
+        System.arraycopy(M, 1 + elementSize, yp, 0, elementSize);
+
+        ECPoint P = new ECPoint(new BigInteger(1, xp), new BigInteger(1, yp));
+
+        // TODO check point 3.5
+
+        // Step 3.6
+        return P;
+    }
+
+    /**
+     * Encode EllipticCurvePoint to an OctetString
+     */
+    public static byte[] encodeECPoint(ECPoint group, EllipticCurve curve) {
+        // M has len 2 ceil(log_2(q)/8) + 1 ?
+        int elementSize = (curve.getField().getFieldSize() + 7) / 8;
+        byte[] M = new byte[2 * elementSize + 1];
+
+        // Uncompressed format
+        M[0] = 0x04;
+
+        {
+            byte[] affineX = removeLeadingZeroes(group.getAffineX().toByteArray());
+            System.arraycopy(affineX, 0, M, 1 + elementSize - affineX.length, affineX.length);
+        }
+
+        {
+            byte[] affineY = removeLeadingZeroes(group.getAffineY().toByteArray());
+            System.arraycopy(affineY, 0, M, 1 + elementSize + elementSize - affineY.length, affineY.length);
+        }
+
+        return M;
+    }
+
+    private static byte[] removeLeadingZeroes(byte[] input) {
+        if (input[0] != 0x00) {
+            return input;
+        }
+
+        int pos = 1;
+        while (pos < input.length - 1 && input[pos] == 0x00) {
+            pos++;
+        }
+
+        byte[] output = new byte[input.length - pos];
+        System.arraycopy(input, pos, output, 0, output.length);
+        return output;
+    }
+
+    public static class EllipticCurves {
+        public static ECParameterSpec nistp256 = new ECParameterSpec(
+                new EllipticCurve(
+                        new ECFieldFp(new BigInteger("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF", 16)),
+                        new BigInteger("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC", 16),
+                        new BigInteger("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", 16)),
+                new ECPoint(
+                        new BigInteger("6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296", 16),
+                        new BigInteger("4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5", 16)),
+                new BigInteger("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551", 16),
+                1);
+
+        public static ECParameterSpec nistp384 = new ECParameterSpec(
+                new EllipticCurve(
+                        new ECFieldFp(new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF", 16)),
+                        new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC", 16),
+                        new BigInteger("B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF", 16)),
+                new ECPoint(
+                        new BigInteger("AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7", 16),
+                        new BigInteger("3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F", 16)),
+                new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973", 16),
+                1);
+
+        public static ECParameterSpec nistp521 = new ECParameterSpec(
+                new EllipticCurve(
+                        new ECFieldFp(new BigInteger("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 16)),
+                        new BigInteger("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC", 16),
+                        new BigInteger("0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00", 16)),
+                new ECPoint(
+                        new BigInteger("00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66", 16),
+                        new BigInteger("011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650", 16)),
+                new BigInteger("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409", 16),
+                1);
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1706dca4/sshd-core/src/main/java/org/apache/sshd/common/digest/SHA256.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/digest/SHA256.java b/sshd-core/src/main/java/org/apache/sshd/common/digest/SHA256.java
new file mode 100644
index 0000000..079663d
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/digest/SHA256.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.common.digest;
+
+import org.apache.sshd.common.Digest;
+import org.apache.sshd.common.NamedFactory;
+
+/**
+ * SHA-256 Digest.
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class SHA256 extends BaseDigest {
+
+    /**
+     * Named factory for SHA1 digest
+     */
+    public static class Factory implements NamedFactory<Digest> {
+
+        public String getName() {
+            return "sha256";
+        }
+
+        public Digest create() {
+            return new SHA256();
+        }
+    }
+
+    /**
+     * Create a new instance of a SHA-256 digest
+     */
+    public SHA256() {
+        super("SHA-256", 32);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1706dca4/sshd-core/src/main/java/org/apache/sshd/common/digest/SHA384.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/digest/SHA384.java b/sshd-core/src/main/java/org/apache/sshd/common/digest/SHA384.java
new file mode 100644
index 0000000..04dc356
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/digest/SHA384.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.common.digest;
+
+import org.apache.sshd.common.Digest;
+import org.apache.sshd.common.NamedFactory;
+
+/**
+ * SHA-384 Digest.
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class SHA384 extends BaseDigest {
+
+    /**
+     * Named factory for SHA1 digest
+     */
+    public static class Factory implements NamedFactory<Digest> {
+
+        public String getName() {
+            return "sha384";
+        }
+
+        public Digest create() {
+            return new SHA384();
+        }
+    }
+
+    /**
+     * Create a new instance of a SHA-384 digest
+     */
+    public SHA384() {
+        super("SHA-384", 48);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1706dca4/sshd-core/src/main/java/org/apache/sshd/common/digest/SHA512.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/digest/SHA512.java b/sshd-core/src/main/java/org/apache/sshd/common/digest/SHA512.java
new file mode 100644
index 0000000..943ee9a
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/digest/SHA512.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.common.digest;
+
+import org.apache.sshd.common.Digest;
+import org.apache.sshd.common.NamedFactory;
+
+/**
+ * SHA-512 Digest.
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class SHA512 extends BaseDigest {
+
+    /**
+     * Named factory for SHA1 digest
+     */
+    public static class Factory implements NamedFactory<Digest> {
+
+        public String getName() {
+            return "sha512";
+        }
+
+        public Digest create() {
+            return new SHA512();
+        }
+    }
+
+    /**
+     * Create a new instance of a SHA-512 digest
+     */
+    public SHA512() {
+        super("SHA-512", 64);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1706dca4/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
new file mode 100644
index 0000000..2097b5d
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/kex/AbstractDH.java
@@ -0,0 +1,59 @@
+/*
+ * 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.Digest;
+
+/**
+ * Base class for the Diffie-Hellman key agreement.
+ * 
+ */
+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();
+        }
+    }
+
+    public abstract void setF(byte[] e);
+
+    public abstract byte[] getE() throws Exception;
+
+    protected abstract byte[] calculateK() throws Exception;
+
+    public byte[] getK() throws Exception {
+        if (K == null) {
+            K_array = calculateK();
+            K = new BigInteger(K_array);
+        }
+        return K_array;
+    }
+
+    public abstract Digest getHash() throws Exception;
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1706dca4/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
index 8b05f29..cb8e1ab 100644
--- 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
@@ -28,6 +28,8 @@ 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.digest.SHA1;
 import org.apache.sshd.common.util.SecurityUtils;
 
 /**
@@ -35,15 +37,13 @@ import org.apache.sshd.common.util.SecurityUtils;
  *
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
-public class DH {
+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 BigInteger K;  // shared secret key
-    private byte[] K_array;
     private KeyPairGenerator myKpairGen;
     private KeyAgreement myKeyAgree;
 
@@ -64,17 +64,12 @@ public class DH {
         return e_array;
     }
 
-    public byte[] getK() throws Exception {
-        if (K == null) {
-            KeyFactory myKeyFac = SecurityUtils.getKeyFactory("DH");
-            DHPublicKeySpec keySpec = new DHPublicKeySpec(f, p, g);
-            PublicKey yourPubKey = myKeyFac.generatePublic(keySpec);
-            myKeyAgree.doPhase(yourPubKey, true);
-            byte[] mySharedSecret = myKeyAgree.generateSecret();
-            K = new BigInteger(mySharedSecret);
-            K_array = mySharedSecret;
-        }
-        return K_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 myKeyAgree.generateSecret();
     }
 
     public void setP(byte[] p) {
@@ -100,4 +95,9 @@ public class DH {
     void setF(BigInteger f) {
         this.f = f;
     }
+
+    @Override
+    public Digest getHash() throws Exception {
+        return new SHA1();
+    }
 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1706dca4/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
new file mode 100644
index 0000000..65fce4c
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/kex/ECDH.java
@@ -0,0 +1,89 @@
+/*
+ * 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.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PublicKey;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.ECPoint;
+import java.security.spec.ECPublicKeySpec;
+
+import javax.crypto.KeyAgreement;
+
+import org.apache.sshd.common.Digest;
+import org.apache.sshd.common.cipher.ECCurves;
+import org.apache.sshd.common.util.SecurityUtils;
+
+/**
+ * Elliptic Curve Diffie-Hellman key agreement.
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class ECDH extends AbstractDH {
+
+    private ECParameterSpec params;
+    private ECPoint e;
+    private byte[] e_array;
+    private ECPoint f;
+    private KeyPairGenerator myKpairGen;
+    private KeyAgreement myKeyAgree;
+
+    public ECDH() throws Exception {
+        myKpairGen = SecurityUtils.getKeyPairGenerator("EC");
+        myKeyAgree = SecurityUtils.getKeyAgreement("ECDH");
+    }
+
+    @Override
+    public byte[] getE() throws Exception {
+        if (e == null) {
+            myKpairGen.initialize(params);
+            KeyPair myKpair = myKpairGen.generateKeyPair();
+            myKeyAgree.init(myKpair.getPrivate());
+            e = ((ECPublicKey) myKpair.getPublic()).getW();
+            e_array = ECCurves.encodeECPoint(e, params.getCurve());
+        }
+        return e_array;
+    }
+
+    @Override
+    protected byte[] calculateK() throws Exception {
+        KeyFactory myKeyFac = SecurityUtils.getKeyFactory("EC");
+        ECPublicKeySpec keySpec = new ECPublicKeySpec(f, params);
+        PublicKey yourPubKey = myKeyFac.generatePublic(keySpec);
+        myKeyAgree.doPhase(yourPubKey, true);
+        return myKeyAgree.generateSecret();
+    }
+
+    public void setCurveParameters(ECParameterSpec params) {
+        this.params = params;
+    }
+
+    @Override
+    public void setF(byte[] f) {
+        this.f = ECCurves.decodeECPoint(f, params.getCurve());
+    }
+
+    @Override
+    public Digest getHash() throws Exception {
+        return ECCurves.getDigestForParams(params);
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1706dca4/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/AbstractKeyPairProvider.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/AbstractKeyPairProvider.java b/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/AbstractKeyPairProvider.java
index 21f09d3..0337e87 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/AbstractKeyPairProvider.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/AbstractKeyPairProvider.java
@@ -20,7 +20,9 @@ package org.apache.sshd.common.keyprovider;
 
 import java.security.KeyPair;
 import java.security.interfaces.DSAKey;
+import java.security.interfaces.ECKey;
 import java.security.interfaces.RSAKey;
+import java.security.spec.ECParameterSpec;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -73,6 +75,21 @@ public abstract class AbstractKeyPairProvider implements KeyPairProvider {
             return SSH_DSS;
         } else if (key instanceof RSAKey) {
             return SSH_RSA;
+        } else if (key instanceof ECKey) {
+            ECKey ecKey = (ECKey) key;
+            ECParameterSpec ecSpec = ecKey.getParams();
+            /*
+             * TODO make this more robust by checking the actual parameters instead of
+             * just the field size.
+             */
+            switch (ecSpec.getCurve().getField().getFieldSize()) {
+            case 256:
+                return ECDSA_SHA2_NISTP256;
+            case 384:
+                return ECDSA_SHA2_NISTP384;
+            case 521:
+                return ECDSA_SHA2_NISTP521;
+            }
         }
         return null;
     }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1706dca4/sshd-core/src/main/java/org/apache/sshd/common/signature/AbstractSignatureDSA.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/signature/AbstractSignatureDSA.java b/sshd-core/src/main/java/org/apache/sshd/common/signature/AbstractSignatureDSA.java
new file mode 100644
index 0000000..bd2f466
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/signature/AbstractSignatureDSA.java
@@ -0,0 +1,91 @@
+/*
+ * 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.signature;
+
+
+/**
+ * DSA <code>Signature</code>
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public abstract class AbstractSignatureDSA extends AbstractSignature {
+    protected AbstractSignatureDSA(String algorithm) {
+	super(algorithm);
+    }
+
+    public byte[] sign() throws Exception {
+        byte[] sig = signature.sign();
+
+        // sig is in ASN.1
+        // SEQUENCE::={ r INTEGER, s INTEGER }
+        int len = 0;
+        int index = 3;
+        len = sig[index++] & 0xff;
+        byte[] r = new byte[len];
+        System.arraycopy(sig, index, r, 0, r.length);
+        index = index + len + 1;
+        len = sig[index++] & 0xff;
+        byte[] s = new byte[len];
+        System.arraycopy(sig, index, s, 0, s.length);
+
+        byte[] result = new byte[40];
+
+        // result must be 40 bytes, but length of r and s may not be 20 bytes
+
+        System.arraycopy(r,
+                         (r.length > 20) ? 1 : 0,
+                         result,
+                         (r.length > 20) ? 0 : 20 - r.length,
+                         (r.length > 20) ? 20 : r.length);
+        System.arraycopy(s,
+                         (s.length > 20) ? 1 : 0,
+                         result,
+                         (s.length > 20) ? 20 : 40 - s.length,
+                         (s.length > 20) ? 20 : s.length);
+
+        return result;
+    }
+
+    public boolean verify(byte[] sig) throws Exception {
+        sig = extractSig(sig);
+
+        // ASN.1
+        int frst = ((sig[0] & 0x80) != 0 ? 1 : 0);
+        int scnd = ((sig[20] & 0x80) != 0 ? 1 : 0);
+
+        int length = sig.length + 6 + frst + scnd;
+        byte[] tmp = new byte[length];
+        tmp[0] = (byte) 0x30;
+        tmp[1] = (byte) 0x2c;
+        tmp[1] += frst;
+        tmp[1] += scnd;
+        tmp[2] = (byte) 0x02;
+        tmp[3] = (byte) 0x14;
+        tmp[3] += frst;
+        System.arraycopy(sig, 0, tmp, 4 + frst, 20);
+        tmp[4 + tmp[3]] = (byte) 0x02;
+        tmp[5 + tmp[3]] = (byte) 0x14;
+        tmp[5 + tmp[3]] += scnd;
+        System.arraycopy(sig, 20, tmp, 6 + tmp[3] + scnd, 20);
+        sig = tmp;
+
+        return signature.verify(sig);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1706dca4/sshd-core/src/main/java/org/apache/sshd/common/signature/SignatureDSA.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/signature/SignatureDSA.java b/sshd-core/src/main/java/org/apache/sshd/common/signature/SignatureDSA.java
index 9162cbe..1109f54 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/signature/SignatureDSA.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/signature/SignatureDSA.java
@@ -23,12 +23,11 @@ import org.apache.sshd.common.NamedFactory;
 import org.apache.sshd.common.Signature;
 
 /**
- * DSA <code>Signature</code>
+ * TODO Add javadoc
  *
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
-public class SignatureDSA extends AbstractSignature {
-
+public class SignatureDSA extends AbstractSignatureDSA {
     /**
      * A named factory for DSA signature
      */
@@ -47,64 +46,4 @@ public class SignatureDSA extends AbstractSignature {
     public SignatureDSA() {
         super("SHA1withDSA");
     }
-
-    public byte[] sign() throws Exception {
-        byte[] sig = signature.sign();
-
-        // sig is in ASN.1
-        // SEQUENCE::={ r INTEGER, s INTEGER }
-        int len = 0;
-        int index = 3;
-        len = sig[index++] & 0xff;
-        byte[] r = new byte[len];
-        System.arraycopy(sig, index, r, 0, r.length);
-        index = index + len + 1;
-        len = sig[index++] & 0xff;
-        byte[] s = new byte[len];
-        System.arraycopy(sig, index, s, 0, s.length);
-
-        byte[] result = new byte[40];
-
-        // result must be 40 bytes, but length of r and s may not be 20 bytes
-
-        System.arraycopy(r,
-                         (r.length > 20) ? 1 : 0,
-                         result,
-                         (r.length > 20) ? 0 : 20 - r.length,
-                         (r.length > 20) ? 20 : r.length);
-        System.arraycopy(s,
-                         (s.length > 20) ? 1 : 0,
-                         result,
-                         (s.length > 20) ? 20 : 40 - s.length,
-                         (s.length > 20) ? 20 : s.length);
-
-        return result;
-    }
-
-    public boolean verify(byte[] sig) throws Exception {
-        sig = extractSig(sig);
-
-        // ASN.1
-        int frst = ((sig[0] & 0x80) != 0 ? 1 : 0);
-        int scnd = ((sig[20] & 0x80) != 0 ? 1 : 0);
-
-        int length = sig.length + 6 + frst + scnd;
-        byte[] tmp = new byte[length];
-        tmp[0] = (byte) 0x30;
-        tmp[1] = (byte) 0x2c;
-        tmp[1] += frst;
-        tmp[1] += scnd;
-        tmp[2] = (byte) 0x02;
-        tmp[3] = (byte) 0x14;
-        tmp[3] += frst;
-        System.arraycopy(sig, 0, tmp, 4 + frst, 20);
-        tmp[4 + tmp[3]] = (byte) 0x02;
-        tmp[5 + tmp[3]] = (byte) 0x14;
-        tmp[5 + tmp[3]] += scnd;
-        System.arraycopy(sig, 20, tmp, 6 + tmp[3] + scnd, 20);
-        sig = tmp;
-
-        return signature.verify(sig);
-    }
-
 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1706dca4/sshd-core/src/main/java/org/apache/sshd/common/signature/SignatureECDSA.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/signature/SignatureECDSA.java b/sshd-core/src/main/java/org/apache/sshd/common/signature/SignatureECDSA.java
new file mode 100644
index 0000000..d82cc3d
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/signature/SignatureECDSA.java
@@ -0,0 +1,180 @@
+/*
+ * 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.signature;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.spec.ECParameterSpec;
+
+import org.apache.sshd.common.KeyPairProvider;
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.Signature;
+import org.apache.sshd.common.cipher.ECCurves;
+import org.apache.sshd.common.util.Buffer;
+
+/**
+ * Signature algorithm for EC keys using ECDSA. There 
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class SignatureECDSA extends AbstractSignatureDSA {
+
+    /**
+     * Signature algorithm for curves of above 384 bits.
+     */
+    private static final String SIGNATURE_ALGORITHM_512 = "SHA512withECDSA";
+
+    /**
+     * Signature algorithm for curves from 256 to 384 bits.
+     */
+    private static final String SIGNATURE_ALGORITHM_384 = "SHA384withECDSA";
+
+    /**
+     * Signature algorithm for curves of 256 bits and below.
+     */
+    private static final String SIGNATURE_ALGORITHM_256 = "SHA256withECDSA";
+
+    /**
+     * A named factory for ECDSA signatures of NIST P-256
+     */
+    public static class NISTP256Factory implements NamedFactory<Signature> {
+
+        public String getName() {
+            return KeyPairProvider.ECDSA_SHA2_NISTP256;
+        }
+
+        public Signature create() {
+            return new SignatureECDSA(SIGNATURE_ALGORITHM_256);
+        }
+    }
+
+    /**
+     * A named factory for ECDSA signatures of NIST P-384
+     */
+    public static class NISTP384Factory implements NamedFactory<Signature> {
+
+        public String getName() {
+            return KeyPairProvider.ECDSA_SHA2_NISTP384;
+        }
+
+        public Signature create() {
+            return new SignatureECDSA(SIGNATURE_ALGORITHM_384);
+        }
+    }
+
+    /**
+     * A named factory for ECDSA signatures of NIST P-521
+     */
+    public static class NISTP521Factory implements NamedFactory<Signature> {
+
+        public String getName() {
+            return KeyPairProvider.ECDSA_SHA2_NISTP521;
+        }
+
+        public Signature create() {
+            return new SignatureECDSA(SIGNATURE_ALGORITHM_512);
+        }
+    }
+
+    protected SignatureECDSA(String algo) {
+        super(algo);
+    }
+
+    public static Signature getByCurveSize(ECParameterSpec params) {
+        int curveSize = ECCurves.getCurveSize(params);
+        if (curveSize <= 256) {
+            return new SignatureECDSA(SIGNATURE_ALGORITHM_256);
+        } else if (curveSize <= 384) {
+            return new SignatureECDSA(SIGNATURE_ALGORITHM_384);
+        } else {
+            return new SignatureECDSA(SIGNATURE_ALGORITHM_512);
+        }
+    }
+
+    @Override
+    public byte[] sign() throws Exception {
+        byte[] sig = signature.sign();
+
+        if ((sig[0] != 0x30) || (sig[1] != sig.length - 2) || (sig[2] != 0x02)) {
+            throw new IOException("Invalid signature format");
+        }
+
+        int rLength = sig[3];
+        if ((rLength + 6 > sig.length) || (sig[4 + rLength] != 0x02)) {
+            throw new IOException("Invalid signature format");
+        }
+
+        int sLength = sig[5 + rLength];
+        if (6 + rLength + sLength > sig.length) {
+            throw new IOException("Invalid signature format");
+        }
+
+        byte[] rArray = new byte[rLength];
+        byte[] sArray = new byte[sLength];
+
+        System.arraycopy(sig, 4, rArray, 0, rLength);
+        System.arraycopy(sig, 6 + rLength, sArray, 0, sLength);
+
+        BigInteger r = new BigInteger(rArray);
+        BigInteger s = new BigInteger(sArray);
+
+        // Write the <r,s> to its own types writer.
+        Buffer rsBuf = new Buffer();
+        rsBuf.putMPInt(r);
+        rsBuf.putMPInt(s);
+
+        return rsBuf.getCompactData();
+    }
+
+    @Override
+    public boolean verify(byte[] sig) throws Exception {
+        sig = extractSig(sig);
+
+        Buffer rsBuf = new Buffer(sig);
+        byte[] rArray = rsBuf.getMPIntAsBytes();
+        byte[] sArray = rsBuf.getMPIntAsBytes();
+
+        if (rsBuf.available() != 0) {
+            throw new IOException("Signature had padding");
+        }
+
+        // ASN.1
+        int frst = ((rArray[0] & 0x80) != 0 ? 1 : 0);
+        int scnd = ((sArray[0] & 0x80) != 0 ? 1 : 0);
+
+        int length = rArray.length + sArray.length + 6 + frst + scnd;
+        byte[] tmp = new byte[length];
+        tmp[0] = (byte) 0x30;
+        tmp[1] = (byte) 0x2c;
+        tmp[1] += frst;
+        tmp[1] += scnd;
+        tmp[2] = (byte) 0x02;
+        tmp[3] = (byte) 0x14;
+        tmp[3] += frst;
+        System.arraycopy(rArray, 0, tmp, 4 + frst, 20);
+        tmp[4 + tmp[3]] = (byte) 0x02;
+        tmp[5 + tmp[3]] = (byte) 0x14;
+        tmp[5 + tmp[3]] += scnd;
+        System.arraycopy(sArray, 0, tmp, 6 + tmp[3] + scnd, 20);
+        sig = tmp;
+
+        return signature.verify(sig);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1706dca4/sshd-core/src/main/java/org/apache/sshd/common/util/Buffer.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/Buffer.java b/sshd-core/src/main/java/org/apache/sshd/common/util/Buffer.java
index d82f980..804eec6 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/util/Buffer.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/Buffer.java
@@ -27,10 +27,16 @@ import java.security.PrivateKey;
 import java.security.PublicKey;
 import java.security.interfaces.DSAPrivateKey;
 import java.security.interfaces.DSAPublicKey;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.ECPublicKey;
 import java.security.interfaces.RSAPrivateCrtKey;
 import java.security.interfaces.RSAPublicKey;
 import java.security.spec.DSAPrivateKeySpec;
 import java.security.spec.DSAPublicKeySpec;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.ECPoint;
+import java.security.spec.ECPrivateKeySpec;
+import java.security.spec.ECPublicKeySpec;
 import java.security.spec.InvalidKeySpecException;
 import java.security.spec.RSAPrivateCrtKeySpec;
 import java.security.spec.RSAPublicKeySpec;
@@ -38,6 +44,7 @@ import java.security.spec.RSAPublicKeySpec;
 import org.apache.sshd.common.KeyPairProvider;
 import org.apache.sshd.common.SshConstants;
 import org.apache.sshd.common.SshException;
+import org.apache.sshd.common.cipher.ECCurves;
 
 /**
  * TODO Add javadoc
@@ -252,6 +259,12 @@ public final class Buffer implements Readable {
                 BigInteger y = getMPInt();
                 KeyFactory keyFactory = SecurityUtils.getKeyFactory("DSA");
                 key = keyFactory.generatePublic(new DSAPublicKeySpec(y, p, q, g));
+            } else if (KeyPairProvider.ECDSA_SHA2_NISTP256.equals(keyAlg)) {
+                key = getRawECKey("nistp256", ECCurves.EllipticCurves.nistp256);
+            } else if (KeyPairProvider.ECDSA_SHA2_NISTP384.equals(keyAlg)) {
+                key = getRawECKey("nistp384", ECCurves.EllipticCurves.nistp384);
+            } else if (KeyPairProvider.ECDSA_SHA2_NISTP521.equals(keyAlg)) {
+                key = getRawECKey("nistp521", ECCurves.EllipticCurves.nistp521);
             } else {
                 throw new IllegalStateException("Unsupported algorithm: " + keyAlg);
             }
@@ -265,6 +278,18 @@ public final class Buffer implements Readable {
         }
     }
 
+    private PublicKey getRawECKey(String expectedCurve, ECParameterSpec spec) throws InvalidKeySpecException,
+            SshException, NoSuchAlgorithmException, NoSuchProviderException {
+        String curveName = getString();
+        if (!expectedCurve.equals(curveName)) {
+            throw new InvalidKeySpecException("Curve name does not match expected: " + curveName + " vs "
+                    + expectedCurve);
+        }
+        ECPoint w = ECCurves.decodeECPoint(getStringAsBytes(), spec.getCurve());
+        KeyFactory keyFactory = SecurityUtils.getKeyFactory("EC");
+        return keyFactory.generatePublic(new ECPublicKeySpec(w, spec));
+    }
+
     public KeyPair getKeyPair() throws SshException {
         try {
             PublicKey pub;
@@ -291,6 +316,12 @@ public final class Buffer implements Readable {
                 KeyFactory keyFactory = SecurityUtils.getKeyFactory("DSA");
                 pub = keyFactory.generatePublic(new DSAPublicKeySpec(y, p, q, g));
                 prv = keyFactory.generatePrivate(new DSAPrivateKeySpec(x, p, q, g));
+            } else if (KeyPairProvider.ECDSA_SHA2_NISTP256.equals(keyAlg)) {
+                return extractEC("nistp256", ECCurves.EllipticCurves.nistp256);
+            } else if (KeyPairProvider.ECDSA_SHA2_NISTP384.equals(keyAlg)) {
+                return extractEC("nistp384", ECCurves.EllipticCurves.nistp384);
+            } else if (KeyPairProvider.ECDSA_SHA2_NISTP521.equals(keyAlg)) {
+                return extractEC("nistp521", ECCurves.EllipticCurves.nistp521);
             } else {
                 throw new IllegalStateException("Unsupported algorithm: " + keyAlg);
             }
@@ -304,6 +335,27 @@ public final class Buffer implements Readable {
         }
     }
 
+    private KeyPair extractEC(String expectedCurveName, ECParameterSpec spec) throws NoSuchAlgorithmException,
+            NoSuchProviderException, InvalidKeySpecException, SshException {
+        String curveName = getString();
+        byte[] groupBytes = getStringAsBytes();
+        BigInteger exponent = getMPInt();
+
+        if (!expectedCurveName.equals(curveName)) {
+            throw new SshException("Expected curve " + expectedCurveName + " but was " + curveName);
+        }
+
+        ECPoint group = ECCurves.decodeECPoint(groupBytes, spec.getCurve());
+        if (group == null) {
+            throw new InvalidKeySpecException("Couldn't decode EC group");
+        }
+
+        KeyFactory keyFactory = SecurityUtils.getKeyFactory("EC");
+        PublicKey pubKey = keyFactory.generatePublic(new ECPublicKeySpec(group, spec));
+        PrivateKey privKey = keyFactory.generatePrivate(new ECPrivateKeySpec(exponent, spec));
+        return new KeyPair(pubKey, privKey);
+    }
+
     public SshConstants.Message getCommand() {
         byte b = getByte();
         SshConstants.Message cmd = SshConstants.Message.fromByte(b);
@@ -435,6 +487,13 @@ public final class Buffer implements Readable {
             putMPInt(((DSAPublicKey) key).getParams().getQ());
             putMPInt(((DSAPublicKey) key).getParams().getG());
             putMPInt(((DSAPublicKey) key).getY());
+        } else if (key instanceof ECPublicKey) {
+            ECPublicKey ecKey = (ECPublicKey) key;
+            ECParameterSpec ecParams = ecKey.getParams();
+            String curveName = ECCurves.getCurveName(ecParams);
+            putString(ECCurves.ECDSA_SHA2_PREFIX + curveName);
+            putString(curveName);
+            putBytes(ECCurves.encodeECPoint(ecKey.getW(), ecParams.getCurve()));
         } else {
             throw new IllegalStateException("Unsupported algorithm: " + key.getAlgorithm());
         }
@@ -456,6 +515,16 @@ public final class Buffer implements Readable {
             putMPInt(((DSAPublicKey) key.getPublic()).getParams().getG());
             putMPInt(((DSAPublicKey) key.getPublic()).getY());
             putMPInt(((DSAPrivateKey) key.getPrivate()).getX());
+        } else if (key.getPublic() instanceof ECPublicKey) {
+            ECPublicKey ecPub = (ECPublicKey) key.getPublic();
+            ECPrivateKey ecPriv = (ECPrivateKey) key.getPrivate();
+            ECParameterSpec ecParams = ecPub.getParams();
+            String curveName = ECCurves.getCurveName(ecParams);
+
+            putString(ECCurves.ECDSA_SHA2_PREFIX + curveName);
+            putString(curveName);
+            putString(ECCurves.encodeECPoint(ecPub.getW(), ecParams.getCurve()));
+            putMPInt(ecPriv.getS());
         } else {
             throw new IllegalStateException("Unsupported algorithm: " + key.getPublic().getAlgorithm());
         }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1706dca4/sshd-core/src/main/java/org/apache/sshd/common/util/SecurityUtils.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/SecurityUtils.java b/sshd-core/src/main/java/org/apache/sshd/common/util/SecurityUtils.java
index e2fb362..1669cf5 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/util/SecurityUtils.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/SecurityUtils.java
@@ -48,6 +48,19 @@ public class SecurityUtils {
     private static String securityProvider = null;
     private static Boolean registerBouncyCastle;
     private static boolean registrationDone;
+    private static Boolean hasEcc;
+
+    public static boolean hasEcc() {
+        if (hasEcc == null) {
+            try {
+                getKeyPairGenerator("EC");
+                hasEcc = true;
+            } catch (Throwable t) {
+                hasEcc = false;
+            }
+        }
+        return hasEcc;
+    }
 
     public static synchronized void setSecurityProvider(String securityProvider) {
         SecurityUtils.securityProvider = securityProvider;

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1706dca4/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
index bbcff30..16e107a 100644
--- 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
@@ -27,8 +27,7 @@ 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.digest.SHA1;
-import org.apache.sshd.common.kex.DH;
+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;
@@ -50,8 +49,8 @@ public abstract class AbstractDHGServer implements KeyExchange {
     private byte[] V_C;
     private byte[] I_S;
     private byte[] I_C;
-    private Digest sha;
-    private DH dh;
+    private Digest hash;
+    private AbstractDH dh;
     private byte[] e;
     private byte[] f;
     private byte[] K;
@@ -66,14 +65,13 @@ public abstract class AbstractDHGServer implements KeyExchange {
         this.V_C = V_C;
         this.I_S = I_S;
         this.I_C = I_C;
-        sha = new SHA1();
-        sha.init();
-        dh = new DH();
-        initDH(dh);
+        dh = getDH();
+        hash = dh.getHash();
+        hash.init();
         f = dh.getE();
     }
 
-    protected abstract void initDH(DH dh);
+    protected abstract AbstractDH getDH() throws Exception;
 
     public boolean next(Buffer buffer) throws Exception {
         SshConstants.Message cmd = buffer.getCommand();
@@ -105,8 +103,8 @@ public abstract class AbstractDHGServer implements KeyExchange {
         buffer.putMPInt(e);
         buffer.putMPInt(f);
         buffer.putMPInt(K);
-        sha.update(buffer.array(), 0, buffer.available());
-        H = sha.digest();
+        hash.update(buffer.array(), 0, buffer.available());
+        H = hash.digest();
 
         byte[] sigH;
         buffer.clear();
@@ -135,7 +133,7 @@ public abstract class AbstractDHGServer implements KeyExchange {
     }
 
     public Digest getHash() {
-        return sha;
+        return hash;
     }
 
     public byte[] getH() {

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1706dca4/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
index 7f95a52..abe3474 100644
--- 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
@@ -20,6 +20,7 @@ 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;
 
@@ -42,9 +43,12 @@ public class DHG1 extends AbstractDHGServer {
 
     }
 
-    protected void initDH(DH dh) {
+    @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/1706dca4/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
index 660c790..2a7b925 100644
--- 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
@@ -20,6 +20,7 @@ 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;
 
@@ -46,9 +47,12 @@ public class DHG14 extends AbstractDHGServer {
 
     }
 
-    protected void initDH(DH dh) {
+    @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/1706dca4/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
new file mode 100644
index 0000000..7da6c9a
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/server/kex/ECDHP256.java
@@ -0,0 +1,53 @@
+/*
+ * 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/1706dca4/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
new file mode 100644
index 0000000..093cba7
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/server/kex/ECDHP384.java
@@ -0,0 +1,53 @@
+/*
+ * 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/1706dca4/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
new file mode 100644
index 0000000..674e95b
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/server/kex/ECDHP521.java
@@ -0,0 +1,53 @@
+/*
+ * 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/1706dca4/sshd-core/src/main/java/org/apache/sshd/server/keyprovider/AbstractGeneratorHostKeyProvider.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/keyprovider/AbstractGeneratorHostKeyProvider.java b/sshd-core/src/main/java/org/apache/sshd/server/keyprovider/AbstractGeneratorHostKeyProvider.java
index 7c99222..7cd8333 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/keyprovider/AbstractGeneratorHostKeyProvider.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/keyprovider/AbstractGeneratorHostKeyProvider.java
@@ -27,6 +27,7 @@ import java.io.InputStream;
 import java.io.OutputStream;
 import java.security.KeyPair;
 import java.security.KeyPairGenerator;
+import java.security.spec.AlgorithmParameterSpec;
 
 import org.apache.sshd.common.keyprovider.AbstractKeyPairProvider;
 import org.apache.sshd.common.util.SecurityUtils;
@@ -41,6 +42,7 @@ public abstract class AbstractGeneratorHostKeyProvider extends AbstractKeyPairPr
     private String path;
     private String algorithm = "DSA";
     private int keySize;
+    private AlgorithmParameterSpec keySpec;
     private KeyPair keyPair;
 
     protected AbstractGeneratorHostKeyProvider() {
@@ -85,6 +87,14 @@ public abstract class AbstractGeneratorHostKeyProvider extends AbstractKeyPairPr
         this.keySize = keySize;
     }
 
+    public AlgorithmParameterSpec getKeySpec() {
+        return keySpec;
+    }
+
+    public void setKeySpec(AlgorithmParameterSpec keySpec) {
+        this.keySpec = keySpec;
+    }
+
     protected abstract KeyPair doReadKeyPair(InputStream is) throws Exception;
 
     protected abstract void doWriteKeyPair(KeyPair kp, OutputStream os) throws Exception;
@@ -138,7 +148,9 @@ public abstract class AbstractGeneratorHostKeyProvider extends AbstractKeyPairPr
     private KeyPair generateKeyPair(String algorithm) {
         try {
             KeyPairGenerator generator = SecurityUtils.getKeyPairGenerator(algorithm);
-            if (keySize != 0) {
+            if (keySpec != null) {
+                generator.initialize(keySpec);
+            } else if (keySize != 0) {
                 generator.initialize(keySize);
             }
             log.info("Generating host key...");