Repository: mina-sshd Updated Branches: refs/heads/master 19d5e8edd -> 3ddd221b3
[SSHD-390] Support switching to a none cipher on the client side for performances Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/c4c42ca4 Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/c4c42ca4 Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/c4c42ca4 Branch: refs/heads/master Commit: c4c42ca4cf489571c45a2a3d9898c01b1a8e8ee4 Parents: 19d5e8e Author: Guillaume Nodet <[email protected]> Authored: Tue Dec 16 21:56:41 2014 +0100 Committer: Guillaume Nodet <[email protected]> Committed: Tue Dec 16 21:56:41 2014 +0100 ---------------------------------------------------------------------- .../java/org/apache/sshd/ClientSession.java | 15 +++++++++ .../sshd/client/session/ClientSessionImpl.java | 34 ++++++++++++++++++++ .../test/java/org/apache/sshd/ClientTest.java | 17 ++++++++++ 3 files changed, 66 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/c4c42ca4/sshd-core/src/main/java/org/apache/sshd/ClientSession.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/ClientSession.java b/sshd-core/src/main/java/org/apache/sshd/ClientSession.java index 482719b..bee81f7 100644 --- a/sshd-core/src/main/java/org/apache/sshd/ClientSession.java +++ b/sshd-core/src/main/java/org/apache/sshd/ClientSession.java @@ -34,6 +34,7 @@ import org.apache.sshd.client.future.AuthFuture; import org.apache.sshd.common.Session; import org.apache.sshd.common.SshdSocketAddress; import org.apache.sshd.common.future.CloseFuture; +import org.apache.sshd.common.future.SshFuture; /** * An authenticated session to a given SSH server @@ -230,4 +231,18 @@ public interface ClientSession extends Session { */ ClientFactoryManager getFactoryManager(); + /** + * Switch to a none cipher for performance. + * + * This should be done after the authentication phase has been performed. + * After such a switch, interactive channels are not allowed anymore. + * Both client and server must have been configured to support the none cipher. + * If that's not the case, the returned future will be set with an exception. + * + * @return an {@link SshFuture} that can be used to wait for the exchange + * to be finished + * @throws IOException if a key exchange is already running + */ + SshFuture switchToNoneCipher() throws IOException; + } http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/c4c42ca4/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java b/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java index 76a8bca..9309674 100644 --- a/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java +++ b/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java @@ -22,6 +22,7 @@ import java.io.IOException; import java.net.SocketAddress; import java.security.KeyPair; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -53,7 +54,11 @@ import org.apache.sshd.common.SessionListener; import org.apache.sshd.common.SshConstants; import org.apache.sshd.common.SshException; import org.apache.sshd.common.SshdSocketAddress; +import org.apache.sshd.common.cipher.CipherNone; +import org.apache.sshd.common.future.DefaultSshFuture; +import org.apache.sshd.common.future.SshFuture; import org.apache.sshd.common.io.IoSession; +import org.apache.sshd.common.session.AbstractConnectionService; import org.apache.sshd.common.session.AbstractSession; import org.apache.sshd.common.session.ConnectionService; import org.apache.sshd.common.util.Buffer; @@ -188,6 +193,32 @@ public class ClientSessionImpl extends AbstractSession implements ClientSession } } + @Override + public SshFuture switchToNoneCipher() throws IOException { + if (!(currentService instanceof AbstractConnectionService) + || !((AbstractConnectionService) currentService).getChannels().isEmpty()) { + throw new IllegalStateException("The switch to the none cipher must be done immediately after authentication"); + } + if (kexState.compareAndSet(KEX_STATE_DONE, KEX_STATE_INIT)) { + reexchangeFuture = new DefaultSshFuture(null); + if (!serverProposal[SshConstants.PROPOSAL_ENC_ALGS_CTOS].matches("(^|.*,)none($|,.*)") + || !serverProposal[SshConstants.PROPOSAL_ENC_ALGS_STOC].matches("(^|.*,)none($|,.*)")) { + reexchangeFuture.setValue(new SshException("Server does not support none cipher")); + } else if (!clientProposal[SshConstants.PROPOSAL_ENC_ALGS_CTOS].matches("(^|.*,)none($|,.*)") + || !clientProposal[SshConstants.PROPOSAL_ENC_ALGS_STOC].matches("(^|.*,)none($|,.*)")) { + reexchangeFuture.setValue(new SshException("Client does not support none cipher")); + } else { + log.info("Switching to none cipher"); + clientProposal[SshConstants.PROPOSAL_ENC_ALGS_CTOS] = "none"; + clientProposal[SshConstants.PROPOSAL_ENC_ALGS_STOC] = "none"; + I_C = sendKexInit(clientProposal); + } + return reexchangeFuture; + } else { + throw new SshException("In flight key exchange"); + } + } + public ClientChannel createChannel(String type) throws IOException { return createChannel(type, null); } @@ -205,6 +236,9 @@ public class ClientSessionImpl extends AbstractSession implements ClientSession } public ChannelShell createShellChannel() throws IOException { + if (inCipher instanceof CipherNone || outCipher instanceof CipherNone) { + throw new IllegalStateException("Interactive channels are not supported with none cipher"); + } ChannelShell channel = new ChannelShell(); getConnectionService().registerChannel(channel); return channel; http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/c4c42ca4/sshd-core/src/test/java/org/apache/sshd/ClientTest.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/test/java/org/apache/sshd/ClientTest.java b/sshd-core/src/test/java/org/apache/sshd/ClientTest.java index 245973d..45881d9 100644 --- a/sshd-core/src/test/java/org/apache/sshd/ClientTest.java +++ b/sshd-core/src/test/java/org/apache/sshd/ClientTest.java @@ -51,6 +51,7 @@ import org.apache.sshd.common.Service; import org.apache.sshd.common.Session; import org.apache.sshd.common.SshConstants; import org.apache.sshd.common.SshException; +import org.apache.sshd.common.cipher.CipherNone; import org.apache.sshd.common.forward.TcpipServerChannel; import org.apache.sshd.common.future.CloseFuture; import org.apache.sshd.common.future.SshFutureListener; @@ -744,6 +745,22 @@ public class ClientTest extends BaseTest { client.stop(); } + @Test + public void testSwitchToNoneCipher() throws Exception { + sshd.getCipherFactories().add(new CipherNone.Factory()); + client.getCipherFactories().add(new CipherNone.Factory()); + client.start(); + ClientSession session = client.connect("smx", "localhost", port).await().getSession(); + session.addPasswordIdentity("smx"); + session.auth().verify(); + session.switchToNoneCipher().await(); + + ClientChannel channel = session.createSubsystemChannel("sftp"); + channel.open().verify(); + + client.stop(); + } + private void suspend(IoSession ioSession) { if (ioSession instanceof MinaSession) { ((MinaSession) ioSession).suspend();
