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...");