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 2018/09/06 16:03:40 UTC

[30/51] [abbrv] mina-sshd git commit: [SSHD-842] Split common utilities code from sshd-core into sshd-common (new artifact)

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/util/io/IoUtilsTest.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/io/IoUtilsTest.java b/sshd-common/src/test/java/org/apache/sshd/common/util/io/IoUtilsTest.java
new file mode 100644
index 0000000..a94811d
--- /dev/null
+++ b/sshd-common/src/test/java/org/apache/sshd/common/util/io/IoUtilsTest.java
@@ -0,0 +1,61 @@
+/*
+ * 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.util.io;
+
+import java.nio.file.LinkOption;
+
+import org.apache.sshd.common.util.NumberUtils;
+import org.apache.sshd.util.test.JUnitTestSupport;
+import org.apache.sshd.util.test.NoIoTestCase;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runners.MethodSorters;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Category({ NoIoTestCase.class })
+public class IoUtilsTest extends JUnitTestSupport {
+    public IoUtilsTest() {
+        super();
+    }
+
+    @Test
+    public void testFollowLinks() {
+        assertTrue("Null ?", IoUtils.followLinks((LinkOption[]) null));
+        assertTrue("Empty ?", IoUtils.followLinks(IoUtils.EMPTY_LINK_OPTIONS));
+        assertFalse("No-follow ?", IoUtils.followLinks(IoUtils.getLinkOptions(false)));
+    }
+
+    @Test
+    public void testGetEOLBytes() {
+        byte[] expected = IoUtils.getEOLBytes();
+        assertTrue("Empty bytes", NumberUtils.length(expected) > 0);
+
+        for (int index = 1; index < Byte.SIZE; index++) {
+            byte[] actual = IoUtils.getEOLBytes();
+            assertNotSame("Same bytes received at iteration " + index, expected, actual);
+            assertArrayEquals("Mismatched bytes at iteration " + index, expected, actual);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/util/io/LimitInputStreamTest.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/io/LimitInputStreamTest.java b/sshd-common/src/test/java/org/apache/sshd/common/util/io/LimitInputStreamTest.java
new file mode 100644
index 0000000..e009527
--- /dev/null
+++ b/sshd-common/src/test/java/org/apache/sshd/common/util/io/LimitInputStreamTest.java
@@ -0,0 +1,118 @@
+/*
+ * 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.util.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import org.apache.sshd.util.test.JUnitTestSupport;
+import org.apache.sshd.util.test.NoIoTestCase;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runners.MethodSorters;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Category({ NoIoTestCase.class })
+public class LimitInputStreamTest extends JUnitTestSupport {
+    public LimitInputStreamTest() {
+        super();
+    }
+
+    @Test
+    public void testReadLimit() throws IOException {
+        Path targetPath = detectTargetFolder();
+        Path rootFolder = assertHierarchyTargetFolderExists(targetPath.resolve(getClass().getSimpleName()));
+        Path inputFile = rootFolder.resolve(getCurrentTestName() + ".bin");
+        byte[] data = (getClass().getName() + "#" + getCurrentTestName()).getBytes(StandardCharsets.UTF_8);
+        Files.write(inputFile, data);
+
+        try (InputStream in = Files.newInputStream(inputFile)) {
+            int maxLen = data.length / 2;
+            byte[] expected = new byte[maxLen];
+            System.arraycopy(data, 0, expected, 0, expected.length);
+
+            byte[] actual = new byte[expected.length];
+            try (LimitInputStream limited = new LimitInputStream(in, expected.length)) {
+                assertTrue("Limited stream not marked as open", limited.isOpen());
+                assertEquals("Mismatched initial available data size", expected.length, limited.available());
+
+                int readLen = limited.read(actual);
+                assertEquals("Incomplete actual data read", actual.length, readLen);
+                assertArrayEquals("Mismatched read data", expected, actual);
+                assertEquals("Mismatched remaining available data size", 0, limited.available());
+
+                readLen = limited.read();
+                assertTrue("Unexpected success to read one more byte: " + readLen, readLen < 0);
+
+                readLen = limited.read(actual);
+                assertTrue("Unexpected success to read extra buffer: " + readLen, readLen < 0);
+
+                limited.close();
+                assertFalse("Limited stream still marked as open", limited.isOpen());
+
+                try {
+                    readLen = limited.read();
+                    fail("Unexpected one byte read success after close");
+                } catch (IOException e) {
+                    // expected
+                }
+
+                try {
+                    readLen = limited.read(actual);
+                    fail("Unexpected buffer read success after close: " + readLen);
+                } catch (IOException e) {
+                    // expected
+                }
+
+                try {
+                    readLen = limited.read(actual);
+                    fail("Unexpected buffer read success after close: " + readLen);
+                } catch (IOException e) {
+                    // expected
+                }
+
+                try {
+                    readLen = (int) limited.skip(Byte.SIZE);
+                    fail("Unexpected skip success after close: " + readLen);
+                } catch (IOException e) {
+                    // expected
+                }
+
+                try {
+                    readLen = limited.available();
+                    fail("Unexpected available success after close: " + readLen);
+                } catch (IOException e) {
+                    // expected
+                }
+            }
+
+            // make sure underlying stream not closed
+            int readLen = in.read(actual);
+            assertEquals("Incomplete extra data read", Math.min(actual.length, data.length - expected.length), readLen);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/util/io/ModifiableFileWatcherTest.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/io/ModifiableFileWatcherTest.java b/sshd-common/src/test/java/org/apache/sshd/common/util/io/ModifiableFileWatcherTest.java
new file mode 100644
index 0000000..05343af
--- /dev/null
+++ b/sshd-common/src/test/java/org/apache/sshd/common/util/io/ModifiableFileWatcherTest.java
@@ -0,0 +1,82 @@
+/*
+ * 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.util.io;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.attribute.PosixFilePermission;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Map;
+
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.OsUtils;
+import org.apache.sshd.util.test.JUnitTestSupport;
+import org.apache.sshd.util.test.NoIoTestCase;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runners.MethodSorters;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Category({ NoIoTestCase.class })
+public class ModifiableFileWatcherTest extends JUnitTestSupport {
+    public ModifiableFileWatcherTest() {
+        super();
+    }
+
+    @Test   // see SSHD-606
+    public void testValidateStrictConfigFilePermissions() throws IOException {
+        Path file = getTempTargetRelativeFile(getClass().getSimpleName(), getCurrentTestName());
+        outputDebugMessage("%s deletion result=%s", file, Files.deleteIfExists(file));
+        assertNull("Unexpected violation for non-existent file: " + file, ModifiableFileWatcher.validateStrictConfigFilePermissions(file));
+
+        assertHierarchyTargetFolderExists(file.getParent());
+        try (OutputStream output = Files.newOutputStream(file)) {
+            output.write((getClass().getName() + "#" + getCurrentTestName() + "@" + new Date(System.currentTimeMillis())).getBytes(StandardCharsets.UTF_8));
+        }
+
+        Collection<PosixFilePermission> perms = IoUtils.getPermissions(file);
+        if (GenericUtils.isEmpty(perms)) {
+            assertNull("Unexpected violation for no permissions file: " + file, ModifiableFileWatcher.validateStrictConfigFilePermissions(file));
+        } else if (OsUtils.isUNIX()) {
+            Map.Entry<String, Object> violation = null;
+            for (PosixFilePermission p : ModifiableFileWatcher.STRICTLY_PROHIBITED_FILE_PERMISSION) {
+                if (perms.contains(p)) {
+                    violation = ModifiableFileWatcher.validateStrictConfigFilePermissions(file);
+                    assertNotNull("Unexpected success for permission=" + p + " of file " + file + " permissions=" + perms, violation);
+                    break;
+                }
+            }
+
+            if (violation == null) {    // we do not expected a failure if no permissions have been violated
+                assertNull("Unexpected UNIX violation for file " + file + " permissions=" + perms, ModifiableFileWatcher.validateStrictConfigFilePermissions(file));
+            }
+        } else {
+            assertNull("Unexpected Windows violation for file " + file + " permissions=" + perms, ModifiableFileWatcher.validateStrictConfigFilePermissions(file));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/util/io/NoCloseInputStreamTest.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/io/NoCloseInputStreamTest.java b/sshd-common/src/test/java/org/apache/sshd/common/util/io/NoCloseInputStreamTest.java
new file mode 100644
index 0000000..564dc42
--- /dev/null
+++ b/sshd-common/src/test/java/org/apache/sshd/common/util/io/NoCloseInputStreamTest.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sshd.common.util.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Date;
+
+import org.apache.sshd.util.test.JUnitTestSupport;
+import org.apache.sshd.util.test.NoIoTestCase;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runners.MethodSorters;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Category({ NoIoTestCase.class })
+public class NoCloseInputStreamTest extends JUnitTestSupport {
+    public NoCloseInputStreamTest() {
+        super();
+    }
+
+    @Test
+    public void testCanKeepReadingAfterClose() throws IOException {
+        byte[] expected = (getClass().getName() + "#" + getCurrentTestName() + "@" + new Date()).getBytes(StandardCharsets.UTF_8);
+        Path dir = createTempClassFolder();
+        Path file = Files.write(dir.resolve(getCurrentTestName() + ".txt"), expected);
+        try (InputStream fileStream = Files.newInputStream(file);
+             InputStream shielded = new NoCloseInputStream(fileStream)) {
+            int index = 0;
+
+            for (; index < (expected.length / 2); index++) {
+                shielded.close();
+
+                int readValue = shielded.read();
+                if (readValue == -1) {
+                    fail("Premature EOF after shield read of " + index + " bytes");
+                }
+
+                byte expValue = expected[index];
+                byte actValue = (byte) (readValue & 0xFF);
+                if (expValue != actValue) {
+                    fail("Mismatched shielded read value after " + index + " bytes");
+                }
+            }
+
+            for (; index < expected.length; index++) {
+                int readValue = fileStream.read();
+                if (readValue == -1) {
+                    fail("Premature EOF after original read of " + index + " bytes");
+                }
+                byte expValue = expected[index];
+                byte actValue = (byte) (readValue & 0xFF);
+                if (expValue != actValue) {
+                    fail("Mismatched original read value after " + index + " bytes");
+                }
+            }
+
+            int readValue = shielded.read();
+            assertEquals("Shielded EOF not signalled", -1, readValue);
+
+            readValue = fileStream.read();
+            assertEquals("Original EOF not signalled", -1, readValue);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/util/io/NoCloseOutputStreamTest.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/io/NoCloseOutputStreamTest.java b/sshd-common/src/test/java/org/apache/sshd/common/util/io/NoCloseOutputStreamTest.java
new file mode 100644
index 0000000..f01f132
--- /dev/null
+++ b/sshd-common/src/test/java/org/apache/sshd/common/util/io/NoCloseOutputStreamTest.java
@@ -0,0 +1,69 @@
+/*
+ * 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.util.io;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Date;
+
+import org.apache.sshd.util.test.JUnitTestSupport;
+import org.apache.sshd.util.test.NoIoTestCase;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runners.MethodSorters;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Category({ NoIoTestCase.class })
+public class NoCloseOutputStreamTest extends JUnitTestSupport {
+    public NoCloseOutputStreamTest() {
+        super();
+    }
+
+    @Test
+    public void testCanKeepWritingAfterClose() throws IOException {
+        Path dir = createTempClassFolder();
+        Path file = dir.resolve(getCurrentTestName() + ".txt");
+        Files.deleteIfExists(file);
+
+        String expectedOutput = getClass().getName() + "#" + getCurrentTestName() + "@" + new Date();
+        byte[] expected = expectedOutput.getBytes(StandardCharsets.UTF_8);
+        try (OutputStream fileStream = Files.newOutputStream(file);
+             OutputStream shielded = new NoCloseOutputStream(fileStream)) {
+            int index = 0;
+            for (; index < (expected.length / 2); index++) {
+                shielded.close();
+                shielded.write(expected[index] & 0xFF);
+            }
+
+            fileStream.write(expected, index, expected.length - index);
+        }
+
+        byte[] actual = Files.readAllBytes(file);
+        String actualOutput = new String(actual, StandardCharsets.UTF_8);
+        assertEquals(expectedOutput, actualOutput);
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/util/io/NoCloseReaderTest.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/io/NoCloseReaderTest.java b/sshd-common/src/test/java/org/apache/sshd/common/util/io/NoCloseReaderTest.java
new file mode 100644
index 0000000..14a72fc
--- /dev/null
+++ b/sshd-common/src/test/java/org/apache/sshd/common/util/io/NoCloseReaderTest.java
@@ -0,0 +1,95 @@
+/*
+ * 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.util.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Date;
+
+import org.apache.sshd.util.test.JUnitTestSupport;
+import org.apache.sshd.util.test.NoIoTestCase;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runners.MethodSorters;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Category({ NoIoTestCase.class })
+public class NoCloseReaderTest extends JUnitTestSupport {
+    public NoCloseReaderTest() {
+        super();
+    }
+
+    @Test
+    public void testCanKeepReadingAfterClose() throws IOException {
+        String expected = getClass().getName() + "#" + getCurrentTestName() + "@" + new Date();
+        Path dir = createTempClassFolder();
+        Path file = Files.write(dir.resolve(getCurrentTestName() + ".txt"), expected.getBytes(StandardCharsets.UTF_8));
+        try (InputStream fileStream = Files.newInputStream(file);
+             Reader rdr = new InputStreamReader(fileStream, StandardCharsets.UTF_8);
+             Reader shielded = new NoCloseReader(rdr)) {
+            int index = 0;
+
+            int availLen = expected.length();
+            for (; index < (availLen / 2); index++) {
+                shielded.close();
+
+                int readValue = shielded.read();
+                if (readValue == -1) {
+                    fail("Premature EOF after shield read of " + index + " bytes");
+                }
+
+                char expValue = expected.charAt(index);
+                char actValue = (char) (readValue & 0xFFFF);
+                if (expValue != actValue) {
+                    fail("Mismatched shielded read value after " + index + " bytes");
+                }
+            }
+
+            for (; index < availLen; index++) {
+                int readValue = rdr.read();
+                if (readValue == -1) {
+                    fail("Premature EOF after original read of " + index + " bytes");
+                }
+
+                char expValue = expected.charAt(index);
+                char actValue = (char) (readValue & 0xFFFF);
+                if (expValue != actValue) {
+                    fail("Mismatched original read value after " + index + " bytes");
+                }
+            }
+
+            int readValue = shielded.read();
+            assertEquals("Shielded EOF not signalled", -1, readValue);
+
+            readValue = rdr.read();
+            assertEquals("Original EOF not signalled", -1, readValue);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/util/io/NoCloseWriterTest.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/io/NoCloseWriterTest.java b/sshd-common/src/test/java/org/apache/sshd/common/util/io/NoCloseWriterTest.java
new file mode 100644
index 0000000..b49678e
--- /dev/null
+++ b/sshd-common/src/test/java/org/apache/sshd/common/util/io/NoCloseWriterTest.java
@@ -0,0 +1,73 @@
+/*
+ * 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.util.io;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Date;
+
+import org.apache.sshd.util.test.JUnitTestSupport;
+import org.apache.sshd.util.test.NoIoTestCase;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runners.MethodSorters;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Category({ NoIoTestCase.class })
+public class NoCloseWriterTest extends JUnitTestSupport {
+    public NoCloseWriterTest() {
+        super();
+    }
+
+    @Test
+    public void testCanKeepWritingAfterClose() throws IOException {
+        Path dir = createTempClassFolder();
+        Path file = dir.resolve(getCurrentTestName() + ".txt");
+        Files.deleteIfExists(file);
+
+        String expected = getClass().getName() + "#" + getCurrentTestName() + "@" + new Date();
+        try (OutputStream fileStream = Files.newOutputStream(file);
+             Writer w = new OutputStreamWriter(fileStream, StandardCharsets.UTF_8);
+                Writer shielded = new NoCloseWriter(w)) {
+            int index = 0;
+            int availLen = expected.length();
+            for (; index < (availLen / 2); index++) {
+                shielded.close();
+                shielded.write(expected.charAt(index));
+            }
+
+            w.write(expected, index, availLen - index);
+        }
+
+        byte[] actualBytes = Files.readAllBytes(file);
+        String actual = new String(actualBytes, StandardCharsets.UTF_8);
+        assertEquals(expected, actual);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/util/io/NullInputStreamTest.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/io/NullInputStreamTest.java b/sshd-common/src/test/java/org/apache/sshd/common/util/io/NullInputStreamTest.java
new file mode 100644
index 0000000..31982da
--- /dev/null
+++ b/sshd-common/src/test/java/org/apache/sshd/common/util/io/NullInputStreamTest.java
@@ -0,0 +1,118 @@
+/*
+ * 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.util.io;
+
+import java.io.EOFException;
+import java.io.IOException;
+
+import org.apache.sshd.util.test.JUnitTestSupport;
+import org.apache.sshd.util.test.NoIoTestCase;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runners.MethodSorters;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Category({ NoIoTestCase.class })
+public class NullInputStreamTest extends JUnitTestSupport {
+    private static final NullInputStream INSTANCE = new NullInputStream();
+
+    public NullInputStreamTest() {
+        super();
+    }
+
+    @Test
+    public void testReadOneChar() throws IOException {
+        assertEquals(-1, INSTANCE.read());
+    }
+
+    @Test
+    public void testReadFullBuffer() throws IOException {
+        assertEquals(-1, INSTANCE.read(new byte[Byte.SIZE]));
+    }
+
+    @Test
+    public void testReadPartialBuffer() throws IOException {
+        byte[] buf = new byte[Byte.SIZE];
+        assertEquals(-1, INSTANCE.read(buf, buf.length / 2, (buf.length / 2) - 1));
+    }
+
+    @Test
+    public void testSkip() throws IOException {
+        assertEquals(0L, INSTANCE.skip(Long.SIZE));
+    }
+
+    @Test
+    public void testAvailable() throws IOException {
+        assertEquals(0, INSTANCE.available());
+    }
+
+    @Test
+    public void testNotAllowedToAccessAfterClose() throws IOException {
+        NullInputStream stream = new NullInputStream();
+        stream.close();
+        assertFalse("Stream not marked as closed", stream.isOpen());
+
+        try {
+            int nRead = stream.read();
+            fail("Unexpected single byte read: " + nRead);
+        } catch (EOFException e) {
+            // expected
+        }
+
+        byte[] buf = new byte[Byte.SIZE];
+        try {
+            int nRead = stream.read(buf);
+            fail("Unexpected full buffer read: " + nRead);
+        } catch (EOFException e) {
+            // expected
+        }
+
+        try {
+            int nRead = stream.read(buf, buf.length / 2, (buf.length / 2) - 1);
+            fail("Unexpected partial buffer read: " + nRead);
+        } catch (EOFException e) {
+            // expected
+        }
+
+        try {
+            long skip = stream.skip(Long.SIZE);
+            fail("Unexpected skip result: " + skip);
+        } catch (EOFException e) {
+            // expected
+        }
+
+        try {
+            int nRead = stream.available();
+            fail("Unexpected available count: " + nRead);
+        } catch (IOException e) {
+            // expected
+        }
+        try {
+            stream.reset();
+            fail("Unexpected reset success");
+        } catch (EOFException e) {
+            // expected
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/util/io/NullOutputStreamTest.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/io/NullOutputStreamTest.java b/sshd-common/src/test/java/org/apache/sshd/common/util/io/NullOutputStreamTest.java
new file mode 100644
index 0000000..0fe845f
--- /dev/null
+++ b/sshd-common/src/test/java/org/apache/sshd/common/util/io/NullOutputStreamTest.java
@@ -0,0 +1,80 @@
+/*
+ * 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.util.io;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.util.Arrays;
+
+import org.apache.sshd.util.test.JUnitTestSupport;
+import org.apache.sshd.util.test.NoIoTestCase;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runners.MethodSorters;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Category({ NoIoTestCase.class })
+public class NullOutputStreamTest extends JUnitTestSupport {
+    public NullOutputStreamTest() {
+        super();
+    }
+
+    @Test
+    public void testNoAccessAllowedAfterClose() throws IOException {
+        NullOutputStream stream = new NullOutputStream();
+        stream.close();
+        assertFalse("Stream not marked as closed", stream.isOpen());
+
+        try {
+            stream.write('a');
+            fail("Unexpected single value write success");
+        } catch (EOFException e) {
+            // expected
+        }
+
+        byte[] buf = new byte[Byte.SIZE];
+        try {
+            Arrays.fill(buf, (byte) 0x41);
+            stream.write(buf);
+            fail("Unexpected full buffer write success");
+        } catch (EOFException e) {
+            // expected
+        }
+
+        try {
+            Arrays.fill(buf, (byte) 0x42);
+            stream.write(buf, buf.length / 2, (buf.length / 2) - 1);
+            fail("Unexpected partial buffer write success");
+        } catch (EOFException e) {
+            // expected
+        }
+
+        try {
+            stream.flush();
+            fail("Unexpected flush success");
+        } catch (EOFException e) {
+            // expected
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/util/io/der/ASN1ClassTest.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/io/der/ASN1ClassTest.java b/sshd-common/src/test/java/org/apache/sshd/common/util/io/der/ASN1ClassTest.java
new file mode 100644
index 0000000..5f30529
--- /dev/null
+++ b/sshd-common/src/test/java/org/apache/sshd/common/util/io/der/ASN1ClassTest.java
@@ -0,0 +1,67 @@
+/*
+ * 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.util.io.der;
+
+import java.util.List;
+
+import org.apache.sshd.util.test.JUnit4ClassRunnerWithParametersFactory;
+import org.apache.sshd.util.test.JUnitTestSupport;
+import org.apache.sshd.util.test.NoIoTestCase;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+import org.junit.runners.MethodSorters;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+import org.junit.runners.Parameterized.UseParametersRunnerFactory;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RunWith(Parameterized.class)   // see https://github.com/junit-team/junit/wiki/Parameterized-tests
+@UseParametersRunnerFactory(JUnit4ClassRunnerWithParametersFactory.class)
+@Category({ NoIoTestCase.class })
+public class ASN1ClassTest extends JUnitTestSupport {
+    private final ASN1Class expected;
+
+    public ASN1ClassTest(ASN1Class expected) {
+        this.expected = expected;
+    }
+
+    @Parameters(name = "{0}")
+    public static List<Object[]> parameters() {
+        return parameterize(ASN1Class.VALUES);
+    }
+
+    @Test
+    public void testFromName() {
+        String name = expected.name();
+        for (int index = 1, count = name.length(); index <= count; index++) {
+            assertSame(name, expected, ASN1Class.fromName(name));
+            name = shuffleCase(name);
+        }
+    }
+
+    @Test // NOTE: this also tests "fromTypeValue" since "fromDERValue" invokes it
+    public void testFromDERValue() {
+        assertSame(expected, ASN1Class.fromDERValue((expected.getClassValue() << 6) & 0xFF));
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/util/io/der/ASN1TypeTest.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/io/der/ASN1TypeTest.java b/sshd-common/src/test/java/org/apache/sshd/common/util/io/der/ASN1TypeTest.java
new file mode 100644
index 0000000..06034e2
--- /dev/null
+++ b/sshd-common/src/test/java/org/apache/sshd/common/util/io/der/ASN1TypeTest.java
@@ -0,0 +1,67 @@
+/*
+ * 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.util.io.der;
+
+import java.util.List;
+
+import org.apache.sshd.util.test.JUnit4ClassRunnerWithParametersFactory;
+import org.apache.sshd.util.test.JUnitTestSupport;
+import org.apache.sshd.util.test.NoIoTestCase;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+import org.junit.runners.MethodSorters;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+import org.junit.runners.Parameterized.UseParametersRunnerFactory;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RunWith(Parameterized.class)   // see https://github.com/junit-team/junit/wiki/Parameterized-tests
+@UseParametersRunnerFactory(JUnit4ClassRunnerWithParametersFactory.class)
+@Category({ NoIoTestCase.class })
+public class ASN1TypeTest extends JUnitTestSupport {
+    private final ASN1Type expected;
+
+    public ASN1TypeTest(ASN1Type expected) {
+        this.expected = expected;
+    }
+
+    @Parameters(name = "{0}")
+    public static List<Object[]> parameters() {
+        return parameterize(ASN1Type.VALUES);
+    }
+
+    @Test
+    public void testFromName() {
+        String name = expected.name();
+        for (int index = 1, count = name.length(); index <= count; index++) {
+            assertSame(name, expected, ASN1Type.fromName(name));
+            name = shuffleCase(name);
+        }
+    }
+
+    @Test
+    public void testFromTypeValue() {
+        assertSame(expected, ASN1Type.fromTypeValue(expected.getTypeValue()));
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/util/io/der/DERParserTest.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/io/der/DERParserTest.java b/sshd-common/src/test/java/org/apache/sshd/common/util/io/der/DERParserTest.java
new file mode 100644
index 0000000..ecc5b31
--- /dev/null
+++ b/sshd-common/src/test/java/org/apache/sshd/common/util/io/der/DERParserTest.java
@@ -0,0 +1,61 @@
+/*
+ * 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.util.io.der;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.StreamCorruptedException;
+
+import org.apache.sshd.util.test.JUnitTestSupport;
+import org.apache.sshd.util.test.NoIoTestCase;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runners.MethodSorters;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Category({ NoIoTestCase.class })
+public class DERParserTest extends JUnitTestSupport {
+    public DERParserTest() {
+        super();
+    }
+
+    @Test
+    public void testReadLengthConstraint() throws IOException {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        try {
+            try (DERWriter w = new DERWriter(baos)) {
+                w.writeLength(DERParser.MAX_DER_VALUE_LENGTH + 1);
+            }
+        } finally {
+            baos.close();
+        }
+
+        try (DERParser parser = new DERParser(baos.toByteArray())) {
+            int len = parser.readLength();
+            fail("Unexpected success: len=" + len);
+        } catch (StreamCorruptedException e) {
+            // expected ignored
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/util/io/der/DERWriterTest.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/io/der/DERWriterTest.java b/sshd-common/src/test/java/org/apache/sshd/common/util/io/der/DERWriterTest.java
new file mode 100644
index 0000000..3064caa
--- /dev/null
+++ b/sshd-common/src/test/java/org/apache/sshd/common/util/io/der/DERWriterTest.java
@@ -0,0 +1,64 @@
+/*
+ * 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.util.io.der;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+
+import org.apache.sshd.util.test.JUnitTestSupport;
+import org.apache.sshd.util.test.NoIoTestCase;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runners.MethodSorters;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Category({ NoIoTestCase.class })
+public class DERWriterTest extends JUnitTestSupport {
+    public DERWriterTest() {
+        super();
+    }
+
+    @Test
+    public void testWriteStripLeadingZeroes() throws IOException {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        try {
+            try (DERWriter w = new DERWriter(baos)) {
+                w.writeBigInteger(BigInteger.valueOf(-1));
+                w.writeBigInteger(BigInteger.valueOf(129));
+                w.writeBigInteger(new byte[] {0, 0}, 0, 2);
+                w.writeBigInteger(new byte[] {0, 1}, 0, 2);
+            }
+        } finally {
+            baos.close();
+        }
+
+        try (DERParser parser = new DERParser(baos.toByteArray())) {
+            assertEquals(BigInteger.valueOf(255), parser.readBigInteger());
+            assertEquals(BigInteger.valueOf(129), parser.readBigInteger());
+            assertEquals(BigInteger.valueOf(0), parser.readBigInteger());
+            assertEquals(BigInteger.valueOf(1), parser.readBigInteger());
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/util/net/SshdSocketIpv6AddressTest.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/net/SshdSocketIpv6AddressTest.java b/sshd-common/src/test/java/org/apache/sshd/common/util/net/SshdSocketIpv6AddressTest.java
new file mode 100644
index 0000000..a38db34
--- /dev/null
+++ b/sshd-common/src/test/java/org/apache/sshd/common/util/net/SshdSocketIpv6AddressTest.java
@@ -0,0 +1,88 @@
+/*
+ * 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.util.net;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.apache.sshd.util.test.JUnit4ClassRunnerWithParametersFactory;
+import org.apache.sshd.util.test.JUnitTestSupport;
+import org.apache.sshd.util.test.NoIoTestCase;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+import org.junit.runners.MethodSorters;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+import org.junit.runners.Parameterized.UseParametersRunnerFactory;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@RunWith(Parameterized.class)   // see https://github.com/junit-team/junit/wiki/Parameterized-tests
+@UseParametersRunnerFactory(JUnit4ClassRunnerWithParametersFactory.class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Category({ NoIoTestCase.class })
+public class SshdSocketIpv6AddressTest extends JUnitTestSupport {
+    public static final List<String> VALID_ADDRESSES =
+        Collections.unmodifiableList(
+            Arrays.asList(
+                "2001:0db8:85a3:0000:0000:8a2e:0370:7334", "2001:db8:85a3:0:0:8a2e:370:7334",
+                "2001:db8:85a3::8a2e:370:7334",
+                "2001:0db8::0001", "2001:db8::1",
+                "2001:db8:0:0:0:0:2:1", "2001:db8::2:1",
+                "2001:db8:0000:1:1:1:1:1", "2001:db8:0:1:1:1:1:1",
+                "2001:db8:85a3:8d3:1319:8a2e:370:7348",
+                "fe80::1ff:fe23:4567:890a", "fe80::1ff:fe23:4567:890a%eth2",
+                "fe80::1ff:fe23:4567:890a%3", "fe80:3::1ff:fe23:4567:890a",
+                "::ffff:c000:0280", "::ffff:192.0.2.128"));
+
+    private final String address;
+    private final boolean matches;
+
+    public SshdSocketIpv6AddressTest(String address, boolean matches) {
+        this.address = address;
+        this.matches = matches;
+    }
+
+    @Parameters(name = "{0}")
+    public static List<Object[]> parameters() {
+        return Stream
+                .concat(SshdSocketAddress.WELL_KNOWN_IPV6_ADDRESSES.stream(), VALID_ADDRESSES.stream())
+                .map(address -> new Object[] {address, Boolean.TRUE})
+                .collect(Collectors.toList());
+    }
+
+    @Test
+    public void testIPv6AddressValidity() {
+        assertEquals(address, matches, SshdSocketAddress.isIPv6Address(address));
+    }
+
+    @Override
+    public String toString() {
+        return getClass().getSimpleName()
+            + "[address=" + address
+            + " , matches=" + matches
+            + "]";
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/util/security/SecurityProviderRegistrarCipherNameTest.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/security/SecurityProviderRegistrarCipherNameTest.java b/sshd-common/src/test/java/org/apache/sshd/common/util/security/SecurityProviderRegistrarCipherNameTest.java
new file mode 100644
index 0000000..5d40c59
--- /dev/null
+++ b/sshd-common/src/test/java/org/apache/sshd/common/util/security/SecurityProviderRegistrarCipherNameTest.java
@@ -0,0 +1,75 @@
+/*
+ * 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.util.security;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.crypto.Cipher;
+
+import org.apache.sshd.common.cipher.BuiltinCiphers;
+import org.apache.sshd.common.cipher.CipherInformation;
+import org.apache.sshd.util.test.JUnit4ClassRunnerWithParametersFactory;
+import org.apache.sshd.util.test.JUnitTestSupport;
+import org.apache.sshd.util.test.NoIoTestCase;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+import org.junit.runners.MethodSorters;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+import org.junit.runners.Parameterized.UseParametersRunnerFactory;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RunWith(Parameterized.class)   // see https://github.com/junit-team/junit/wiki/Parameterized-tests
+@UseParametersRunnerFactory(JUnit4ClassRunnerWithParametersFactory.class)
+@Category({ NoIoTestCase.class })
+public class SecurityProviderRegistrarCipherNameTest extends JUnitTestSupport {
+    private final CipherInformation cipherInfo;
+
+    public SecurityProviderRegistrarCipherNameTest(CipherInformation cipherInfo) {
+        this.cipherInfo = cipherInfo;
+    }
+
+    @Parameters(name = "{0}")
+    public static List<Object[]> parameters() {
+        List<Object[]> params = new ArrayList<>();
+        for (CipherInformation cipherInfo : BuiltinCiphers.VALUES) {
+            String algorithm = cipherInfo.getAlgorithm();
+            String xform = cipherInfo.getTransformation();
+            if (!xform.startsWith(algorithm)) {
+                continue;
+            }
+
+            params.add(new Object[]{cipherInfo});
+        }
+        return params;
+    }
+
+    @Test
+    public void testGetEffectiveSecurityEntityName() {
+        String expected = cipherInfo.getAlgorithm();
+        String actual = SecurityProviderRegistrar.getEffectiveSecurityEntityName(Cipher.class, cipherInfo.getTransformation());
+        assertEquals("Mismatched pure cipher name", expected, actual);
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/util/security/SecurityProviderRegistrarTestSupport.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/security/SecurityProviderRegistrarTestSupport.java b/sshd-common/src/test/java/org/apache/sshd/common/util/security/SecurityProviderRegistrarTestSupport.java
new file mode 100644
index 0000000..9958916
--- /dev/null
+++ b/sshd-common/src/test/java/org/apache/sshd/common/util/security/SecurityProviderRegistrarTestSupport.java
@@ -0,0 +1,62 @@
+/*
+ * 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.util.security;
+
+import java.security.Provider;
+import java.util.Arrays;
+import java.util.Collection;
+
+import org.apache.sshd.util.test.JUnitTestSupport;
+import org.apache.sshd.util.test.NoIoTestCase;
+import org.junit.experimental.categories.Category;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@Category({ NoIoTestCase.class })
+public abstract class SecurityProviderRegistrarTestSupport extends JUnitTestSupport {
+    protected SecurityProviderRegistrarTestSupport() {
+        super();
+    }
+
+    public static Provider testGetSecurityProviderCaching(String prefix, SecurityProviderRegistrar registrar) {
+        return testGetSecurityProviderCaching(prefix, registrar, registrar.getSecurityProvider());
+    }
+
+    public static <P extends Provider> P testGetSecurityProviderCaching(String prefix, SecurityProviderRegistrar registrar, P expected) {
+        for (int index = 1; index <= Byte.SIZE; index++) {
+            Provider actual = registrar.getSecurityProvider();
+            assertSame(prefix + ": Mismatched provider instance at invocation #" + index, expected, actual);
+        }
+
+        return expected;
+    }
+
+    public static void assertSecurityEntitySupportState(
+            String prefix, SecurityProviderRegistrar registrar, boolean expected, String name, Class<?>... entities) {
+        assertSecurityEntitySupportState(prefix, registrar, expected, name, Arrays.asList(entities));
+    }
+
+    public static void assertSecurityEntitySupportState(
+            String prefix, SecurityProviderRegistrar registrar, boolean expected, String name, Collection<Class<?>> entities) {
+        for (Class<?> entity : entities) {
+            assertEquals(prefix + "[" + entity.getSimpleName() + "]", expected, registrar.isSecurityEntitySupported(entity, name));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/util/security/SecurityUtilsTest.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/security/SecurityUtilsTest.java b/sshd-common/src/test/java/org/apache/sshd/common/util/security/SecurityUtilsTest.java
new file mode 100644
index 0000000..46ca075
--- /dev/null
+++ b/sshd-common/src/test/java/org/apache/sshd/common/util/security/SecurityUtilsTest.java
@@ -0,0 +1,231 @@
+/*
+ * 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.util.security;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.security.GeneralSecurityException;
+import java.security.KeyPair;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.interfaces.DSAPrivateKey;
+import java.security.interfaces.DSAPublicKey;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.ECPublicKey;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.sshd.common.cipher.BuiltinCiphers;
+import org.apache.sshd.common.cipher.ECCurves;
+import org.apache.sshd.common.config.keys.FilePasswordProvider;
+import org.apache.sshd.common.config.keys.KeyUtils;
+import org.apache.sshd.common.config.keys.loader.KeyPairResourceLoader;
+import org.apache.sshd.common.keyprovider.AbstractResourceKeyPairProvider;
+import org.apache.sshd.common.keyprovider.ClassLoadableResourceKeyPairProvider;
+import org.apache.sshd.common.keyprovider.FileKeyPairProvider;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.util.test.JUnitTestSupport;
+import org.apache.sshd.util.test.NoIoTestCase;
+import org.junit.AfterClass;
+import org.junit.Assume;
+import org.junit.BeforeClass;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runners.MethodSorters;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Category({ NoIoTestCase.class })
+@SuppressWarnings("checkstyle:MethodCount")
+public class SecurityUtilsTest extends JUnitTestSupport {
+    public static final String BC_NAMED_USAGE_PROP =
+            SecurityProviderRegistrar.CONFIG_PROP_BASE
+          + "." + SecurityUtils.BOUNCY_CASTLE
+          + "." + SecurityProviderRegistrar.NAMED_PROVIDER_PROPERTY;
+
+    private static final String DEFAULT_PASSWORD = "super secret passphrase";
+    private static final FilePasswordProvider TEST_PASSWORD_PROVIDER = file -> DEFAULT_PASSWORD;
+
+    public SecurityUtilsTest() {
+        super();
+    }
+
+    // NOTE: Using the BouncyCastle provider instead of the name does not work as expected so we take no chances
+    @BeforeClass
+    public static void useNamedBouncyCastleProvider() {
+        System.setProperty(BC_NAMED_USAGE_PROP, Boolean.TRUE.toString());
+    }
+
+    @AfterClass
+    public static void unsetBouncyCastleProviderUsagePreference() {
+        System.clearProperty(BC_NAMED_USAGE_PROP);
+    }
+
+    @Test
+    public void testLoadEncryptedDESPrivateKey() throws Exception {
+        testLoadEncryptedRSAPrivateKey("DES-EDE3");
+    }
+
+    @Test
+    public void testLoadEncryptedAESPrivateKey() {
+        for (BuiltinCiphers c : new BuiltinCiphers[]{
+            BuiltinCiphers.aes128cbc, BuiltinCiphers.aes192cbc, BuiltinCiphers.aes256cbc
+        }) {
+            if (!c.isSupported()) {
+                System.out.println("Skip unsupported encryption scheme: " + c.getName());
+                continue;
+            }
+
+            try {
+                testLoadEncryptedRSAPrivateKey("AES-" + c.getKeySize());
+            } catch (Exception e) {
+                fail("Failed (" + e.getClass().getSimpleName() + " to load key for " + c.getName() + ": " + e.getMessage());
+            }
+        }
+    }
+
+    private KeyPair testLoadEncryptedRSAPrivateKey(String algorithm) throws IOException, GeneralSecurityException {
+        return testLoadRSAPrivateKey(DEFAULT_PASSWORD.replace(' ', '-') + "-RSA-" + algorithm.toUpperCase() + "-key");
+    }
+
+    @Test
+    public void testLoadUnencryptedRSAPrivateKey() throws Exception {
+        testLoadRSAPrivateKey(getClass().getSimpleName() + "-RSA-KeyPair");
+    }
+
+    @Test
+    public void testLoadUnencryptedDSSPrivateKey() throws Exception {
+        testLoadDSSPrivateKey(getClass().getSimpleName() + "-DSA-KeyPair");
+    }
+
+    private KeyPair testLoadDSSPrivateKey(String name) throws Exception {
+        return testLoadPrivateKey(name, DSAPublicKey.class, DSAPrivateKey.class);
+    }
+
+    @Test
+    public void testLoadUnencryptedECPrivateKey() throws Exception {
+        Assume.assumeTrue("EC not supported", SecurityUtils.isECCSupported());
+        for (ECCurves c : ECCurves.VALUES) {
+            if (!c.isSupported()) {
+                System.out.println("Skip unsupported curve: " + c.getName());
+                continue;
+            }
+
+            testLoadECPrivateKey(getClass().getSimpleName() + "-EC-" + c.getKeySize() + "-KeyPair");
+        }
+    }
+
+    private KeyPair testLoadECPrivateKey(String name) throws IOException, GeneralSecurityException {
+        return testLoadPrivateKey(name, ECPublicKey.class, ECPrivateKey.class);
+    }
+
+    private KeyPair testLoadRSAPrivateKey(String name) throws IOException, GeneralSecurityException {
+        return testLoadPrivateKey(name, RSAPublicKey.class, RSAPrivateKey.class);
+    }
+
+    private KeyPair testLoadPrivateKey(String name, Class<? extends PublicKey> pubType, Class<? extends PrivateKey> prvType)
+            throws IOException, GeneralSecurityException {
+        Path folder = getTestResourcesFolder();
+        Path file = folder.resolve(name);
+        KeyPair kpFile = testLoadPrivateKeyFile(file, pubType, prvType);
+        if (SecurityUtils.isBouncyCastleRegistered()) {
+            KeyPairResourceLoader bcLoader = SecurityUtils.getBouncycastleKeyPairResourceParser();
+            Collection<KeyPair> kpList = bcLoader.loadKeyPairs(file, TEST_PASSWORD_PROVIDER);
+            assertEquals(name + ": Mismatched loaded BouncyCastle keys count", 1, GenericUtils.size(kpList));
+
+            KeyPair kpBC = kpList.iterator().next();
+            assertTrue(name + ": Mismatched BouncyCastle vs. file values", KeyUtils.compareKeyPairs(kpFile, kpBC));
+        }
+
+        Class<?> clazz = getClass();
+        Package pkg = clazz.getPackage();
+        KeyPair kpResource = testLoadPrivateKeyResource(pkg.getName().replace('.', '/') + "/" + name, pubType, prvType);
+        assertTrue(name + ": Mismatched key file vs. resource values", KeyUtils.compareKeyPairs(kpFile, kpResource));
+        return kpResource;
+    }
+
+    private static KeyPair testLoadPrivateKeyResource(String name, Class<? extends PublicKey> pubType, Class<? extends PrivateKey> prvType) {
+        return testLoadPrivateKey(name, new ClassLoadableResourceKeyPairProvider(name), pubType, prvType);
+    }
+
+    private static KeyPair testLoadPrivateKeyFile(Path file, Class<? extends PublicKey> pubType, Class<? extends PrivateKey> prvType) {
+        return testLoadPrivateKey(file.toString(), new FileKeyPairProvider(file), pubType, prvType);
+    }
+
+    private static KeyPair testLoadPrivateKey(String resourceKey, AbstractResourceKeyPairProvider<?> provider,
+            Class<? extends PublicKey> pubType, Class<? extends PrivateKey> prvType) {
+        provider.setPasswordFinder(TEST_PASSWORD_PROVIDER);
+        Iterable<KeyPair> iterator = provider.loadKeys();
+        List<KeyPair> pairs = new ArrayList<>();
+        for (KeyPair kp : iterator) {
+            pairs.add(kp);
+        }
+
+        assertEquals("Mismatched loaded pairs count for " + resourceKey, 1, pairs.size());
+
+        KeyPair kp = pairs.get(0);
+        PublicKey pub = kp.getPublic();
+        assertNotNull("No public key extracted", pub);
+        assertTrue("Not an " + pubType.getSimpleName() + " public key for " + resourceKey, pubType.isAssignableFrom(pub.getClass()));
+
+        PrivateKey prv = kp.getPrivate();
+        assertNotNull("No private key extracted", prv);
+        assertTrue("Not an " + prvType.getSimpleName() + " private key for " + resourceKey, prvType.isAssignableFrom(prv.getClass()));
+
+        return kp;
+    }
+
+    @Test
+    public void testSetMaxDHGroupExchangeKeySizeByProperty() {
+        try {
+            for (int expected = SecurityUtils.MIN_DHGEX_KEY_SIZE; expected <= SecurityUtils.MAX_DHGEX_KEY_SIZE; expected += 1024) {
+                SecurityUtils.setMaxDHGroupExchangeKeySize(0);  // force detection
+                try {
+                    System.setProperty(SecurityUtils.MAX_DHGEX_KEY_SIZE_PROP, Integer.toString(expected));
+                    assertTrue("DH group not supported for key size=" + expected, SecurityUtils.isDHGroupExchangeSupported());
+                    assertEquals("Mismatched values", expected, SecurityUtils.getMaxDHGroupExchangeKeySize());
+                } finally {
+                    System.clearProperty(SecurityUtils.MAX_DHGEX_KEY_SIZE_PROP);
+                }
+            }
+        } finally {
+            SecurityUtils.setMaxDHGroupExchangeKeySize(0);  // force detection
+        }
+    }
+
+    @Test
+    public void testSetMaxDHGroupExchangeKeySizeProgrammatically() {
+        try {
+            for (int expected = SecurityUtils.MIN_DHGEX_KEY_SIZE; expected <= SecurityUtils.MAX_DHGEX_KEY_SIZE; expected += 1024) {
+                SecurityUtils.setMaxDHGroupExchangeKeySize(expected);
+                assertTrue("DH group not supported for key size=" + expected, SecurityUtils.isDHGroupExchangeSupported());
+                assertEquals("Mismatched values", expected, SecurityUtils.getMaxDHGroupExchangeKeySize());
+            }
+        } finally {
+            SecurityUtils.setMaxDHGroupExchangeKeySize(0);  // force detection
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/util/security/eddsa/EDDSAProviderTest.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/security/eddsa/EDDSAProviderTest.java b/sshd-common/src/test/java/org/apache/sshd/common/util/security/eddsa/EDDSAProviderTest.java
new file mode 100644
index 0000000..7da51c5
--- /dev/null
+++ b/sshd-common/src/test/java/org/apache/sshd/common/util/security/eddsa/EDDSAProviderTest.java
@@ -0,0 +1,126 @@
+/*
+ * 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.util.security.eddsa;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.security.GeneralSecurityException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.Signature;
+
+import org.apache.sshd.common.config.keys.AuthorizedKeyEntry;
+import org.apache.sshd.common.config.keys.KeyUtils;
+import org.apache.sshd.common.keyprovider.KeyPairProvider;
+import org.apache.sshd.common.util.buffer.Buffer;
+import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
+import org.apache.sshd.common.util.security.SecurityUtils;
+import org.apache.sshd.util.test.JUnitTestSupport;
+import org.apache.sshd.util.test.NoIoTestCase;
+import org.junit.Assume;
+import org.junit.BeforeClass;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runners.MethodSorters;
+
+import net.i2p.crypto.eddsa.EdDSAEngine;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Category({ NoIoTestCase.class })
+public class EDDSAProviderTest extends JUnitTestSupport {
+    private static KeyPair keyPair;
+
+    public EDDSAProviderTest() {
+        super();
+    }
+
+    @BeforeClass
+    public static void checkProviderSupported() throws GeneralSecurityException {
+        Assume.assumeTrue(SecurityUtils.EDDSA + " not supported", SecurityUtils.isEDDSACurveSupported());
+        KeyPairGenerator g = SecurityUtils.getKeyPairGenerator(SecurityUtils.EDDSA);
+        assertNotNull("No generator instance", g);
+
+        keyPair = g.generateKeyPair();
+        assertNotNull("No key pair generated", keyPair);
+
+        PublicKey pubKey = keyPair.getPublic();
+        assertNotNull("No public key", pubKey);
+        assertEquals("Mismatched public key algorithm", SecurityUtils.EDDSA, pubKey.getAlgorithm());
+        assertEquals("Mismatched public key type", KeyPairProvider.SSH_ED25519, KeyUtils.getKeyType(pubKey));
+
+        PrivateKey prvKey = keyPair.getPrivate();
+        assertNotNull("No private key", prvKey);
+        assertEquals("Mismatched key-pair algorithm", pubKey.getAlgorithm(), prvKey.getAlgorithm());
+        assertEquals("Mismatched private key type", KeyPairProvider.SSH_ED25519, KeyUtils.getKeyType(prvKey));
+    }
+
+    @Test
+    public void testSignature() throws GeneralSecurityException {
+        Signature s = SecurityUtils.getSignature(EdDSAEngine.SIGNATURE_ALGORITHM);
+        assertNotNull("No signature instance", s);
+        s.initSign(keyPair.getPrivate());
+
+        byte[] data = (getClass().getName() + "#" + getCurrentTestName()).getBytes(StandardCharsets.UTF_8);
+        s.update(data);
+        byte[] signed = s.sign();
+
+        s = SecurityUtils.getSignature(EdDSAEngine.SIGNATURE_ALGORITHM);
+        s.initVerify(keyPair.getPublic());
+        s.update(data);
+        assertTrue("Failed to verify", s.verify(signed));
+    }
+
+    @Test
+    public void testPublicKeyEntryDecoder() throws IOException, GeneralSecurityException {
+        String comment = getCurrentTestName() + "@" + getClass().getSimpleName();
+        String expected = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGPKSUTyz1HwHReFVvD5obVsALAgJRNarH4TRpNePnAS " + comment;
+        AuthorizedKeyEntry keyEntry = AuthorizedKeyEntry.parseAuthorizedKeyEntry(expected);
+        assertNotNull("No extracted key entry", keyEntry);
+
+        assertEquals("Mismatched key type", KeyPairProvider.SSH_ED25519, keyEntry.getKeyType());
+        assertEquals("Mismatched comment", comment, keyEntry.getComment());
+
+        StringBuilder sb = new StringBuilder(expected.length());
+        PublicKey pubKey = keyEntry.appendPublicKey(sb, null);
+        assertEquals("Mismatched encoded result", expected, sb.toString());
+
+        testPublicKeyRecovery(pubKey);
+    }
+
+    @Test
+    public void testGeneratedPublicKeyRecovery() throws IOException, GeneralSecurityException {
+        testPublicKeyRecovery(keyPair.getPublic());
+    }
+
+    private void testPublicKeyRecovery(PublicKey pubKey) throws IOException, GeneralSecurityException {
+        assertNotNull("No public key generated", pubKey);
+        assertEquals("Mismatched public key algorithm", SecurityUtils.EDDSA, pubKey.getAlgorithm());
+
+        Buffer buf = SecurityUtils.putRawEDDSAPublicKey(new ByteArrayBuffer(), pubKey);
+        PublicKey actual = buf.getRawPublicKey();
+        assertEquals("Mismatched key algorithm", pubKey.getAlgorithm(), actual.getAlgorithm());
+        assertEquals("Mismatched recovered key", pubKey, actual);
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/util/security/eddsa/Ed25519VectorsTest.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/security/eddsa/Ed25519VectorsTest.java b/sshd-common/src/test/java/org/apache/sshd/common/util/security/eddsa/Ed25519VectorsTest.java
new file mode 100644
index 0000000..cfebb85
--- /dev/null
+++ b/sshd-common/src/test/java/org/apache/sshd/common/util/security/eddsa/Ed25519VectorsTest.java
@@ -0,0 +1,238 @@
+/*
+ * 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.util.security.eddsa;
+
+import java.nio.charset.StandardCharsets;
+import java.security.GeneralSecurityException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.sshd.common.signature.Signature;
+import org.apache.sshd.common.util.buffer.BufferUtils;
+import org.apache.sshd.common.util.security.SecurityUtils;
+import org.apache.sshd.util.test.JUnit4ClassRunnerWithParametersFactory;
+import org.apache.sshd.util.test.JUnitTestSupport;
+import org.apache.sshd.util.test.NoIoTestCase;
+import org.junit.Assume;
+import org.junit.BeforeClass;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+import org.junit.runners.MethodSorters;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+import org.junit.runners.Parameterized.UseParametersRunnerFactory;
+
+import net.i2p.crypto.eddsa.EdDSAPrivateKey;
+import net.i2p.crypto.eddsa.EdDSAPublicKey;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ * @see <A HREF="https://tools.ietf.org/html/draft-josefsson-eddsa-ed25519-02#section-6">
+ * EdDSA and Ed25519 draft-josefsson-eddsa-ed25519-02 - section 6 - Test Vectors for Ed25519</A>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RunWith(Parameterized.class)   // see https://github.com/junit-team/junit/wiki/Parameterized-tests
+@UseParametersRunnerFactory(JUnit4ClassRunnerWithParametersFactory.class)
+@Category({ NoIoTestCase.class })
+public class Ed25519VectorsTest extends JUnitTestSupport {
+    private final byte[] prvBytes;
+    private final PrivateKey privateKey;
+    private final byte[] pubBytes;
+    private final PublicKey publicKey;
+    private final byte[] msgBytes;
+    private final byte[] expSignature;
+
+    public Ed25519VectorsTest(String name, String prvKey, String pubKey, String msg, String signature)
+            throws GeneralSecurityException {
+        prvBytes = BufferUtils.decodeHex(BufferUtils.EMPTY_HEX_SEPARATOR, prvKey);
+        privateKey = EdDSASecurityProviderUtils.generateEDDSAPrivateKey(prvBytes.clone());
+        pubBytes = BufferUtils.decodeHex(BufferUtils.EMPTY_HEX_SEPARATOR, pubKey);
+        publicKey = EdDSASecurityProviderUtils.generateEDDSAPublicKey(pubBytes.clone());
+        msgBytes = BufferUtils.decodeHex(BufferUtils.EMPTY_HEX_SEPARATOR, msg);
+        expSignature = BufferUtils.decodeHex(BufferUtils.EMPTY_HEX_SEPARATOR, signature);
+    }
+
+    @Parameters(name = "{0}")
+    @SuppressWarnings("checkstyle:anoninnerlength")
+    public static List<Object[]> parameters() {
+        return new ArrayList<>(Arrays.asList(
+                new Object[]{
+                    "TEST1 - empty message",
+                    "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60",
+                    "d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a",
+                    "",
+                    "e5564300c360ac729086e2cc806e828a"
+                      + "84877f1eb8e5d974d873e06522490155"
+                      + "5fb8821590a33bacc61e39701cf9b46b"
+                      + "d25bf5f0595bbe24655141438e7a100b"
+                },
+                new Object[]{
+                    "TEST2 - one byte",
+                    "4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb",
+                    "3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c",
+                    "72",
+                    "92a009a9f0d4cab8720e820b5f642540"
+                      + "a2b27b5416503f8fb3762223ebdb69da"
+                      + "085ac1e43e15996e458f3613d0f11d8c"
+                      + "387b2eaeb4302aeeb00d291612bb0c00"
+                },
+                new Object[]{
+                    "TEST3 - 2 bytes",
+                    "c5aa8df43f9f837bedb7442f31dcb7b166d38535076f094b85ce3a2e0b4458f7",
+                    "fc51cd8e6218a1a38da47ed00230f0580816ed13ba3303ac5deb911548908025",
+                    "af82",
+                    "6291d657deec24024827e69c3abe01a3"
+                      + "0ce548a284743a445e3680d7db5ac3ac"
+                      + "18ff9b538d16f290ae67f760984dc659"
+                      + "4a7c15e9716ed28dc027beceea1ec40a"
+                },
+                new Object[]{
+                    "TEST1024 - large message",
+                    "f5e5767cf153319517630f226876b86c8160cc583bc013744c6bf255f5cc0ee5",
+                    "278117fc144c72340f67d0f2316e8386ceffbf2b2428c9c51fef7c597f1d426e",
+                    "08b8b2b733424243760fe426a4b54908"
+                      + "632110a66c2f6591eabd3345e3e4eb98"
+                      + "fa6e264bf09efe12ee50f8f54e9f77b1"
+                      + "e355f6c50544e23fb1433ddf73be84d8"
+                      + "79de7c0046dc4996d9e773f4bc9efe57"
+                      + "38829adb26c81b37c93a1b270b20329d"
+                      + "658675fc6ea534e0810a4432826bf58c"
+                      + "941efb65d57a338bbd2e26640f89ffbc"
+                      + "1a858efcb8550ee3a5e1998bd177e93a"
+                      + "7363c344fe6b199ee5d02e82d522c4fe"
+                      + "ba15452f80288a821a579116ec6dad2b"
+                      + "3b310da903401aa62100ab5d1a36553e"
+                      + "06203b33890cc9b832f79ef80560ccb9"
+                      + "a39ce767967ed628c6ad573cb116dbef"
+                      + "efd75499da96bd68a8a97b928a8bbc10"
+                      + "3b6621fcde2beca1231d206be6cd9ec7"
+                      + "aff6f6c94fcd7204ed3455c68c83f4a4"
+                      + "1da4af2b74ef5c53f1d8ac70bdcb7ed1"
+                      + "85ce81bd84359d44254d95629e9855a9"
+                      + "4a7c1958d1f8ada5d0532ed8a5aa3fb2"
+                      + "d17ba70eb6248e594e1a2297acbbb39d"
+                      + "502f1a8c6eb6f1ce22b3de1a1f40cc24"
+                      + "554119a831a9aad6079cad88425de6bd"
+                      + "e1a9187ebb6092cf67bf2b13fd65f270"
+                      + "88d78b7e883c8759d2c4f5c65adb7553"
+                      + "878ad575f9fad878e80a0c9ba63bcbcc"
+                      + "2732e69485bbc9c90bfbd62481d9089b"
+                      + "eccf80cfe2df16a2cf65bd92dd597b07"
+                      + "07e0917af48bbb75fed413d238f5555a"
+                      + "7a569d80c3414a8d0859dc65a46128ba"
+                      + "b27af87a71314f318c782b23ebfe808b"
+                      + "82b0ce26401d2e22f04d83d1255dc51a"
+                      + "ddd3b75a2b1ae0784504df543af8969b"
+                      + "e3ea7082ff7fc9888c144da2af58429e"
+                      + "c96031dbcad3dad9af0dcbaaaf268cb8"
+                      + "fcffead94f3c7ca495e056a9b47acdb7"
+                      + "51fb73e666c6c655ade8297297d07ad1"
+                      + "ba5e43f1bca32301651339e22904cc8c"
+                      + "42f58c30c04aafdb038dda0847dd988d"
+                      + "cda6f3bfd15c4b4c4525004aa06eeff8"
+                      + "ca61783aacec57fb3d1f92b0fe2fd1a8"
+                      + "5f6724517b65e614ad6808d6f6ee34df"
+                      + "f7310fdc82aebfd904b01e1dc54b2927"
+                      + "094b2db68d6f903b68401adebf5a7e08"
+                      + "d78ff4ef5d63653a65040cf9bfd4aca7"
+                      + "984a74d37145986780fc0b16ac451649"
+                      + "de6188a7dbdf191f64b5fc5e2ab47b57"
+                      + "f7f7276cd419c17a3ca8e1b939ae49e4"
+                      + "88acba6b965610b5480109c8b17b80e1"
+                      + "b7b750dfc7598d5d5011fd2dcc5600a3"
+                      + "2ef5b52a1ecc820e308aa342721aac09"
+                      + "43bf6686b64b2579376504ccc493d97e"
+                      + "6aed3fb0f9cd71a43dd497f01f17c0e2"
+                      + "cb3797aa2a2f256656168e6c496afc5f"
+                      + "b93246f6b1116398a346f1a641f3b041"
+                      + "e989f7914f90cc2c7fff357876e506b5"
+                      + "0d334ba77c225bc307ba537152f3f161"
+                      + "0e4eafe595f6d9d90d11faa933a15ef1"
+                      + "369546868a7f3a45a96768d40fd9d034"
+                      + "12c091c6315cf4fde7cb68606937380d"
+                      + "b2eaaa707b4c4185c32eddcdd306705e"
+                      + "4dc1ffc872eeee475a64dfac86aba41c"
+                      + "0618983f8741c5ef68d3a101e8a3b8ca"
+                      + "c60c905c15fc910840b94c00a0b9d0",
+                    "0aab4c900501b3e24d7cdf4663326a3a"
+                      + "87df5e4843b2cbdb67cbf6e460fec350"
+                      + "aa5371b1508f9f4528ecea23c436d94b"
+                      + "5e8fcd4f681e30a6ac00a9704a188a03"
+                }));
+    }
+
+    @BeforeClass
+    public static void checkEDDSASupported() {
+        Assume.assumeTrue("EDDSA N/A", SecurityUtils.isEDDSACurveSupported());
+    }
+
+    @Test
+    public void testPublicKeyBytes() {
+        byte[] publicSeed = Ed25519PublicKeyDecoder.getSeedValue((EdDSAPublicKey) publicKey);
+        assertArrayEquals("Mismatched public seed value", pubBytes, publicSeed);
+    }
+
+    @Test
+    public void testPrivateKeyBytes() {
+        assertArrayEquals("Mismatched private seed value", prvBytes, ((EdDSAPrivateKey) privateKey).getSeed());
+    }
+
+    @Test
+    public void testSignature() throws Exception {
+        Signature signer = EdDSASecurityProviderUtils.getEDDSASignature();
+        signer.initSigner(privateKey);
+        signer.update(msgBytes.clone());
+
+        byte[] actSignature = signer.sign();
+        assertArrayEquals("Mismatched signature", expSignature, actSignature);
+
+        Signature verifier = EdDSASecurityProviderUtils.getEDDSASignature();
+        verifier.initVerifier(publicKey);
+        verifier.update(msgBytes.clone());
+        assertTrue("Verification failed", verifier.verify(expSignature));
+    }
+
+    @Test
+    public void testPartialBufferSignature() throws Exception {
+        byte[] extraData = getCurrentTestName().getBytes(StandardCharsets.UTF_8);
+        byte[] dataBuf = new byte[msgBytes.length + extraData.length];
+        int offset = extraData.length / 2;
+        System.arraycopy(extraData, 0, dataBuf, 0, offset);
+        System.arraycopy(msgBytes, 0, dataBuf, offset, msgBytes.length);
+        System.arraycopy(extraData, offset, dataBuf, offset + msgBytes.length, extraData.length - offset);
+
+        Signature signer = EdDSASecurityProviderUtils.getEDDSASignature();
+        signer.initSigner(privateKey);
+        signer.update(dataBuf.clone(), offset, msgBytes.length);
+
+        byte[] actSignature = signer.sign();
+        assertArrayEquals("Mismatched signature", expSignature, actSignature);
+
+        Signature verifier = EdDSASecurityProviderUtils.getEDDSASignature();
+        verifier.initVerifier(publicKey);
+        verifier.update(dataBuf.clone(), offset, msgBytes.length);
+        assertTrue("Verification failed", verifier.verify(expSignature));
+    }
+}