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

[2/6] mina-sshd git commit: [SSHD-488] Implement (a naive) ssh-keyscan

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/test/java/org/apache/sshd/agent/AgentTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/agent/AgentTest.java b/sshd-core/src/test/java/org/apache/sshd/agent/AgentTest.java
new file mode 100644
index 0000000..dc7d958
--- /dev/null
+++ b/sshd-core/src/test/java/org/apache/sshd/agent/AgentTest.java
@@ -0,0 +1,212 @@
+/*
+ * 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.agent;
+
+import static org.apache.sshd.util.Utils.createTestKeyPairProvider;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.security.KeyPair;
+import java.security.PublicKey;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.sshd.agent.SshAgent;
+import org.apache.sshd.agent.local.LocalAgentFactory;
+import org.apache.sshd.agent.local.ProxyAgentFactory;
+import org.apache.sshd.agent.unix.AgentClient;
+import org.apache.sshd.agent.unix.AgentServer;
+import org.apache.sshd.client.SshClient;
+import org.apache.sshd.client.channel.ChannelShell;
+import org.apache.sshd.client.session.ClientSession;
+import org.apache.sshd.common.keyprovider.KeyPairProvider;
+import org.apache.sshd.common.util.SecurityUtils;
+import org.apache.sshd.server.Command;
+import org.apache.sshd.server.Environment;
+import org.apache.sshd.server.SshServer;
+import org.apache.sshd.server.PublickeyAuthenticator.AcceptAllPublickeyAuthenticator;
+import org.apache.sshd.server.forward.ForwardingFilter;
+import org.apache.sshd.util.BaseTestSupport;
+import org.apache.sshd.util.BogusPasswordAuthenticator;
+import org.apache.sshd.util.EchoShellFactory;
+import org.apache.sshd.util.Utils;
+import org.junit.Assume;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class AgentTest extends BaseTestSupport {
+    public AgentTest() {
+        super();
+    }
+
+    @Test
+    public void testAgentServer() throws Exception {
+        // TODO: revisit this test to work without BC
+        Assume.assumeTrue("BouncyCastle not registered", SecurityUtils.isBouncyCastleRegistered());
+
+        try(AgentServer agent = new AgentServer()) {
+            String authSocket;
+            try {
+                authSocket = agent.start();
+            } catch (UnsatisfiedLinkError e) {
+                // the native library is not available, so these tests should be skipped
+                authSocket = null;
+            }
+            Assume.assumeTrue("Native library N/A", authSocket != null);
+    
+            try(SshAgent client = new AgentClient(authSocket)) {
+                List<SshAgent.Pair<PublicKey, String>> keys = client.getIdentities();
+                assertNotNull("No initial identities", keys);
+                assertEquals("Unexpected initial identities size", 0, keys.size());
+        
+                KeyPair k = Utils.createTestHostKeyProvider().loadKey(KeyPairProvider.SSH_RSA);
+                client.addIdentity(k, "");
+                keys = client.getIdentities();
+                assertNotNull("No registered identities after add", keys);
+                assertEquals("Mismatched registered keys size", 1, keys.size());
+        
+                client.removeIdentity(k.getPublic());
+                keys = client.getIdentities();
+                assertNotNull("No registered identities after remove", keys);
+                assertEquals("Registered keys size not empty", 0, keys.size());
+        
+                client.removeAllIdentities();
+            }    
+        }
+    }
+
+    @Test
+    public void testAgentForwarding() throws Exception {
+        // TODO: revisit this test to work without BC
+        Assume.assumeTrue("BouncyCastle not registered", SecurityUtils.isBouncyCastleRegistered());
+
+        TestEchoShellFactory shellFactory = new TestEchoShellFactory();
+        ProxyAgentFactory agentFactory = new ProxyAgentFactory();
+        LocalAgentFactory localAgentFactory = new LocalAgentFactory();
+        String username = getCurrentTestName();
+        KeyPair pair = createTestKeyPairProvider("dsaprivkey.pem").loadKey(KeyPairProvider.SSH_DSS);
+        localAgentFactory.getAgent().addIdentity(pair, username);
+
+        try(SshServer sshd1 = SshServer.setUpDefaultServer()) {
+            sshd1.setKeyPairProvider(Utils.createTestHostKeyProvider());
+            sshd1.setShellFactory(shellFactory);
+            sshd1.setPasswordAuthenticator(BogusPasswordAuthenticator.INSTANCE);
+            sshd1.setPublickeyAuthenticator(AcceptAllPublickeyAuthenticator.INSTANCE);
+            sshd1.setAgentFactory(agentFactory);
+            sshd1.setTcpipForwardingFilter(ForwardingFilter.AcceptAllForwardingFilter.INSTANCE);
+            sshd1.start();
+            
+            final int port1 = sshd1.getPort();
+            try(SshServer sshd2 = SshServer.setUpDefaultServer()) {
+                sshd2.setKeyPairProvider(Utils.createTestHostKeyProvider());
+                sshd2.setShellFactory(new TestEchoShellFactory());
+                sshd2.setPasswordAuthenticator(BogusPasswordAuthenticator.INSTANCE);
+                sshd2.setPublickeyAuthenticator(AcceptAllPublickeyAuthenticator.INSTANCE);
+                sshd1.setTcpipForwardingFilter(ForwardingFilter.AcceptAllForwardingFilter.INSTANCE);
+                sshd2.setAgentFactory(new ProxyAgentFactory());
+                sshd2.start();
+    
+                final int port2 = sshd2.getPort();
+                try(SshClient client1 = SshClient.setUpDefaultClient()) {
+                    client1.setAgentFactory(localAgentFactory);
+                    client1.start();
+                    
+                    try(ClientSession session1 = client1.connect(username, "localhost", port1).await().getSession()) {
+                        session1.auth().verify(15L, TimeUnit.SECONDS);
+
+                        try(ChannelShell channel1 = session1.createShellChannel();
+                            ByteArrayOutputStream out = new ByteArrayOutputStream();
+                            ByteArrayOutputStream err = new ByteArrayOutputStream()) {
+
+                            channel1.setOut(out);
+                            channel1.setErr(err);
+                            channel1.setAgentForwarding(true);
+                            channel1.open().await();
+                            
+                            try(OutputStream pipedIn = channel1.getInvertedIn()) {
+                                synchronized (shellFactory.shell) {
+                                    System.out.println("Possibly waiting for remote shell to start");
+                                    if (!shellFactory.shell.started) {
+                                        shellFactory.shell.wait();
+                                    }
+                                }
+                        
+                                try(SshClient client2 = SshClient.setUpDefaultClient()) {
+                                    client2.setAgentFactory(agentFactory);
+                                    client2.getProperties().putAll(shellFactory.shell.getEnvironment().getEnv());
+                                    client2.start();
+                                    
+                                    try(ClientSession session2 = client2.connect(username, "localhost", port2).await().getSession()) {
+                                        session2.auth().verify(15L, TimeUnit.SECONDS);
+
+                                        try(ChannelShell channel2 = session2.createShellChannel()) {
+                                            channel2.setIn(shellFactory.shell.getIn());
+                                            channel2.setOut(shellFactory.shell.getOut());
+                                            channel2.setErr(shellFactory.shell.getErr());
+                                            channel2.setAgentForwarding(true);
+                                            channel2.open().await();
+                                    
+                                            pipedIn.write("foo\n".getBytes());
+                                            pipedIn.flush();
+                                        }
+                                
+                                        Thread.sleep(1000);
+                                
+                                        System.out.println(out.toString());
+                                        System.err.println(err.toString());
+                            
+                                        sshd1.stop(true);
+                                        sshd2.stop(true);
+                                        client1.stop();
+                                        client2.stop();
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    public static class TestEchoShellFactory extends EchoShellFactory {
+
+        TestEchoShell shell = new TestEchoShell();
+
+        @Override
+        public Command create() {
+            return shell;
+        }
+
+        public class TestEchoShell extends EchoShell {
+
+            boolean started;
+
+            @Override
+            public synchronized void start(Environment env) throws IOException {
+                super.start(env);
+                started = true;
+                notifyAll();
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/test/java/org/apache/sshd/client/ClientTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/ClientTest.java b/sshd-core/src/test/java/org/apache/sshd/client/ClientTest.java
new file mode 100644
index 0000000..8285002
--- /dev/null
+++ b/sshd-core/src/test/java/org/apache/sshd/client/ClientTest.java
@@ -0,0 +1,958 @@
+/*
+ * 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;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PipedInputStream;
+import java.io.PipedOutputStream;
+import java.net.SocketAddress;
+import java.security.KeyPair;
+import java.security.PublicKey;
+import java.util.Arrays;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.sshd.client.ClientFactoryManager;
+import org.apache.sshd.client.ServerKeyVerifier;
+import org.apache.sshd.client.SshClient;
+import org.apache.sshd.client.UserAuth;
+import org.apache.sshd.client.UserInteraction;
+import org.apache.sshd.client.auth.UserAuthKeyboardInteractive;
+import org.apache.sshd.client.auth.UserAuthPassword;
+import org.apache.sshd.client.auth.UserAuthPublicKey;
+import org.apache.sshd.client.channel.ChannelExec;
+import org.apache.sshd.client.channel.ChannelShell;
+import org.apache.sshd.client.channel.ClientChannel;
+import org.apache.sshd.client.future.AuthFuture;
+import org.apache.sshd.client.future.OpenFuture;
+import org.apache.sshd.client.session.ClientSession;
+import org.apache.sshd.common.FactoryManager;
+import org.apache.sshd.common.FactoryManagerUtils;
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.RuntimeSshException;
+import org.apache.sshd.common.Service;
+import org.apache.sshd.common.SshConstants;
+import org.apache.sshd.common.SshException;
+import org.apache.sshd.common.channel.Channel;
+import org.apache.sshd.common.cipher.BuiltinCiphers;
+import org.apache.sshd.common.future.CloseFuture;
+import org.apache.sshd.common.future.SshFutureListener;
+import org.apache.sshd.common.io.IoReadFuture;
+import org.apache.sshd.common.io.IoSession;
+import org.apache.sshd.common.io.IoWriteFuture;
+import org.apache.sshd.common.io.mina.MinaSession;
+import org.apache.sshd.common.io.nio2.Nio2Session;
+import org.apache.sshd.common.keyprovider.KeyPairProvider;
+import org.apache.sshd.common.session.AbstractSession;
+import org.apache.sshd.common.session.ConnectionService;
+import org.apache.sshd.common.session.Session;
+import org.apache.sshd.common.sftp.SftpConstants;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.buffer.Buffer;
+import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
+import org.apache.sshd.common.util.io.NoCloseOutputStream;
+import org.apache.sshd.server.Command;
+import org.apache.sshd.server.CommandFactory;
+import org.apache.sshd.server.PublickeyAuthenticator;
+import org.apache.sshd.server.SshServer;
+import org.apache.sshd.server.PublickeyAuthenticator.AcceptAllPublickeyAuthenticator;
+import org.apache.sshd.server.channel.ChannelSession;
+import org.apache.sshd.server.command.UnknownCommand;
+import org.apache.sshd.server.forward.TcpipServerChannel;
+import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
+import org.apache.sshd.server.session.ServerConnectionService;
+import org.apache.sshd.server.session.ServerSession;
+import org.apache.sshd.server.session.ServerUserAuthService;
+import org.apache.sshd.util.AsyncEchoShellFactory;
+import org.apache.sshd.util.BaseTestSupport;
+import org.apache.sshd.util.BogusPasswordAuthenticator;
+import org.apache.sshd.util.EchoShellFactory;
+import org.apache.sshd.util.TeeOutputStream;
+import org.apache.sshd.util.Utils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+
+/**
+ * TODO Add javadoc
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class ClientTest extends BaseTestSupport {
+
+    private SshServer sshd;
+    private SshClient client;
+    private int port;
+    private CountDownLatch authLatch;
+    private CountDownLatch channelLatch;
+
+    public ClientTest() {
+        super();
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        authLatch = new CountDownLatch(0);
+        channelLatch = new CountDownLatch(0);
+
+        sshd = SshServer.setUpDefaultServer();
+        sshd.setKeyPairProvider(Utils.createTestHostKeyProvider());
+        sshd.setShellFactory(new TestEchoShellFactory());
+        sshd.setCommandFactory(new CommandFactory() {
+            @Override
+            public Command createCommand(String command) {
+                return new UnknownCommand(command);
+            }
+        });
+        sshd.setPasswordAuthenticator(BogusPasswordAuthenticator.INSTANCE);
+        sshd.setPublickeyAuthenticator(AcceptAllPublickeyAuthenticator.INSTANCE);
+        sshd.setServiceFactories(Arrays.asList(
+                new ServerUserAuthService.Factory() {
+                    @Override
+                    public Service create(Session session) throws IOException {
+                        return new ServerUserAuthService(session) {
+                            @SuppressWarnings("synthetic-access")
+                            @Override
+                            public void process(byte cmd, Buffer buffer) throws Exception {
+                                authLatch.await();
+                                super.process(cmd, buffer);
+                            }
+                        };
+                    }
+                },
+                new ServerConnectionService.Factory()
+        ));
+        sshd.setChannelFactories(Arrays.<NamedFactory<Channel>>asList(
+                new ChannelSession.ChannelSessionFactory() {
+                    @Override
+                    public Channel create() {
+                        return new ChannelSession() {
+                            @SuppressWarnings("synthetic-access")
+                            @Override
+                            public OpenFuture open(int recipient, int rwsize, int rmpsize, Buffer buffer) {
+                                try {
+                                    channelLatch.await();
+                                } catch (InterruptedException e) {
+                                    throw new RuntimeSshException(e);
+                                }
+                                return super.open(recipient, rwsize, rmpsize, buffer);
+                            }
+
+                            @Override
+                            public String toString() {
+                                return "ChannelSession" + "[id=" + id + ", recipient=" + recipient + "]";
+                            }
+                        };
+                    }
+                },
+                TcpipServerChannel.DirectTcpipFactory.INSTANCE));
+        sshd.start();
+        port = sshd.getPort();
+
+        client = SshClient.setUpDefaultClient();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        if (sshd != null) {
+            sshd.stop(true);
+        }
+        if (client != null) {
+            client.stop();
+        }
+    }
+
+    @Test
+    public void testAsyncClient() throws Exception {
+        FactoryManagerUtils.updateProperty(sshd, FactoryManager.WINDOW_SIZE, 1024);
+        sshd.setShellFactory(new AsyncEchoShellFactory());
+
+        FactoryManagerUtils.updateProperty(client, FactoryManager.WINDOW_SIZE, 1024);
+        client.start();
+
+        try(ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+            session.addPasswordIdentity(getCurrentTestName());
+            session.auth().verify(5L, TimeUnit.SECONDS);
+
+            try(final ChannelShell channel = session.createShellChannel()) {
+                channel.setStreaming(ClientChannel.Streaming.Async);
+                channel.open().verify(5L, TimeUnit.SECONDS);
+        
+                final byte[] message = "0123456789\n".getBytes();
+                final int nbMessages = 1000;
+        
+                try(final ByteArrayOutputStream baosOut = new ByteArrayOutputStream();
+                    final ByteArrayOutputStream baosErr = new ByteArrayOutputStream()) {
+                    final AtomicInteger writes = new AtomicInteger(nbMessages);
+            
+                    channel.getAsyncIn().write(new ByteArrayBuffer(message))
+                            .addListener(new SshFutureListener<IoWriteFuture>() {
+                                @Override
+                                public void operationComplete(IoWriteFuture future) {
+                                    try {
+                                        if (future.isWritten()) {
+                                            if (writes.decrementAndGet() > 0) {
+                                                channel.getAsyncIn().write(new ByteArrayBuffer(message)).addListener(this);
+                                            } else {
+                                                channel.getAsyncIn().close(false);
+                                            }
+                                        } else {
+                                            throw new SshException("Error writing", future.getException());
+                                        }
+                                    } catch (IOException e) {
+                                        if (!channel.isClosing()) {
+                                            e.printStackTrace();
+                                            channel.close(true);
+                                        }
+                                    }
+                                }
+                            });
+                    channel.getAsyncOut().read(new ByteArrayBuffer())
+                            .addListener(new SshFutureListener<IoReadFuture>() {
+                                @Override
+                                public void operationComplete(IoReadFuture future) {
+                                    try {
+                                        future.verify(5L, TimeUnit.SECONDS);
+                                        Buffer buffer = future.getBuffer();
+                                        baosOut.write(buffer.array(), buffer.rpos(), buffer.available());
+                                        buffer.rpos(buffer.rpos() + buffer.available());
+                                        buffer.compact();
+                                        channel.getAsyncOut().read(buffer).addListener(this);
+                                    } catch (IOException e) {
+                                        if (!channel.isClosing()) {
+                                            e.printStackTrace();
+                                            channel.close(true);
+                                        }
+                                    }
+                                }
+                            });
+                    channel.getAsyncErr().read(new ByteArrayBuffer())
+                            .addListener(new SshFutureListener<IoReadFuture>() {
+                                @Override
+                                public void operationComplete(IoReadFuture future) {
+                                    try {
+                                        future.verify(5L, TimeUnit.SECONDS);
+                                        Buffer buffer = future.getBuffer();
+                                        baosErr.write(buffer.array(), buffer.rpos(), buffer.available());
+                                        buffer.rpos(buffer.rpos() + buffer.available());
+                                        buffer.compact();
+                                        channel.getAsyncErr().read(buffer).addListener(this);
+                                    } catch (IOException e) {
+                                        if (!channel.isClosing()) {
+                                            e.printStackTrace();
+                                            channel.close(true);
+                                        }
+                                    }
+                                }
+                            });
+        
+                    channel.waitFor(ClientChannel.CLOSED, 0);
+        
+                    assertEquals(nbMessages * message.length, baosOut.size());
+                }
+            }    
+
+            client.close(true);
+        } finally {
+            client.stop();
+        }
+    }
+
+    @Test
+    public void testCommandDeadlock() throws Exception {
+        client.start();
+
+        try(ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+            session.addPasswordIdentity(getCurrentTestName());
+            session.auth().verify(5L, TimeUnit.SECONDS);
+            
+            try(ChannelExec channel = session.createExecChannel("test");
+                OutputStream stdout = new NoCloseOutputStream(System.out);
+                OutputStream stderr = new NoCloseOutputStream(System.err)) {
+
+                channel.setOut(stdout);
+                channel.setErr(stderr);
+                channel.open().await();
+                Thread.sleep(100);
+                try {
+                    for (int i = 0; i < 100; i++) {
+                        channel.getInvertedIn().write("a".getBytes());
+                        channel.getInvertedIn().flush();
+                    }
+                } catch (SshException e) {
+                    // That's ok, the channel is being closed by the other side
+                }
+                assertEquals(ClientChannel.CLOSED, channel.waitFor(ClientChannel.CLOSED, 0) & ClientChannel.CLOSED);
+                session.close(false).await();
+            }
+        } finally {
+            client.stop();
+        }
+    }
+
+    @Test
+    public void testClient() throws Exception {
+        client.start();
+
+        try(ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+            session.addPasswordIdentity(getCurrentTestName());
+            session.auth().verify(5L, TimeUnit.SECONDS);
+            
+            try(ClientChannel channel = session.createChannel(ClientChannel.CHANNEL_SHELL);
+                ByteArrayOutputStream sent = new ByteArrayOutputStream();
+                PipedOutputStream pipedIn = new PipedOutputStream();
+                PipedInputStream pipedOut = new PipedInputStream(pipedIn)) {
+
+                channel.setIn(pipedOut);
+
+                try(OutputStream teeOut = new TeeOutputStream(sent, pipedIn);
+                    ByteArrayOutputStream out = new ByteArrayOutputStream();
+                    ByteArrayOutputStream err = new ByteArrayOutputStream()) {
+
+                    channel.setOut(out);
+                    channel.setErr(err);
+                    channel.open();
+            
+                    teeOut.write("this is my command\n".getBytes());
+                    teeOut.flush();
+            
+                    StringBuilder sb = new StringBuilder();
+                    for (int i = 0; i < 1000; i++) {
+                        sb.append("0123456789");
+                    }
+                    sb.append("\n");
+                    teeOut.write(sb.toString().getBytes());
+            
+                    teeOut.write("exit\n".getBytes());
+                    teeOut.flush();
+            
+                    channel.waitFor(ClientChannel.CLOSED, 0);
+            
+                    channel.close(false);
+                    client.stop();
+            
+                    assertArrayEquals(sent.toByteArray(), out.toByteArray());
+                }
+            }
+        } finally {
+            client.stop();
+        }
+    }
+
+    @Test
+    public void testClientInverted() throws Exception {
+        client.start();
+        
+        try(ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+            session.addPasswordIdentity(getCurrentTestName());
+            session.auth().verify(5L, TimeUnit.SECONDS);
+            
+            try(ClientChannel channel = session.createChannel(ClientChannel.CHANNEL_SHELL);
+                ByteArrayOutputStream sent = new ByteArrayOutputStream();
+                ByteArrayOutputStream out = new ByteArrayOutputStream();
+                ByteArrayOutputStream err = new ByteArrayOutputStream()) {
+
+                channel.setOut(out);
+                channel.setErr(err);
+                channel.open().await();
+        
+                try(OutputStream pipedIn = new TeeOutputStream(sent, channel.getInvertedIn())) {
+                    pipedIn.write("this is my command\n".getBytes());
+                    pipedIn.flush();
+            
+                    StringBuilder sb = new StringBuilder();
+                    for (int i = 0; i < 1000; i++) {
+                        sb.append("0123456789");
+                    }
+                    sb.append("\n");
+                    pipedIn.write(sb.toString().getBytes());
+            
+                    pipedIn.write("exit\n".getBytes());
+                    pipedIn.flush();
+                }
+        
+                channel.waitFor(ClientChannel.CLOSED, 0);
+        
+                channel.close(false);
+                client.stop();
+        
+                assertArrayEquals(sent.toByteArray(), out.toByteArray());
+            }
+        } finally {
+            client.stop();
+        }
+    }
+
+    @Test
+    public void testClientWithCustomChannel() throws Exception {
+        client.start();
+        
+        try(ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+            session.addPasswordIdentity(getCurrentTestName());
+            session.auth().verify(5L, TimeUnit.SECONDS);
+    
+            try(ChannelShell channel = new ChannelShell();
+                ByteArrayOutputStream sent = new ByteArrayOutputStream();
+                ByteArrayOutputStream out = new ByteArrayOutputStream();
+                ByteArrayOutputStream err = new ByteArrayOutputStream()) {
+
+                session.getService(ConnectionService.class).registerChannel(channel);
+                channel.setOut(out);
+                channel.setErr(err);
+                channel.open().verify(5L, TimeUnit.SECONDS);
+                channel.close(false).await();
+            }
+        } finally {
+            client.stop();
+        }
+    }
+
+    @Test
+    public void testClientClosingStream() throws Exception {
+        client.start();
+        
+        try(ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+            session.addPasswordIdentity(getCurrentTestName());
+            session.auth().verify(5L, TimeUnit.SECONDS);
+    
+            try(ClientChannel channel = session.createChannel(ClientChannel.CHANNEL_SHELL);
+                ByteArrayOutputStream sent = new ByteArrayOutputStream();
+                PipedOutputStream pipedIn = new PipedOutputStream();
+                InputStream inPipe = new PipedInputStream(pipedIn);
+                ByteArrayOutputStream out = new ByteArrayOutputStream();
+                ByteArrayOutputStream err = new ByteArrayOutputStream()) {
+
+                channel.setIn(inPipe);
+                channel.setOut(out);
+                channel.setErr(err);
+                channel.open();
+
+                try(OutputStream teeOut = new TeeOutputStream(sent, pipedIn)) {
+                    teeOut.write("this is my command\n".getBytes());
+                    teeOut.flush();
+        
+                    StringBuilder sb = new StringBuilder();
+                    for (int i = 0; i < 1000; i++) {
+                        sb.append("0123456789");
+                    }
+                    sb.append("\n");
+                    teeOut.write(sb.toString().getBytes());
+                }    
+    
+                channel.waitFor(ClientChannel.CLOSED, 0);
+        
+                channel.close(false);
+                client.stop();
+        
+                assertArrayEquals(sent.toByteArray(), out.toByteArray());
+            }
+        } finally {
+            client.stop();
+        }
+    }
+
+    @Test
+    public void testClientWithLengthyDialog() throws Exception {
+        // Reduce window size and packet size
+//        FactoryManagerUtils.updateProperty(client, SshClient.WINDOW_SIZE, 0x20000);
+//        FactoryManagerUtils.updateProperty(client, SshClient.MAX_PACKET_SIZE, 0x1000);
+//        FactoryManagerUtils.updateProperty(sshd, SshServer.WINDOW_SIZE, 0x20000);
+//        FactoryManagerUtils.updateProperty(sshd, SshServer.MAX_PACKET_SIZE, 0x1000);
+        client.start();
+        
+        try(ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+            session.addPasswordIdentity(getCurrentTestName());
+            session.auth().verify(5L, TimeUnit.SECONDS);
+
+            try(ClientChannel channel = session.createChannel(ClientChannel.CHANNEL_SHELL);
+                ByteArrayOutputStream sent = new ByteArrayOutputStream();
+                PipedOutputStream pipedIn = new PipedOutputStream();
+                InputStream inPipe = new PipedInputStream(pipedIn); 
+                ByteArrayOutputStream out = new ByteArrayOutputStream();
+                ByteArrayOutputStream err = new ByteArrayOutputStream()) {
+
+                channel.setIn(inPipe);
+                channel.setOut(out);
+                channel.setErr(err);
+                channel.open().await();
+        
+        
+                int bytes = 0;
+                byte[] data = "01234567890123456789012345678901234567890123456789\n".getBytes();
+                long t0 = System.currentTimeMillis();
+                try(OutputStream teeOut = new TeeOutputStream(sent, pipedIn)) {
+                    for (int i = 0; i < 10000; i++) {
+                        teeOut.write(data);
+                        teeOut.flush();
+                        bytes += data.length;
+                        if ((bytes & 0xFFF00000) != ((bytes - data.length) & 0xFFF00000)) {
+                            System.out.println("Bytes written: " + bytes);
+                        }
+                    }
+                    teeOut.write("exit\n".getBytes());
+                    teeOut.flush();
+                }        
+                long t1 = System.currentTimeMillis();
+        
+                System.out.println("Sent " + (bytes / 1024) + " Kb in " + (t1 - t0) + " ms");
+        
+                System.out.println("Waiting for channel to be closed");
+        
+                channel.waitFor(ClientChannel.CLOSED, 0);
+        
+                channel.close(false);
+                client.stop();
+        
+                assertArrayEquals(sent.toByteArray(), out.toByteArray());
+                //assertArrayEquals(sent.toByteArray(), out.toByteArray());
+            }
+        } finally {
+            client.stop();
+        }
+    }
+
+    @Test(expected = SshException.class)
+    public void testOpenChannelOnClosedSession() throws Exception {
+        client.start();
+        
+        try(ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+            session.addPasswordIdentity(getCurrentTestName());
+            session.auth().verify(5L, TimeUnit.SECONDS);
+            
+            try(ClientChannel channel = session.createChannel(ClientChannel.CHANNEL_SHELL)) {
+                session.close(false);
+        
+                try(PipedOutputStream pipedIn = new PipedOutputStream();
+                    InputStream inPipe = new PipedInputStream(pipedIn);
+                    ByteArrayOutputStream out = new ByteArrayOutputStream();
+                    ByteArrayOutputStream err = new ByteArrayOutputStream()) {
+
+                    channel.setIn(inPipe);
+                    channel.setOut(out);
+                    channel.setErr(err);
+                    channel.open();
+                }
+            }
+        }
+    }
+
+    @Test
+    public void testCloseBeforeAuthSucceed() throws Exception {
+        authLatch = new CountDownLatch(1);
+        client.start();
+        
+        try(ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+            session.addPasswordIdentity(getCurrentTestName());
+
+            AuthFuture authFuture = session.auth();
+            CloseFuture closeFuture = session.close(false);
+            authLatch.countDown();
+            authFuture.await();
+            closeFuture.await();
+            assertNotNull("No authentication exception", authFuture.getException());
+            assertTrue("Future not closed", closeFuture.isClosed());
+        } finally {
+            client.stop();
+        }
+    }
+
+    @Test
+    public void testCloseCleanBeforeChannelOpened() throws Exception {
+        client.start();
+        
+        try(ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+            session.addPasswordIdentity(getCurrentTestName());
+            session.auth().verify(5L, TimeUnit.SECONDS);
+
+            try(ClientChannel channel = session.createChannel(ClientChannel.CHANNEL_SHELL);
+                InputStream inp = new ByteArrayInputStream(GenericUtils.EMPTY_BYTE_ARRAY);
+                OutputStream out = new ByteArrayOutputStream();
+                OutputStream err = new ByteArrayOutputStream()) { 
+
+                channel.setIn(inp);
+                channel.setOut(out);
+                channel.setErr(err);
+
+                OpenFuture openFuture = channel.open();
+                CloseFuture closeFuture = session.close(false);
+                openFuture.await();
+                closeFuture.await();
+                assertTrue("Not open", openFuture.isOpened());
+                assertTrue("Not closed", closeFuture.isClosed());
+            }
+        } finally {
+            client.stop();
+        }
+    }
+
+    @Test
+    public void testCloseImmediateBeforeChannelOpened() throws Exception {
+        channelLatch = new CountDownLatch(1);
+        client.start();
+
+        try(ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+            session.addPasswordIdentity(getCurrentTestName());
+            session.auth().verify(5L, TimeUnit.SECONDS);
+
+            try(ClientChannel channel = session.createChannel(ClientChannel.CHANNEL_SHELL);
+                InputStream inp = new ByteArrayInputStream(GenericUtils.EMPTY_BYTE_ARRAY);
+                OutputStream out = new ByteArrayOutputStream();
+                OutputStream err = new ByteArrayOutputStream()) { 
+
+                channel.setIn(inp);
+                channel.setOut(out);
+                channel.setErr(err);
+
+                OpenFuture openFuture = channel.open();
+                CloseFuture closeFuture = session.close(true);
+                channelLatch.countDown();
+                openFuture.await();
+                closeFuture.await();
+                assertNotNull("No open exception", openFuture.getException());
+                assertTrue("Not closed", closeFuture.isClosed());
+            }
+        } finally {
+            client.stop();
+        }
+    }
+
+    @Test
+    public void testPublicKeyAuth() throws Exception {
+        client.start();
+        
+        try(ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+            KeyPair pair = Utils.createTestHostKeyProvider().loadKey(KeyPairProvider.SSH_RSA);
+            session.addPublicKeyIdentity(pair);
+            session.auth().verify(5L, TimeUnit.SECONDS);
+        } finally {
+            client.stop();
+        }
+    }
+
+    @Test
+    public void testPublicKeyAuthNew() throws Exception {
+        client.setUserAuthFactories(Arrays.<NamedFactory<UserAuth>>asList(UserAuthPublicKey.UserAuthPublicKeyFactory.INSTANCE));
+        client.start();
+        
+        try(ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+            session.addPublicKeyIdentity(Utils.createTestHostKeyProvider().loadKey(KeyPairProvider.SSH_RSA));
+            session.auth().verify(5L, TimeUnit.SECONDS);
+        } finally {
+            client.stop();
+        }
+    }
+
+    @Test
+    public void testPublicKeyAuthNewWithFailureOnFirstIdentity() throws Exception {
+        final KeyPair pair = Utils.createTestHostKeyProvider().loadKey(KeyPairProvider.SSH_RSA);
+        sshd.setPublickeyAuthenticator(new PublickeyAuthenticator() {
+            @Override
+            public boolean authenticate(String username, PublicKey key, ServerSession session) {
+                return key.equals(pair.getPublic());
+            }
+        });
+        client.setUserAuthFactories(Arrays.<NamedFactory<UserAuth>>asList(UserAuthPublicKey.UserAuthPublicKeyFactory.INSTANCE));
+        client.start();
+
+        try(ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+            session.addPublicKeyIdentity(new SimpleGeneratorHostKeyProvider(null, "RSA").loadKey(KeyPairProvider.SSH_RSA));
+            session.addPublicKeyIdentity(pair);
+            session.auth().verify(5L, TimeUnit.SECONDS);
+        } finally {
+            client.stop();
+        }
+    }
+
+    @Test
+    public void testPasswordAuthNew() throws Exception {
+        client.setUserAuthFactories(Arrays.<NamedFactory<UserAuth>>asList(new UserAuthPassword.UserAuthPasswordFactory()));
+        client.start();
+        
+        try(ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+            session.addPasswordIdentity(getCurrentTestName());
+            session.auth().verify(5L, TimeUnit.SECONDS);
+        } finally {
+            client.stop();
+        }
+    }
+
+    @Test
+    public void testPasswordAuthNewWithFailureOnFirstIdentity() throws Exception {
+        client.setUserAuthFactories(Arrays.<NamedFactory<UserAuth>>asList(new UserAuthPassword.UserAuthPasswordFactory()));
+        client.start();
+        
+        try(ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+            session.addPasswordIdentity(getClass().getSimpleName());
+            session.addPasswordIdentity(getCurrentTestName());
+            session.auth().verify(5L, TimeUnit.SECONDS);
+        } finally {
+            client.stop();
+        }
+    }
+
+    @Test
+    public void testKeyboardInteractiveAuthNew() throws Exception {
+        client.setUserAuthFactories(Arrays.<NamedFactory<UserAuth>>asList(UserAuthKeyboardInteractive.UserAuthKeyboardInteractiveFactory.INSTANCE));
+        client.start();
+        
+        try(ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+            session.addPasswordIdentity(getCurrentTestName());
+            session.auth().verify(5L, TimeUnit.SECONDS);
+        } finally {
+            client.stop();
+        }
+    }
+
+    @Test
+    public void testKeyboardInteractiveAuthNewWithFailureOnFirstIdentity() throws Exception {
+        client.setUserAuthFactories(Arrays.<NamedFactory<UserAuth>>asList(UserAuthKeyboardInteractive.UserAuthKeyboardInteractiveFactory.INSTANCE));
+        client.start();
+        
+        try(ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+            session.addPasswordIdentity(getClass().getSimpleName());
+            session.addPasswordIdentity(getCurrentTestName());
+            session.auth().verify(5L, TimeUnit.SECONDS);
+        } finally {
+            client.stop();
+        }
+    }
+
+    @Test
+    public void testKeyboardInteractiveWithFailures() throws Exception {
+        final AtomicInteger count = new AtomicInteger();
+        final int MAX_PROMPTS = 3;
+        FactoryManagerUtils.updateProperty(client, ClientFactoryManager.PASSWORD_PROMPTS, MAX_PROMPTS);
+
+        client.setUserAuthFactories(Arrays.<NamedFactory<UserAuth>>asList(new UserAuthKeyboardInteractive.UserAuthKeyboardInteractiveFactory()));
+        client.setUserInteraction(new UserInteraction() {
+            @Override
+            public void welcome(String banner) {
+                // ignored
+            }
+            @Override
+            public String[] interactive(String destination, String name, String instruction, String[] prompt, boolean[] echo) {
+                count.incrementAndGet();
+                return new String[] { "bad" };
+            }
+        });
+        client.start();
+        
+        try(ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+            AuthFuture future = session.auth();
+            future.await();
+            assertTrue("Unexpected authentication success", future.isFailure());
+            assertEquals("Mismatched authentication retry count", MAX_PROMPTS, count.get());
+        } finally {
+            client.stop();
+        }
+    }
+
+    @Test
+    public void testKeyboardInteractiveInSessionUserInteractive() throws Exception {
+        final AtomicInteger count = new AtomicInteger();
+        final int MAX_PROMPTS = 3;
+        FactoryManagerUtils.updateProperty(client, ClientFactoryManager.PASSWORD_PROMPTS, MAX_PROMPTS);
+
+        client.setUserAuthFactories(Arrays
+                        .<NamedFactory<UserAuth>> asList(UserAuthKeyboardInteractive.UserAuthKeyboardInteractiveFactory.INSTANCE));
+        client.start();
+
+        try(ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+            session.setUserInteraction(new UserInteraction() {
+                    @Override
+                    public void welcome(String banner) {
+                        // ignored
+                    }
+        
+                    @Override
+                    public String[] interactive(String destination, String name, String instruction,
+                                                String[] prompt, boolean[] echo) {
+                        count.incrementAndGet();
+                        return new String[] { getCurrentTestName() };
+                    }
+                });
+            AuthFuture future = session.auth();
+            future.await();
+            assertTrue("Authentication not marked as success", future.isSuccess());
+            assertFalse("Authentication marked as failure", future.isFailure());
+            assertEquals("Mismatched authentication attempts count", 1, count.get());
+        } finally {
+            client.stop();
+        }
+    }
+
+    @Test
+    public void testKeyboardInteractiveInSessionUserInteractiveFailure() throws Exception {
+        final AtomicInteger count = new AtomicInteger();
+        final int MAX_PROMPTS = 3;
+        FactoryManagerUtils.updateProperty(client, ClientFactoryManager.PASSWORD_PROMPTS, MAX_PROMPTS);
+        client.setUserAuthFactories(Arrays
+                        .<NamedFactory<UserAuth>> asList(new UserAuthKeyboardInteractive.UserAuthKeyboardInteractiveFactory()));
+        client.start();
+        
+        try(ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+            session.setUserInteraction(new UserInteraction() {
+                @Override
+                public void welcome(String banner) {
+                    // ignored
+                }
+    
+                @Override
+                public String[] interactive(String destination, String name, String instruction,
+                                            String[] prompt, boolean[] echo) {
+                    count.incrementAndGet();
+                    return new String[] { "bad" };
+                }
+            });
+            AuthFuture future = session.auth();
+            future.await();
+            assertTrue("Authentication not, marked as failure", future.isFailure());
+            assertEquals("Mismatched authentication retry count", MAX_PROMPTS, count.get());
+        } finally {
+            client.stop();
+        }
+    }
+
+    @Test
+    public void testClientDisconnect() throws Exception {
+        TestEchoShellFactory.TestEchoShell.latch = new CountDownLatch(1);
+        try {
+            client.start();
+            
+            try(ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+                session.addPasswordIdentity(getCurrentTestName());
+                session.auth().verify(5L, TimeUnit.SECONDS);
+                
+                try(ClientChannel channel = session.createChannel(ClientChannel.CHANNEL_SHELL);
+                    PipedOutputStream pipedIn = new PipedOutputStream();
+                    InputStream inPipe = new PipedInputStream(pipedIn); 
+                    ByteArrayOutputStream out = new ByteArrayOutputStream();
+                    ByteArrayOutputStream err = new ByteArrayOutputStream()) {
+
+                    channel.setIn(inPipe);
+                    channel.setOut(out);
+                    channel.setErr(err);
+                    channel.open().await();
+        
+        //            ((AbstractSession) session).disconnect(SshConstants.SSH2_DISCONNECT_BY_APPLICATION, "Cancel");
+                    AbstractSession cs = (AbstractSession) session;
+                    Buffer buffer = cs.createBuffer(SshConstants.SSH_MSG_DISCONNECT);
+                    buffer.putInt(SshConstants.SSH2_DISCONNECT_BY_APPLICATION);
+                    buffer.putString("Cancel");
+                    buffer.putString("");
+                    IoWriteFuture f = cs.writePacket(buffer);
+                    f.await();
+                    suspend(cs.getIoSession());
+    
+                    TestEchoShellFactory.TestEchoShell.latch.await();
+                }
+            } finally {
+                client.stop();
+            }
+        } finally {
+            TestEchoShellFactory.TestEchoShell.latch = null;
+        }
+    }
+
+    @Test
+    public void testWaitAuth() throws Exception {
+        final AtomicBoolean ok = new AtomicBoolean();
+        client.setServerKeyVerifier(
+                new ServerKeyVerifier() {
+                    @Override
+                    public boolean verifyServerKey(
+                            ClientSession sshClientSession,
+                            SocketAddress remoteAddress,
+                            PublicKey serverKey
+                    ) {
+                        System.out.println(serverKey);
+                        ok.set(true);
+                        return true;
+                    }
+                }
+        );
+        client.start();
+        
+        try(ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+            session.waitFor(ClientSession.WAIT_AUTH, TimeUnit.SECONDS.toMillis(10L));
+            assertTrue(ok.get());
+        } finally {
+            client.stop();
+        }
+    }
+
+    @Test
+    public void testSwitchToNoneCipher() throws Exception {
+        sshd.getCipherFactories().add(BuiltinCiphers.none);
+        client.getCipherFactories().add(BuiltinCiphers.none);
+        client.start();
+        
+        try(ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
+            session.addPasswordIdentity(getCurrentTestName());
+            session.auth().verify(5L, TimeUnit.SECONDS);
+            session.switchToNoneCipher().await();
+    
+            try(ClientChannel channel = session.createSubsystemChannel(SftpConstants.SFTP_SUBSYSTEM_NAME)) {
+                channel.open().verify(5L, TimeUnit.SECONDS);
+            }
+        } finally {
+            client.stop();
+        }
+    }
+
+    private void suspend(IoSession ioSession) {
+        if (ioSession instanceof MinaSession) {
+            ((MinaSession) ioSession).suspend();
+        } else {
+            ((Nio2Session) ioSession).suspend();
+        }
+    }
+
+    public static class TestEchoShellFactory extends EchoShellFactory {
+        @Override
+        public Command create() {
+            return new TestEchoShell();
+        }
+        public static class TestEchoShell extends EchoShell {
+
+            public static CountDownLatch latch = new CountDownLatch(1);
+
+            @Override
+            public void destroy() {
+                if (latch != null) {
+                    latch.countDown();
+                }
+                super.destroy();
+            }
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        SshClient.main(args);
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/test/java/org/apache/sshd/client/session/ClientSessionImplTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/session/ClientSessionImplTest.java b/sshd-core/src/test/java/org/apache/sshd/client/session/ClientSessionImplTest.java
new file mode 100644
index 0000000..c17e711
--- /dev/null
+++ b/sshd-core/src/test/java/org/apache/sshd/client/session/ClientSessionImplTest.java
@@ -0,0 +1,103 @@
+/*
+ * 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.session;
+
+import java.io.IOException;
+import java.security.KeyPair;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.sshd.client.ClientFactoryManager;
+import org.apache.sshd.common.Factory;
+import org.apache.sshd.common.ServiceFactory;
+import org.apache.sshd.common.forward.DefaultTcpipForwarderFactory;
+import org.apache.sshd.common.io.IoSession;
+import org.apache.sshd.common.random.JceRandom;
+import org.apache.sshd.common.random.Random;
+import org.apache.sshd.common.random.SingletonRandomFactory;
+import org.apache.sshd.util.BaseTestSupport;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+import org.mockito.Mockito;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class ClientSessionImplTest extends BaseTestSupport {
+    public ClientSessionImplTest() {
+        super();
+    }
+
+    @Test
+    public void testAddRemoveIdentities() throws Exception {
+        ClientFactoryManager client = Mockito.mock(ClientFactoryManager.class);
+        Mockito.when(client.getTcpipForwarderFactory()).thenReturn(DefaultTcpipForwarderFactory.INSTANCE);
+        
+        Factory<Random> randomFactory = new SingletonRandomFactory(JceRandom.JceRandomFactory.INSTANCE);
+        Mockito.when(client.getRandomFactory()).thenReturn(randomFactory);
+        
+        List<ServiceFactory> serviceFactories = Arrays.asList(
+                    new ClientUserAuthService.Factory(),
+                    new ClientConnectionService.Factory()
+                );
+        Mockito.when(client.getServiceFactories()).thenReturn(serviceFactories);
+
+        try(ClientSession session = new ClientSessionImpl(client, Mockito.mock(IoSession.class)) {
+            @Override
+            protected void sendClientIdentification() {
+                // ignored
+            }
+            
+            @Override
+            protected void sendKexInit() throws IOException {
+                // ignored
+            }
+
+            @Override
+            public void close() throws IOException {
+                // ignored
+            }
+        }) {
+            {
+                String expected = getCurrentTestName();
+                assertNull("Unexpected initial password identity", session.removePasswordIdentity(expected));
+                session.addPasswordIdentity(expected);
+    
+                String actual = session.removePasswordIdentity(expected);
+                assertSame("Mismatched removed password identity", expected, actual);
+                assertNull("Password identity not removed", session.removePasswordIdentity(expected));
+            }
+            
+            {
+                KeyPair expected = new KeyPair(Mockito.mock(PublicKey.class), Mockito.mock(PrivateKey.class));
+                assertNull("Unexpected initial pubket identity", session.removePublicKeyIdentity(expected));
+                session.addPublicKeyIdentity(expected);
+                
+                KeyPair actual = session.removePublicKeyIdentity(expected);
+                assertSame("Mismatched removed pubkey identity", expected, actual);
+                assertNull("Pubkey identity not removed", session.removePublicKeyIdentity(expected));
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/test/java/org/apache/sshd/client/sftp/SftpFileSystemTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/sftp/SftpFileSystemTest.java b/sshd-core/src/test/java/org/apache/sshd/client/sftp/SftpFileSystemTest.java
index 1d79f0f..71cd5b0 100644
--- a/sshd-core/src/test/java/org/apache/sshd/client/sftp/SftpFileSystemTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/client/sftp/SftpFileSystemTest.java
@@ -47,8 +47,8 @@ import org.apache.sshd.common.file.FileSystemFactory;
 import org.apache.sshd.common.file.root.RootedFileSystemProvider;
 import org.apache.sshd.common.session.Session;
 import org.apache.sshd.common.sftp.SftpConstants;
-import org.apache.sshd.common.util.IoUtils;
 import org.apache.sshd.common.util.OsUtils;
+import org.apache.sshd.common.util.io.IoUtils;
 import org.apache.sshd.server.Command;
 import org.apache.sshd.server.SshServer;
 import org.apache.sshd.server.command.ScpCommandFactory;

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/test/java/org/apache/sshd/client/sftp/SftpTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/sftp/SftpTest.java b/sshd-core/src/test/java/org/apache/sshd/client/sftp/SftpTest.java
index 7aadf8c..7dc2694 100644
--- a/sshd-core/src/test/java/org/apache/sshd/client/sftp/SftpTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/client/sftp/SftpTest.java
@@ -47,9 +47,9 @@ import org.apache.sshd.common.file.FileSystemFactory;
 import org.apache.sshd.common.file.root.RootedFileSystemProvider;
 import org.apache.sshd.common.session.Session;
 import org.apache.sshd.common.sftp.SftpConstants;
-import org.apache.sshd.common.util.IoUtils;
 import org.apache.sshd.common.util.OsUtils;
 import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
+import org.apache.sshd.common.util.io.IoUtils;
 import org.apache.sshd.server.Command;
 import org.apache.sshd.server.SshServer;
 import org.apache.sshd.server.command.ScpCommandFactory;

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/test/java/org/apache/sshd/common/SshBuilderTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/common/SshBuilderTest.java b/sshd-core/src/test/java/org/apache/sshd/common/SshBuilderTest.java
new file mode 100644
index 0000000..f801f44
--- /dev/null
+++ b/sshd-core/src/test/java/org/apache/sshd/common/SshBuilderTest.java
@@ -0,0 +1,136 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sshd.common;
+
+import java.util.Collection;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.sshd.common.BaseBuilder;
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.NamedResource;
+import org.apache.sshd.common.cipher.BuiltinCiphers;
+import org.apache.sshd.common.cipher.Cipher;
+import org.apache.sshd.common.kex.BuiltinDHFactories;
+import org.apache.sshd.common.mac.BuiltinMacs;
+import org.apache.sshd.common.signature.BuiltinSignatures;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.util.BaseTestSupport;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class SshBuilderTest extends BaseTestSupport {
+    public SshBuilderTest() {
+        super();
+    }
+
+    /**
+     * Make sure that all values in {@link BuiltinCiphers} are
+     * listed in {@link BaseBuilder#DEFAULT_CIPHERS_PREFERENCE}
+     */
+    @Test
+    public void testAllBuiltinCiphersListed() {
+        Set<BuiltinCiphers> all=EnumSet.allOf(BuiltinCiphers.class);
+        // The 'none' cipher is not listed as preferred - it is implied
+        assertTrue("Missing " + BuiltinCiphers.Constants.NONE + " cipher in all values", all.remove(BuiltinCiphers.none));
+        testAllInstancesListed(all, BaseBuilder.DEFAULT_CIPHERS_PREFERENCE);
+    }
+
+    /**
+     * Make sure that all values in {@link BuiltinMacs} are
+     * listed in {@link BaseBuilder#DEFAULT_MAC_PREFERENCE}
+     */
+    @Test
+    public void testAllBuiltinMacsListed() {
+        testAllInstancesListed(BuiltinMacs.VALUES, BaseBuilder.DEFAULT_MAC_PREFERENCE);
+    }
+
+    /**
+     * Make sure that all values in {@link BuiltinSignatures} are
+     * listed in {@link BaseBuilder#DEFAULT_SIGNATURE_PREFERENCE}
+     */
+    @Test
+    public void testAllBuiltinSignaturesListed() {
+        testAllInstancesListed(BuiltinSignatures.VALUES, BaseBuilder.DEFAULT_SIGNATURE_PREFERENCE);
+    }
+
+    /**
+     * Make sure that all values in {@link BuiltinDHFactories} are
+     * listed in {@link BaseBuilder#DEFAULT_KEX_PREFERENCE}
+     */
+    @Test
+    public void testAllBuiltinDHFactoriesListed() {
+        testAllInstancesListed(BuiltinDHFactories.VALUES, BaseBuilder.DEFAULT_KEX_PREFERENCE);
+    }
+
+    private static <E extends Enum<E>> void testAllInstancesListed(Set<? extends E> expValues, Collection<? extends E> actValues) {
+        assertEquals("Mismatched actual values size", expValues.size(), actValues.size());
+        for (E expected : expValues) {
+            assertTrue(expected.name() + " not found in actual values", actValues.contains(expected));
+        }
+    }
+
+    /**
+     * Make sure that {@link BaseBuilder#setUpDefaultCiphers(boolean)} returns
+     * the correct result - i.e., according to the {@code ingoreUnsupported}
+     * parameter and in the defined preference order
+     */
+    @Test
+    public void testSetUpDefaultCiphers() {
+        for (boolean ignoreUnsupported : new boolean[] { true, false }) {
+            List<NamedFactory<Cipher>>  ciphers=BaseBuilder.setUpDefaultCiphers(ignoreUnsupported);
+            int                         numCiphers=GenericUtils.size(ciphers);
+            // make sure returned list size matches expected count
+            if (ignoreUnsupported) {
+                assertEquals("Incomplete full ciphers size", BaseBuilder.DEFAULT_CIPHERS_PREFERENCE.size(), numCiphers);
+            } else {
+                int expectedCount=0;
+                for (BuiltinCiphers c : BaseBuilder.DEFAULT_CIPHERS_PREFERENCE) {
+                    if (c.isSupported()) {
+                        expectedCount++;
+                    }
+                }
+                assertEquals("Incomplete supported ciphers size", expectedCount, numCiphers);
+            }
+            
+            // make sure order is according to the default preference list
+            List<String>    cipherNames=NamedResource.Utils.getNameList(ciphers);
+            int             nameIndex=0;
+            for (BuiltinCiphers c : BaseBuilder.DEFAULT_CIPHERS_PREFERENCE) {
+                if ((!c.isSupported()) && (!ignoreUnsupported)) {
+                    continue;
+                }
+                
+                String  expectedName=c.getName();
+                assertTrue("Out of actual ciphers for expected=" + expectedName, nameIndex < numCiphers);
+                
+                String  actualName=cipherNames.get(nameIndex);
+                assertEquals("Mismatched cipher at position " + nameIndex + " for ignoreUnsupported=" + ignoreUnsupported, expectedName, actualName);
+                nameIndex++;
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/test/java/org/apache/sshd/common/cipher/CipherTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/common/cipher/CipherTest.java b/sshd-core/src/test/java/org/apache/sshd/common/cipher/CipherTest.java
new file mode 100644
index 0000000..bc2d2ff
--- /dev/null
+++ b/sshd-core/src/test/java/org/apache/sshd/common/cipher/CipherTest.java
@@ -0,0 +1,181 @@
+/*
+ * 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.io.InputStream;
+import java.io.OutputStream;
+import java.util.Arrays;
+
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.cipher.BuiltinCiphers;
+import org.apache.sshd.common.cipher.Cipher;
+import org.apache.sshd.common.random.BouncyCastleRandom;
+import org.apache.sshd.common.random.Random;
+import org.apache.sshd.server.SshServer;
+import org.apache.sshd.util.BaseTestSupport;
+import org.apache.sshd.util.BogusPasswordAuthenticator;
+import org.apache.sshd.util.EchoShellFactory;
+import org.apache.sshd.util.JSchLogger;
+import org.apache.sshd.util.SimpleUserInfo;
+import org.apache.sshd.util.Utils;
+import org.junit.After;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+
+import com.jcraft.jsch.JSch;
+
+/**
+ * Test Cipher algorithms.
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class CipherTest extends BaseTestSupport {
+
+    private SshServer sshd;
+    private int port;
+
+    @Test
+    public void testAES128CBC() throws Exception {
+        if (BuiltinCiphers.aes128cbc.isSupported()
+                && checkCipher(com.jcraft.jsch.jce.AES128CBC.class.getName())) {
+            setUp(BuiltinCiphers.aes128cbc);
+            runTest();
+        }
+    }
+
+    @Test
+    public void testAES192CBC() throws Exception {
+        if (BuiltinCiphers.aes192cbc.isSupported()
+                && checkCipher(com.jcraft.jsch.jce.AES192CBC.class.getName())) {
+            setUp(BuiltinCiphers.aes192cbc);
+            runTest();
+        }
+    }
+
+    @Test
+    public void testAES256CBC() throws Exception {
+        if (BuiltinCiphers.aes256cbc.isSupported()
+                && checkCipher(com.jcraft.jsch.jce.AES256CBC.class.getName())) {
+            setUp(BuiltinCiphers.aes256cbc);
+            runTest();
+        }
+    }
+
+    @Test
+    public void testBlowfishCBC() throws Exception {
+        if (BuiltinCiphers.blowfishcbc.isSupported()
+                && checkCipher(com.jcraft.jsch.jce.BlowfishCBC.class.getName())) {
+            setUp(BuiltinCiphers.blowfishcbc);
+            runTest();
+        }
+    }
+
+    @Test
+    public void testTripleDESCBC() throws Exception {
+        if (BuiltinCiphers.tripledescbc.isSupported()
+                && checkCipher(com.jcraft.jsch.jce.TripleDESCBC.class.getName())) {
+            setUp(BuiltinCiphers.tripledescbc);
+            runTest();
+        }
+    }
+
+    @Test
+    public void loadTest() throws Exception {
+        Random random = new BouncyCastleRandom();
+        loadTest(BuiltinCiphers.aes128cbc, random);
+        loadTest(BuiltinCiphers.blowfishcbc, random);
+        loadTest(BuiltinCiphers.tripledescbc, random);
+    }
+
+    protected void loadTest(NamedFactory<Cipher> factory, Random random) throws Exception {
+        Cipher cipher = factory.create();
+        byte[] key = new byte[cipher.getBlockSize()];
+        byte[] iv = new byte[cipher.getIVSize()];
+        random.fill(key, 0, key.length);
+        random.fill(iv, 0, iv.length);
+        cipher.init(Cipher.Mode.Encrypt, key, iv);
+
+        byte[] input = new byte[cipher.getBlockSize()];
+        random.fill(input, 0, input.length);
+        long t0 = System.currentTimeMillis();
+        for (int i = 0; i < 100000; i++) {
+            cipher.update(input, 0, input.length);
+        }
+        long t1 = System.currentTimeMillis();
+        System.err.println(factory.getName() + ": " + (t1 - t0) + " ms");
+    }
+
+
+    protected void setUp(NamedFactory<org.apache.sshd.common.cipher.Cipher> cipher) throws Exception {
+        sshd = SshServer.setUpDefaultServer();
+        sshd.setKeyPairProvider(Utils.createTestHostKeyProvider());
+        sshd.setCipherFactories(Arrays.<NamedFactory<org.apache.sshd.common.cipher.Cipher>>asList(cipher));
+        sshd.setShellFactory(new EchoShellFactory());
+        sshd.setPasswordAuthenticator(BogusPasswordAuthenticator.INSTANCE);
+        sshd.start();
+        port = sshd.getPort();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        if (sshd != null) {
+            sshd.stop(true);
+        }
+    }
+
+    protected void runTest() throws Exception {
+        JSchLogger.init();
+        JSch sch = new JSch();
+        JSch.setConfig("cipher.s2c", "aes128-cbc,3des-cbc,blowfish-cbc,aes192-cbc,aes256-cbc,none");
+        JSch.setConfig("cipher.c2s", "aes128-cbc,3des-cbc,blowfish-cbc,aes192-cbc,aes256-cbc,none");
+        com.jcraft.jsch.Session s = sch.getSession(getCurrentTestName(), "localhost", port);
+        s.setUserInfo(new SimpleUserInfo(getCurrentTestName()));
+        s.connect();
+        com.jcraft.jsch.Channel c = s.openChannel("shell");
+        c.connect();
+        OutputStream os = c.getOutputStream();
+        InputStream is = c.getInputStream();
+        for (int i = 0; i < 10; i++) {
+            os.write("this is my command\n".getBytes());
+            os.flush();
+            byte[] data = new byte[512];
+            int len = is.read(data);
+            String str = new String(data, 0, len);
+            assertEquals("this is my command\n", str);
+        }
+        c.disconnect();
+        s.disconnect();
+    }
+
+    static boolean checkCipher(String cipher){
+        try{
+            Class<?> c=Class.forName(cipher);
+            com.jcraft.jsch.Cipher _c = (com.jcraft.jsch.Cipher)(c.newInstance());
+            _c.init(com.jcraft.jsch.Cipher.ENCRYPT_MODE,
+                    new byte[_c.getBlockSize()],
+                    new byte[_c.getIVSize()]);
+            return true;
+        }
+        catch(Exception e){
+            return false;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/test/java/org/apache/sshd/common/config/SshConfigFileReaderTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/common/config/SshConfigFileReaderTest.java b/sshd-core/src/test/java/org/apache/sshd/common/config/SshConfigFileReaderTest.java
index 5a9aa61..41b4296 100644
--- a/sshd-core/src/test/java/org/apache/sshd/common/config/SshConfigFileReaderTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/common/config/SshConfigFileReaderTest.java
@@ -32,7 +32,6 @@ import org.apache.sshd.common.Closeable;
 import org.apache.sshd.common.FactoryManager;
 import org.apache.sshd.common.NamedFactory;
 import org.apache.sshd.common.NamedResource;
-import org.apache.sshd.common.Transformer;
 import org.apache.sshd.common.cipher.BuiltinCiphers;
 import org.apache.sshd.common.cipher.Cipher;
 import org.apache.sshd.common.compression.BuiltinCompressions;
@@ -44,6 +43,7 @@ import org.apache.sshd.common.mac.Mac;
 import org.apache.sshd.common.signature.BuiltinSignatures;
 import org.apache.sshd.common.signature.Signature;
 import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.Transformer;
 import org.apache.sshd.util.BaseTestSupport;
 import org.junit.FixMethodOrder;
 import org.junit.Test;

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/test/java/org/apache/sshd/common/config/keys/KeyUtilsTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/common/config/keys/KeyUtilsTest.java b/sshd-core/src/test/java/org/apache/sshd/common/config/keys/KeyUtilsTest.java
new file mode 100644
index 0000000..680eec8
--- /dev/null
+++ b/sshd-core/src/test/java/org/apache/sshd/common/config/keys/KeyUtilsTest.java
@@ -0,0 +1,138 @@
+/*
+ * 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.config.keys;
+
+import java.security.GeneralSecurityException;
+import java.security.KeyPair;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+import org.apache.sshd.common.cipher.ECCurves;
+import org.apache.sshd.common.keyprovider.KeyPairProvider;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.SecurityUtils;
+import org.apache.sshd.util.BaseTestSupport;
+import org.junit.Assume;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class KeyUtilsTest extends BaseTestSupport {
+    private static int[] DSS_SIZES = { 512, 768, 1024 };
+    private static int[] RSA_SIZES = { 1024, 2048, 3072, 4096 };
+
+    public KeyUtilsTest() {
+        super();
+    }
+
+    @Test
+    public void testGenerateRSAKeyPairs() throws GeneralSecurityException {
+        GeneralSecurityException err = null;
+        for (int keySize : RSA_SIZES) {
+            try {
+                KeyPair kp = generateKeyPair(KeyPairProvider.SSH_RSA, keySize);
+                testKeyPairCloning(KeyPairProvider.SSH_RSA, keySize, kp);
+            } catch(GeneralSecurityException e) {
+                err = GenericUtils.accumulateException(err, e);
+            }
+        }
+        
+        if (err != null) {
+            throw err;
+        }
+    }
+
+    @Test
+    public void testGenerateDSSKeyPairs() throws GeneralSecurityException {
+        GeneralSecurityException err = null;
+        for (int keySize : DSS_SIZES) {
+            try {
+                KeyPair kp = generateKeyPair(KeyPairProvider.SSH_DSS, keySize);
+                testKeyPairCloning(KeyPairProvider.SSH_DSS, keySize, kp);
+            } catch(GeneralSecurityException e) {
+                err = GenericUtils.accumulateException(err, e);
+            }
+        }
+        
+        if (err != null) {
+            throw err;
+        }
+    }
+
+    @Test
+    public void testGenerateECDSAKeyPairs() throws GeneralSecurityException {
+        Assume.assumeTrue("No ECC support", SecurityUtils.hasEcc());
+
+        GeneralSecurityException err = null;
+        for (String curveName : ECCurves.NAMES) {
+            Integer keySize = ECCurves.getCurveSize(curveName);
+            try {
+                String keyType = ECCurves.ECDSA_SHA2_PREFIX + curveName;
+                KeyPair kp = generateKeyPair(keyType, keySize.intValue());
+                testKeyPairCloning(keyType, keySize.intValue(), kp);
+            } catch(GeneralSecurityException e) {
+                err = GenericUtils.accumulateException(err, e);
+            }
+        }
+        
+        if (err != null) {
+            throw err;
+        }
+    }
+
+    private static KeyPair generateKeyPair(String keyType, int keySize) throws GeneralSecurityException {
+        try {
+            System.out.println("generateKeyPair(" + keyType + ")[" + keySize + "]");
+            return KeyUtils.generateKeyPair(keyType, keySize);
+        } catch(GeneralSecurityException e) {
+            System.err.println("Failed (" + e.getClass().getSimpleName() + ") to generate key-pair for " + keyType + "/" + keySize + ": " + e.getMessage());
+            throw e;
+        }
+    }
+    
+    private static void testKeyPairCloning(String keyType, int keySize, KeyPair kp) throws GeneralSecurityException {
+        String prefix = keyType + "[" + keySize + "]";
+        System.out.println("testKeyPairCloning(" + prefix + ")");
+
+        KeyPair cloned = KeyUtils.cloneKeyPair(keyType, kp);
+        assertNotSame(prefix + ": Key pair not cloned", kp, cloned);
+        assertTrue(prefix + ": Cloned pair not equals", KeyUtils.compareKeyPairs(kp, cloned));
+        
+        {
+            PublicKey k1 = kp.getPublic(), k2 = cloned.getPublic();
+            assertNotSame(prefix + ": Public key not cloned", k1, k2);
+            assertTrue(prefix + ": Cloned public key not equals", KeyUtils.compareKeys(k1, k2));
+            
+            String f1 = KeyUtils.getFingerPrint(k1), f2 = KeyUtils.getFingerPrint(k2);
+            assertEquals(prefix + ": Mismatched fingerprints", f1, f2);
+        }
+        
+        {
+            PrivateKey k1 = kp.getPrivate(), k2 = cloned.getPrivate();
+            assertNotSame(prefix + ": Private key not cloned", k1, k2);
+            assertTrue(prefix + ": Cloned private key not equals", KeyUtils.compareKeys(k1, k2));
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/test/java/org/apache/sshd/common/mac/MacTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/common/mac/MacTest.java b/sshd-core/src/test/java/org/apache/sshd/common/mac/MacTest.java
new file mode 100644
index 0000000..ea9c555
--- /dev/null
+++ b/sshd-core/src/test/java/org/apache/sshd/common/mac/MacTest.java
@@ -0,0 +1,188 @@
+/*
+ * 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.mac;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Arrays;
+
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.cipher.BuiltinCiphers;
+import org.apache.sshd.common.cipher.Cipher;
+import org.apache.sshd.common.mac.BuiltinMacs;
+import org.apache.sshd.common.mac.Mac;
+import org.apache.sshd.common.random.BouncyCastleRandom;
+import org.apache.sshd.common.random.Random;
+import org.apache.sshd.server.SshServer;
+import org.apache.sshd.util.BaseTestSupport;
+import org.apache.sshd.util.BogusPasswordAuthenticator;
+import org.apache.sshd.util.EchoShellFactory;
+import org.apache.sshd.util.JSchLogger;
+import org.apache.sshd.util.SimpleUserInfo;
+import org.apache.sshd.util.Utils;
+import org.junit.After;
+import org.junit.FixMethodOrder;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+
+import com.jcraft.jsch.JSch;
+
+/**
+ * Test Cipher algorithms.
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class MacTest extends BaseTestSupport {
+
+    private SshServer sshd;
+    private int port;
+
+    @Test
+    public void testHMACMD5() throws Exception {
+        setUp(BuiltinMacs.hmacmd5);
+        runTest();
+    }
+
+    @Test
+    public void testHMACMD596() throws Exception {
+        setUp(BuiltinMacs.hmacmd596);
+        runTest();
+    }
+
+    @Test
+    public void testHMACSHA1() throws Exception {
+        setUp(BuiltinMacs.hmacsha1);
+        runTest();
+    }
+
+    @Test
+    public void testHMACSHA196() throws Exception {
+        setUp(BuiltinMacs.hmacsha196);
+        runTest();
+    }
+
+    @Test
+    public void testHMACSHA256() throws Exception {
+        setUp(BuiltinMacs.hmacsha256);
+        runTest();
+    }
+
+    @Test
+    @Ignore("Lead to ArrayIndexOutOfBoundsException in JSch")
+    public void testHMACSHA512() throws Exception {
+        setUp(BuiltinMacs.hmacsha512);
+        runTest();
+    }
+
+    @Test
+    public void loadTest() throws Exception {
+        Random random = new BouncyCastleRandom();
+        loadTest(BuiltinCiphers.aes128cbc, random);
+        loadTest(BuiltinCiphers.blowfishcbc, random);
+        loadTest(BuiltinCiphers.tripledescbc, random);
+    }
+
+    protected void loadTest(NamedFactory<Cipher> factory, Random random) throws Exception {
+        Cipher cipher = factory.create();
+        byte[] key = new byte[cipher.getBlockSize()];
+        byte[] iv = new byte[cipher.getIVSize()];
+        random.fill(key, 0, key.length);
+        random.fill(iv, 0, iv.length);
+        cipher.init(Cipher.Mode.Encrypt, key, iv);
+
+        byte[] input = new byte[cipher.getBlockSize()];
+        random.fill(input, 0, input.length);
+        long t0 = System.currentTimeMillis();
+        for (int i = 0; i < 100000; i++) {
+            cipher.update(input, 0, input.length);
+        }
+        long t1 = System.currentTimeMillis();
+        System.err.println(factory.getName() + ": " + (t1 - t0) + " ms");
+    }
+
+
+    protected void setUp(NamedFactory<Mac> mac) throws Exception {
+        sshd = SshServer.setUpDefaultServer();
+        sshd.setKeyPairProvider(Utils.createTestHostKeyProvider());
+        sshd.setMacFactories(Arrays.<NamedFactory<Mac>>asList(mac));
+        sshd.setShellFactory(new EchoShellFactory());
+        sshd.setPasswordAuthenticator(BogusPasswordAuthenticator.INSTANCE);
+        sshd.start();
+        port  = sshd.getPort();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        if (sshd != null) {
+            sshd.stop(true);
+        }
+    }
+
+    protected void runTest() throws Exception {
+        JSchLogger.init();
+        JSch sch = new JSch();
+        JSch.setConfig("cipher.s2c", "aes128-cbc,3des-cbc,blowfish-cbc,aes192-cbc,aes256-cbc,none");
+        JSch.setConfig("cipher.c2s", "aes128-cbc,3des-cbc,blowfish-cbc,aes192-cbc,aes256-cbc,none");
+        JSch.setConfig("mac.s2c", "hmac-md5,hmac-sha1,hmac-sha2-256,hmac-sha1-96,hmac-md5-96,hmac-sha2-512");
+        JSch.setConfig("mac.c2s", "hmac-md5,hmac-sha1,hmac-sha2-256,hmac-sha1-96,hmac-md5-96,hmac-sha2-512");
+        JSch.setConfig("hmac-sha2-512",  "com.jcraft.jsch.jce.HMACSHA512");
+        com.jcraft.jsch.Session s = sch.getSession(getCurrentTestName(), "localhost", port);
+        try {
+            s.setUserInfo(new SimpleUserInfo(getCurrentTestName()));
+            s.connect();
+            com.jcraft.jsch.Channel c = s.openChannel("shell");
+            c.connect();
+
+            try(OutputStream os = c.getOutputStream();
+                InputStream is = c.getInputStream()) {
+
+                String  expected = "this is my command\n";
+                byte[] bytes = expected.getBytes();
+                byte[] data = new byte[bytes.length + Long.SIZE];
+                for (int i = 0; i < 10; i++) {
+                    os.write(bytes);
+                    os.flush();
+                    int len = is.read(data);
+                    String str = new String(data, 0, len);
+                    assertEquals("Mismatched data at iteration " + i, expected, str);
+                }
+            } finally {
+                c.disconnect();
+            }
+        } finally {
+            s.disconnect();
+        }
+    }
+
+    static boolean checkCipher(String cipher){
+        try{
+            Class<?> c=Class.forName(cipher);
+            com.jcraft.jsch.Cipher _c = (com.jcraft.jsch.Cipher)(c.newInstance());
+            _c.init(com.jcraft.jsch.Cipher.ENCRYPT_MODE,
+                    new byte[_c.getBlockSize()],
+                    new byte[_c.getIVSize()]);
+            return true;
+        }
+        catch(Exception e){
+            return false;
+        }
+    }
+}