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:42 UTC

[32/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/config/keys/KeyUtilsCloneTest.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/test/java/org/apache/sshd/common/config/keys/KeyUtilsCloneTest.java b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/KeyUtilsCloneTest.java
new file mode 100644
index 0000000..48f7ec4
--- /dev/null
+++ b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/KeyUtilsCloneTest.java
@@ -0,0 +1,120 @@
+/*
+ * 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 java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.sshd.common.cipher.ECCurves;
+import org.apache.sshd.common.keyprovider.KeyPairProvider;
+import org.apache.sshd.common.util.ValidateUtils;
+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.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 KeyUtilsCloneTest extends JUnitTestSupport {
+    private final String keyType;
+    private final int keySize;
+
+    public KeyUtilsCloneTest(String keyType, int keySize) {
+        this.keyType = ValidateUtils.checkNotNullAndNotEmpty(keyType, "No key type specified");
+        this.keySize = keySize;
+    }
+
+    @Parameters(name = "type={0}, size={1}")
+    public static List<Object[]> parameters() {
+        List<Object[]> list = new ArrayList<>();
+        addTests(list, KeyPairProvider.SSH_DSS, DSS_SIZES);
+        addTests(list, KeyPairProvider.SSH_RSA, RSA_SIZES);
+        if (SecurityUtils.isECCSupported()) {
+            for (ECCurves curve : ECCurves.VALUES) {
+                if (!curve.isSupported()) {
+                    continue;
+                }
+                addTests(list, curve.getKeyType(), Collections.singletonList(curve.getKeySize()));
+            }
+        }
+        if (SecurityUtils.isEDDSACurveSupported()) {
+            addTests(list, KeyPairProvider.SSH_ED25519, ED25519_SIZES);
+        }
+        return Collections.unmodifiableList(list);
+    }
+
+    private static void addTests(List<Object[]> list, String keyType, Collection<Integer> sizes) {
+        for (Integer keySize : sizes) {
+            list.add(new Object[]{keyType, keySize});
+        }
+    }
+
+    @Test
+    @SuppressWarnings("checkstyle:avoidnestedblocks")
+    public void testKeyPairCloning() throws GeneralSecurityException {
+        outputDebugMessage("generateKeyPair(%s)[%d]", keyType, keySize);
+        KeyPair original = KeyUtils.generateKeyPair(keyType, keySize);
+
+        outputDebugMessage("cloneKeyPair(%s)[%d]", keyType, keySize);
+        KeyPair cloned = KeyUtils.cloneKeyPair(keyType, original);
+
+        String prefix = keyType + "[" + keySize + "]";
+        assertNotSame(prefix + ": Key pair not cloned", original, cloned);
+        assertTrue(prefix + ": Cloned pair not equals", KeyUtils.compareKeyPairs(original, cloned));
+
+        {
+            PublicKey k1 = original.getPublic();
+            PublicKey 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);
+            String f2 = KeyUtils.getFingerPrint(k2);
+            assertEquals(prefix + ": Mismatched fingerprints", f1, f2);
+        }
+
+        {
+            PrivateKey k1 = original.getPrivate();
+            PrivateKey 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/10de190e/sshd-common/src/test/java/org/apache/sshd/common/config/keys/KeyUtilsFingerprintCaseSensitivityTest.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/test/java/org/apache/sshd/common/config/keys/KeyUtilsFingerprintCaseSensitivityTest.java b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/KeyUtilsFingerprintCaseSensitivityTest.java
new file mode 100644
index 0000000..ae0b86d
--- /dev/null
+++ b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/KeyUtilsFingerprintCaseSensitivityTest.java
@@ -0,0 +1,96 @@
+/*
+ * 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.io.IOException;
+import java.security.GeneralSecurityException;
+import java.security.PublicKey;
+import java.util.AbstractMap.SimpleImmutableEntry;
+import java.util.Arrays;
+import java.util.Collection;
+
+import org.apache.sshd.util.test.JUnit4ClassRunnerWithParametersFactory;
+import org.apache.sshd.util.test.JUnitTestSupport;
+import org.apache.sshd.util.test.NoIoTestCase;
+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;
+
+/**
+ * @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 KeyUtilsFingerprintCaseSensitivityTest extends JUnitTestSupport {
+
+    // CHECKSTYLE:OFF
+    private static final String KEY_STRING = "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAxr3N5fkt966xJINl0hH7Q6lLDRR1D0yMjcXCE5roE9VFut2ctGFuo90TCOxkPOMnwzwConeyScVF4ConZeWsxbG9VtRh61IeZ6R5P5ZTvE9xPdZBgIEWvU1bRfrrOfSMihqF98pODspE6NoTtND2eglwSGwxcYFmpdTAmu+8qgxgGxlEaaCjqwdiNPZhygrH81Mv2ruolNeZkn4Bj+wFFmZTD/waN1pQaMf+SO1+kEYIYFNl5+8JRGuUcr8MhHHJB+gwqMTF2BSBVITJzZUiQR0TMtkK6Vbs7yt1F9hhzDzAFDwhV+rsfNQaOHpl3zP07qH+/99A0XG1CVcEdHqVMw== lgoldstein@LGOLDSTEIN-WIN7";
+    // CHECKSTYLE:ON
+    private static final String MD5_PREFIX = "MD5:";
+    private static final String MD5 = "24:32:3c:80:01:b3:e1:fa:7c:53:ca:e3:e8:4e:c6:8e";
+    private static final String MD5_FULL = MD5_PREFIX + MD5;
+    private static final String SHA1_PREFIX = "SHA1:";
+    private static final String SHA1 = "ZNLzC6u+F37oq8BpEAwP69EQtoA";
+    private static final String SHA1_FULL = SHA1_PREFIX + SHA1;
+
+    private static PublicKey key;
+
+    private String expected;
+    private String test;
+
+    public KeyUtilsFingerprintCaseSensitivityTest(String expected, String test) {
+        this.expected = expected;
+        this.test = test;
+    }
+
+    @BeforeClass
+    public static void beforeClass() throws GeneralSecurityException, IOException {
+        key = PublicKeyEntry.parsePublicKeyEntry(KEY_STRING).resolvePublicKey(PublicKeyEntryResolver.FAILING);
+    }
+
+    @Parameters(name = "expected={0}, test={1}")
+    public static Collection<Object[]> parameters() {
+        return Arrays.asList(
+            new Object[] {MD5_FULL, MD5_FULL},
+            new Object[] {MD5_FULL, MD5_FULL.toUpperCase()},
+            new Object[] {MD5_FULL, MD5_FULL.toLowerCase()},
+            new Object[] {MD5_FULL, MD5_PREFIX.toUpperCase() + MD5},
+            new Object[] {MD5_FULL, MD5_PREFIX.toLowerCase() + MD5},
+            new Object[] {MD5_FULL, MD5.toLowerCase()},
+            new Object[] {MD5_FULL, MD5.toUpperCase()},
+            new Object[] {SHA1_FULL, SHA1_FULL},
+            new Object[] {SHA1_FULL, SHA1_PREFIX.toUpperCase() + SHA1},
+            new Object[] {SHA1_FULL, SHA1_PREFIX.toLowerCase() + SHA1}
+        );
+    }
+
+    @Test
+    public void testCase() throws Exception {
+        assertEquals("Check failed", new SimpleImmutableEntry<>(true, expected), KeyUtils.checkFingerPrint(test, key));
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/config/keys/KeyUtilsFingerprintGenerationTest.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/test/java/org/apache/sshd/common/config/keys/KeyUtilsFingerprintGenerationTest.java b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/KeyUtilsFingerprintGenerationTest.java
new file mode 100644
index 0000000..9a8fb7a
--- /dev/null
+++ b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/KeyUtilsFingerprintGenerationTest.java
@@ -0,0 +1,159 @@
+/*
+ * 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.io.IOException;
+import java.security.GeneralSecurityException;
+import java.security.PublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.util.AbstractMap.SimpleImmutableEntry;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.sshd.common.digest.BuiltinDigests;
+import org.apache.sshd.common.digest.DigestFactory;
+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 KeyUtilsFingerprintGenerationTest extends JUnitTestSupport {
+    private final PublicKey key;
+    private final DigestFactory digestFactory;
+    private final String expected;
+
+    public KeyUtilsFingerprintGenerationTest(PublicKey key, DigestFactory digestFactory, String expected) {
+        this.key = key;
+        this.digestFactory = digestFactory;
+        this.expected = expected;
+    }
+
+    @Parameters(name = "key={0}, digestFactory={1}, expected={2}")
+    public static Collection<Object[]> parameters() throws IOException, GeneralSecurityException {
+        List<? extends Map.Entry<String, List<? extends Map.Entry<DigestFactory, String>>>> keyEntries =
+            Collections.unmodifiableList(Arrays.asList(
+                new SimpleImmutableEntry<>(
+                    // CHECKSTYLE:OFF
+                    "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAxr3N5fkt966xJINl0hH7Q6lLDRR1D0yMjcXCE5roE9VFut2ctGFuo90TCOxkPOMnwzwConeyScVF4ConZeWsxbG9VtRh61IeZ6R5P5ZTvE9xPdZBgIEWvU1bRfrrOfSMihqF98pODspE6NoTtND2eglwSGwxcYFmpdTAmu+8qgxgGxlEaaCjqwdiNPZhygrH81Mv2ruolNeZkn4Bj+wFFmZTD/waN1pQaMf+SO1+kEYIYFNl5+8JRGuUcr8MhHHJB+gwqMTF2BSBVITJzZUiQR0TMtkK6Vbs7yt1F9hhzDzAFDwhV+rsfNQaOHpl3zP07qH+/99A0XG1CVcEdHqVMw== lgoldstein@LGOLDSTEIN-WIN7",
+                    // CHECKSTYLE:ON
+                    Arrays.asList(
+                        new SimpleImmutableEntry<>(
+                            BuiltinDigests.md5,
+                            "MD5:24:32:3c:80:01:b3:e1:fa:7c:53:ca:e3:e8:4e:c6:8e"
+                        ),
+                        new SimpleImmutableEntry<>(
+                            BuiltinDigests.sha256,
+                            "SHA256:1wNOZO+/XgNGJMx8UUJst33V+bBMTz5EcL0B6y2iRv0"
+                        )
+                    )
+                ),
+                new SimpleImmutableEntry<>(
+                    // CHECKSTYLE:OFF
+                    "ssh-dss AAAAB3NzaC1kc3MAAACBAMg/IxsG5BxnF5gM7IKqqR0rftxZC+n5GlbO+J4H+iIb/KR8NBehkxG3CrBZMF96M2K1sEGYLob+3k4r71oWaPul8n5rt9kpd+JSq4iD2ygOyg6Kd1/YDBHoxneizy6I/bGsLwhAAKWcRNrXmYVKGzhrhvZWN12AJDq2mGdj3szLAAAAFQD7a2MltdUSF7FU3//SpW4WGjZbeQAAAIBf0nNsfKQL/TEMo7IpTrEMg5V0RnSigCX0+yUERS42GW/ZeCZBJw7oL2XZbuBtu63vMjDgVpnb92BdrcPgjJ7EFW6DlcyeuywStmg1ygXmDR2AQCxv0eX2CQgrdUczmRa155SDVUTvTQlO1IyKx0vwKAh1H7E3yJUfkTAJstbGYQAAAIEAtv+cdRfNevYFkp55jVqazc8zRLvfb64jzgc5oSJVc64kFs4yx+abYpGX9WxNxDlG6g2WiY8voDBB0YnUJsn0kVRjBKX9OceROxrfT4K4dVbQZsdt+SLaXWL4lGJFrFZL3LZqvySvq6xfhJfakQDDivW4hUOhFPXPHrE5/Ia3T7A= dsa-key-20130709",
+                    // CHECKSTYLE:ON
+                    Arrays.asList(
+                        new SimpleImmutableEntry<>(
+                            BuiltinDigests.md5,
+                            "MD5:fb:29:14:8d:94:f9:1d:cf:6b:0e:a4:35:1d:83:44:2f"
+                        ),
+                        new SimpleImmutableEntry<>(
+                            BuiltinDigests.sha256,
+                            "SHA256:grxw4KhY1cK6eOczBWs7tDVvo9V0PQw4E1wN1gJvHlw"
+                        )
+                    )
+                ),
+                new SimpleImmutableEntry<>(
+                    // CHECKSTYLE:OFF
+                    "ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBFImZtcTj842stlcVHLFBFxTEx7lu3jW9aZCvd0r9fUNKZ6LbRPh6l1oJ4ozArnw7XreQBUc5oNd9HB5RNJ8jl1nWXY5cXBA7McZrKZrYmk+zxNhH6UL+kMLaJkyngJHQw== root@osv-linux",
+                    // CHECKSTYLE:ON
+                    Arrays.asList(
+                        new SimpleImmutableEntry<>(
+                            BuiltinDigests.md5,
+                            "MD5:e6:dc:a2:4f:5b:11:b2:3c:0f:e8:f6:d8:d1:01:e9:d3"
+                        ),
+                        new SimpleImmutableEntry<>(
+                            BuiltinDigests.sha512,
+                            "SHA512:4w6ZB78tmFWhpN2J50Ok6WeMJhZp1X0xN0EKWxZmRLcYDbCWhyJDe8lgrQKWqdTCMZ5aNEBl9xQUklcC5Gt2jg"
+                        )
+                    )
+                )
+            ));
+
+        List<Object[]> ret = new ArrayList<>();
+        for (Map.Entry<String, ? extends Collection<? extends Map.Entry<DigestFactory, String>>> kentry : keyEntries) {
+            String keyValue = kentry.getKey();
+            try {
+                PublicKey key = PublicKeyEntry.parsePublicKeyEntry(keyValue).resolvePublicKey(PublicKeyEntryResolver.FAILING);
+                for (Map.Entry<DigestFactory, String> dentry : kentry.getValue()) {
+                    DigestFactory factory = dentry.getKey();
+                    String fingerprint = dentry.getValue();
+                    if (!factory.isSupported()) {
+                        System.out.println("Skip unsupported digest: " + fingerprint);
+                        continue;
+                    }
+
+                    ret.add(new Object[]{key, factory, fingerprint});
+                }
+            } catch (InvalidKeySpecException e) {
+                System.out.println("Skip unsupported key: " + keyValue);
+            }
+        }
+
+        return ret;
+    }
+
+    @Test
+    public void testFingerprint() throws Exception {
+        String name = digestFactory.getName();
+        assertEquals(
+            String.format("Fingerprint does not match for digest %s", name),
+            expected,
+            KeyUtils.getFingerPrint(digestFactory, key)
+        );
+        assertEquals(
+            String.format("Fingerprint check failed for digest %s", name),
+            new SimpleImmutableEntry<>(true, expected),
+            KeyUtils.checkFingerPrint(expected, digestFactory, key)
+        );
+        assertEquals(
+            String.format("Fingerprint check succeeded for invalid digest %s", name),
+            new SimpleImmutableEntry<>(false, expected),
+            KeyUtils.checkFingerPrint(expected + "A", digestFactory, key)
+        );
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/config/keys/KeyUtilsTest.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/test/java/org/apache/sshd/common/config/keys/KeyUtilsTest.java b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/KeyUtilsTest.java
new file mode 100644
index 0000000..00b273f
--- /dev/null
+++ b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/KeyUtilsTest.java
@@ -0,0 +1,157 @@
+/*
+ * 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.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.security.DigestException;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Map;
+
+import org.apache.sshd.common.digest.BaseDigest;
+import org.apache.sshd.common.digest.BuiltinDigests;
+import org.apache.sshd.common.digest.Digest;
+import org.apache.sshd.common.digest.DigestFactory;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.OsUtils;
+import org.apache.sshd.common.util.io.IoUtils;
+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 KeyUtilsTest extends JUnitTestSupport {
+    public KeyUtilsTest() {
+        super();
+    }
+
+    @Test
+    public void testGenerateFingerPrintOnException() {
+        for (DigestFactory info : BuiltinDigests.VALUES) {
+            if (!info.isSupported()) {
+                System.out.println("Skip unsupported digest: " + info.getAlgorithm());
+                continue;
+            }
+
+            Exception thrown = new DigestException(info.getAlgorithm() + ":" + info.getBlockSize());
+            Digest digest = new BaseDigest(info.getAlgorithm(), info.getBlockSize()) {
+                @Override
+                public byte[] digest() throws Exception {
+                    throw thrown;
+                }
+            };
+            String actual = KeyUtils.getFingerPrint(new DigestFactory() {
+                @Override
+                public String getName() {
+                    return getCurrentTestName();
+                }
+
+                @Override
+                public String getAlgorithm() {
+                    return digest.getAlgorithm();
+                }
+
+                @Override
+                public boolean isSupported() {
+                    return info.isSupported();
+                }
+
+                @Override
+                public int getBlockSize() {
+                    return info.getBlockSize();
+                }
+
+                @Override
+                public Digest create() {
+                    return digest;
+                }
+            }, getCurrentTestName());
+            String expected = thrown.getClass().getSimpleName();
+            assertEquals("Mismatched fingerprint for " + thrown.getMessage(), expected, actual);
+        }
+    }
+
+    @Test
+    public void testGenerateDefaultFingerprintDigest() {
+        DigestFactory defaultValue = KeyUtils.getDefaultFingerPrintFactory();
+        assertNotNull("No current default fingerprint digest factory", defaultValue);
+        try {
+            for (DigestFactory f : BuiltinDigests.VALUES) {
+                if (!f.isSupported()) {
+                    System.out.println("Skip unsupported digest=" + f.getAlgorithm());
+                    continue;
+                }
+
+                KeyUtils.setDefaultFingerPrintFactory(f);
+
+                String data = getClass().getName() + "#" + getCurrentTestName() + "(" + f.getName() + ")";
+                String expected = KeyUtils.getFingerPrint(f, data);
+                String actual = KeyUtils.getFingerPrint(data);
+                assertEquals("Mismatched fingerprint for digest=" + f.getName(), expected, actual);
+            }
+        } finally {
+            KeyUtils.setDefaultFingerPrintFactory(defaultValue); // restore the original
+        }
+    }
+
+    @Test   // see SSHD-606
+    public void testValidateStrictKeyFilePermissions() 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, KeyUtils.validateStrictKeyFilePermissions(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, KeyUtils.validateStrictKeyFilePermissions(file));
+        } else if (OsUtils.isUNIX()) {
+            Map.Entry<String, Object> violation = null;
+            for (PosixFilePermission p : KeyUtils.STRICTLY_PROHIBITED_FILE_PERMISSION) {
+                if (perms.contains(p)) {
+                    violation = KeyUtils.validateStrictKeyFilePermissions(file);
+                    assertNotNull("Unexpected success for permission=" + p + " of file " + file + " permissions=" + perms, violation);
+                    break;
+                }
+            }
+
+            if (violation == null) {    // we expect a failure since the parent does not have the necessary permissions
+                assertNotNull("Unexpected UNIX success for file " + file + " permissions=" + perms, KeyUtils.validateStrictKeyFilePermissions(file));
+            }
+        } else {
+            assertNull("Unexpected Windows violation for file " + file + " permissions=" + perms, KeyUtils.validateStrictKeyFilePermissions(file));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/config/keys/PublicKeyEntryTest.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/test/java/org/apache/sshd/common/config/keys/PublicKeyEntryTest.java b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/PublicKeyEntryTest.java
new file mode 100644
index 0000000..1fd372f
--- /dev/null
+++ b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/PublicKeyEntryTest.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.config.keys;
+
+import java.security.GeneralSecurityException;
+import java.security.PublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.util.Arrays;
+
+import org.apache.sshd.common.util.GenericUtils;
+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 PublicKeyEntryTest extends JUnitTestSupport {
+    public PublicKeyEntryTest() {
+        super();
+    }
+
+    @Test
+    public void testFallbackResolver() throws Exception {
+        PublicKeyEntry entry =  // TODO use some
+                PublicKeyEntry.parsePublicKeyEntry(
+                        GenericUtils.join(
+                                Arrays.asList(getCurrentTestName(), "AAAA", getClass().getSimpleName()), ' '));
+        for (PublicKeyEntryResolver resolver : new PublicKeyEntryResolver[]{
+            null, PublicKeyEntryResolver.FAILING, PublicKeyEntryResolver.IGNORING}) {
+            try {
+                PublicKey key = entry.resolvePublicKey(resolver);
+                assertSame("Mismatched successful resolver", PublicKeyEntryResolver.IGNORING, resolver);
+                assertNull("Unexpected success for resolver=" + resolver + ": " + KeyUtils.getFingerPrint(key), key);
+            } catch (GeneralSecurityException e) {
+                assertObjectInstanceOf("Mismatched thrown exception for resolver=" + resolver, InvalidKeySpecException.class, e);
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/config/keys/loader/AESPrivateKeyObfuscatorTest.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/test/java/org/apache/sshd/common/config/keys/loader/AESPrivateKeyObfuscatorTest.java b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/loader/AESPrivateKeyObfuscatorTest.java
new file mode 100644
index 0000000..48797b8
--- /dev/null
+++ b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/loader/AESPrivateKeyObfuscatorTest.java
@@ -0,0 +1,79 @@
+/*
+ * 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.loader;
+
+import java.security.GeneralSecurityException;
+import java.security.Key;
+import java.util.List;
+import java.util.Random;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.apache.sshd.common.util.GenericUtils;
+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.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 AESPrivateKeyObfuscatorTest extends JUnitTestSupport {
+    private static final Random RANDOMIZER = new Random(System.currentTimeMillis());
+
+    private final int keyLength;
+
+    public AESPrivateKeyObfuscatorTest(int keyLength) {
+        this.keyLength = keyLength;
+    }
+
+    @Parameters(name = "keyLength={0}")
+    public static List<Object[]> parameters() {
+        List<Integer> lengths = AESPrivateKeyObfuscator.getAvailableKeyLengths();
+        assertFalse("No lengths available", GenericUtils.isEmpty(lengths));
+        return parameterize(lengths);
+    }
+
+    @Test
+    public void testAvailableKeyLengthExists() throws GeneralSecurityException {
+        assertEquals("Not a BYTE size multiple", 0, keyLength % Byte.SIZE);
+
+        byte[] iv = new byte[keyLength / Byte.SIZE];
+        synchronized (RANDOMIZER) {
+            RANDOMIZER.nextBytes(iv);
+        }
+
+        Key key = new SecretKeySpec(iv, AESPrivateKeyObfuscator.CIPHER_NAME);
+        Cipher c = SecurityUtils.getCipher(AESPrivateKeyObfuscator.CIPHER_NAME);
+        c.init(Cipher.DECRYPT_MODE, key);
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParserTest.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/test/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParserTest.java b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParserTest.java
new file mode 100644
index 0000000..d5c6aba
--- /dev/null
+++ b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParserTest.java
@@ -0,0 +1,108 @@
+/*
+ * 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.loader.openssh;
+
+import java.net.URL;
+import java.security.KeyPair;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.sshd.common.config.keys.AuthorizedKeyEntry;
+import org.apache.sshd.common.config.keys.BuiltinIdentities;
+import org.apache.sshd.common.config.keys.FilePasswordProvider;
+import org.apache.sshd.common.config.keys.PrivateKeyEntryDecoder;
+import org.apache.sshd.common.config.keys.PublicKeyEntryResolver;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.ValidateUtils;
+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.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 OpenSSHKeyPairResourceParserTest extends JUnitTestSupport {
+    private static final OpenSSHKeyPairResourceParser PARSER = OpenSSHKeyPairResourceParser.INSTANCE;
+    private final BuiltinIdentities identity;
+
+    public OpenSSHKeyPairResourceParserTest(BuiltinIdentities identity) {
+        this.identity = identity;
+    }
+
+    @Parameters(name = "type={0}")
+    public static List<Object[]> parameters() {
+        return parameterize(BuiltinIdentities.VALUES);
+    }
+
+    @Test
+    public void testLoadKeyPairs() throws Exception {
+        Assume.assumeTrue(identity + " not supported", identity.isSupported());
+
+        String resourceKey = getClass().getSimpleName() + "-" + identity.getName().toUpperCase() + "-" + KeyPair.class.getSimpleName();
+        URL urlKeyPair = getClass().getResource(resourceKey);
+        assertNotNull("Missing key-pair resource: " + resourceKey, urlKeyPair);
+
+        Collection<KeyPair> pairs = PARSER.loadKeyPairs(urlKeyPair, FilePasswordProvider.EMPTY);
+        assertEquals("Mismatched pairs count", 1, GenericUtils.size(pairs));
+
+        URL urlPubKey = getClass().getResource(resourceKey + ".pub");
+        assertNotNull("Missing public key resource: " + resourceKey, urlPubKey);
+
+        List<AuthorizedKeyEntry> entries = AuthorizedKeyEntry.readAuthorizedKeys(urlPubKey);
+        assertEquals("Mismatched public keys count", 1, GenericUtils.size(entries));
+
+        AuthorizedKeyEntry entry = entries.get(0);
+        PublicKey pubEntry = entry.resolvePublicKey(PublicKeyEntryResolver.FAILING);
+        assertNotNull("Cannot retrieve public key", pubEntry);
+
+        Class<? extends PublicKey> pubType = identity.getPublicKeyType();
+        Class<? extends PrivateKey> prvType = identity.getPrivateKeyType();
+        for (KeyPair kp : pairs) {
+            PublicKey pubKey = ValidateUtils.checkInstanceOf(kp.getPublic(), pubType, "Mismatched public key type");
+            assertKeyEquals("Mismatched identity public key", pubEntry, pubKey);
+
+            PrivateKey prvKey = ValidateUtils.checkInstanceOf(kp.getPrivate(), prvType, "Mismatched private key type");
+            @SuppressWarnings("rawtypes")
+            PrivateKeyEntryDecoder decoder =
+                OpenSSHKeyPairResourceParser.getPrivateKeyEntryDecoder(prvKey);
+            assertNotNull("No private key decoder", decoder);
+
+            if (decoder.isPublicKeyRecoverySupported()) {
+                @SuppressWarnings("unchecked")
+                PublicKey recKey = decoder.recoverPublicKey(prvKey);
+                assertKeyEquals("Mismatched recovered public key", pubKey, recKey);
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/config/keys/loader/pem/PKCS8PEMResourceKeyPairParserTest.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/test/java/org/apache/sshd/common/config/keys/loader/pem/PKCS8PEMResourceKeyPairParserTest.java b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/loader/pem/PKCS8PEMResourceKeyPairParserTest.java
new file mode 100644
index 0000000..406a273
--- /dev/null
+++ b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/loader/pem/PKCS8PEMResourceKeyPairParserTest.java
@@ -0,0 +1,107 @@
+/*
+ * 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.loader.pem;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PrivateKey;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.commons.ssl.PEMItem;
+import org.apache.commons.ssl.PEMUtil;
+import org.apache.sshd.common.config.keys.KeyUtils;
+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.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;
+
+/**
+ * TODO Add javadoc
+ *
+ * @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 PKCS8PEMResourceKeyPairParserTest extends JUnitTestSupport {
+    private final String algorithm;
+    private final int keySize;
+
+    public PKCS8PEMResourceKeyPairParserTest(String algorithm, int keySize) {
+        this.algorithm = algorithm;
+        this.keySize = keySize;
+    }
+
+    @Parameters(name = "{0} / {1}")
+    public static List<Object[]> parameters() {
+        List<Object[]> params = new ArrayList<>();
+        for (Integer ks : RSA_SIZES) {
+            params.add(new Object[]{KeyUtils.RSA_ALGORITHM, ks});
+        }
+        for (Integer ks : DSS_SIZES) {
+            params.add(new Object[]{KeyUtils.DSS_ALGORITHM, ks});
+        }
+        return params;
+    }
+
+    @Test   // see SSHD-760
+    public void testPkcs8() throws IOException, GeneralSecurityException {
+        KeyPairGenerator generator = SecurityUtils.getKeyPairGenerator(algorithm);
+        if (keySize > 0) {
+            generator.initialize(keySize);
+        }
+        KeyPair kp = generator.generateKeyPair();
+
+        try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
+            Collection<Object> items = new ArrayList<>();
+            PrivateKey prv1 = kp.getPrivate();
+            items.add(new PEMItem(prv1.getEncoded(), "PRIVATE KEY"));
+            byte[] bytes = PEMUtil.encode(items);
+            os.write(bytes);
+            os.close();
+
+            try (ByteArrayInputStream bais = new ByteArrayInputStream(os.toByteArray())) {
+                KeyPair kp2 = SecurityUtils.loadKeyPairIdentity(getCurrentTestName(), bais, null);
+
+                assertEquals("Mismatched public key", kp.getPublic(), kp2.getPublic());
+                assertEquals("Mismatched private key", prv1, kp2.getPrivate());
+            }
+        }
+    }
+
+    @Override
+    public String toString() {
+        return getClass().getSimpleName() + "[" + algorithm + "/" + keySize + "]";
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/digest/BuiltinDigestsTest.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/test/java/org/apache/sshd/common/digest/BuiltinDigestsTest.java b/sshd-common/src/test/java/org/apache/sshd/common/digest/BuiltinDigestsTest.java
new file mode 100644
index 0000000..9ec928b
--- /dev/null
+++ b/sshd-common/src/test/java/org/apache/sshd/common/digest/BuiltinDigestsTest.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sshd.common.digest;
+
+import java.lang.reflect.Field;
+import java.util.EnumSet;
+import java.util.Set;
+
+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 BuiltinDigestsTest extends JUnitTestSupport {
+    public BuiltinDigestsTest() {
+        super();
+    }
+
+    @Test
+    public void testFromName() {
+        for (BuiltinDigests expected : BuiltinDigests.VALUES) {
+            String name = expected.getName();
+            BuiltinDigests actual = BuiltinDigests.fromFactoryName(name);
+            assertSame(name, expected, actual);
+        }
+    }
+
+    @Test
+    public void testAllConstantsCovered() throws Exception {
+        Set<BuiltinDigests> avail = EnumSet.noneOf(BuiltinDigests.class);
+        Field[] fields = BuiltinDigests.Constants.class.getFields();
+        for (Field f : fields) {
+            String name = (String) f.get(null);
+            BuiltinDigests value = BuiltinDigests.fromFactoryName(name);
+            assertNotNull("No match found for " + name, value);
+            assertTrue(name + " re-specified", avail.add(value));
+        }
+
+        assertEquals("Incomplete coverage", BuiltinDigests.VALUES, avail);
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/future/DefaultSshFutureTest.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/test/java/org/apache/sshd/common/future/DefaultSshFutureTest.java b/sshd-common/src/test/java/org/apache/sshd/common/future/DefaultSshFutureTest.java
new file mode 100644
index 0000000..05e3df2
--- /dev/null
+++ b/sshd-common/src/test/java/org/apache/sshd/common/future/DefaultSshFutureTest.java
@@ -0,0 +1,137 @@
+/*
+ * 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.future;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+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;
+import org.mockito.Mockito;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Category({ NoIoTestCase.class })
+public class DefaultSshFutureTest extends JUnitTestSupport {
+    public DefaultSshFutureTest() {
+        super();
+    }
+
+    @Test
+    @SuppressWarnings("rawtypes")
+    public void testAwaitUninterrupted() {
+        DefaultSshFuture future = new DefaultSshFuture(getCurrentTestName(), null);
+        Object expected = new Object();
+        new Thread() {
+            @Override
+            public void run() {
+                try {
+                    Thread.sleep(TimeUnit.SECONDS.toMillis(2L));
+                } catch (InterruptedException e) {
+                    throw new RuntimeException(e);
+                }
+                future.setValue(expected);
+            }
+        }.start();
+
+        future.awaitUninterruptibly();
+        assertSame("Mismatched signalled value", expected, future.getValue());
+    }
+
+    @Test
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    public void testNotifyMultipleListeners() {
+        DefaultSshFuture future = new DefaultSshFuture(getCurrentTestName(), null);
+        AtomicInteger listenerCount = new AtomicInteger(0);
+        Object expected = new Object();
+        SshFutureListener listener = f -> {
+            assertSame("Mismatched future instance", future, f);
+            assertSame("Mismatched value object", expected, future.getValue());
+            listenerCount.incrementAndGet();
+        };
+
+        int numListeners = Byte.SIZE;
+        for (int index = 0; index < numListeners; index++) {
+            future.addListener(listener);
+        }
+
+        future.setValue(expected);
+        assertEquals("Mismatched listeners invocation count", numListeners, listenerCount.get());
+    }
+
+    @Test
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    public void testListenerInvokedDirectlyAfterResultSet() {
+        DefaultSshFuture future = new DefaultSshFuture(getCurrentTestName(), null);
+        AtomicInteger listenerCount = new AtomicInteger(0);
+        Object expected = new Object();
+        SshFutureListener listener = f -> {
+            assertSame("Mismatched future instance", future, f);
+            assertSame("Mismatched value object", expected, future.getValue());
+            listenerCount.incrementAndGet();
+        };
+        future.setValue(expected);
+
+        future.addListener(listener);
+        assertEquals("Mismatched number of registered listeners", 0, future.getNumRegisteredListeners());
+        assertEquals("Listener not invoked", 1, listenerCount.get());
+    }
+
+    @Test
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    public void testAddAndRemoveRegisteredListenersBeforeResultSet() {
+        DefaultSshFuture future = new DefaultSshFuture(getCurrentTestName(), null);
+        SshFutureListener listener = Mockito.mock(SshFutureListener.class);
+        for (int index = 1; index <= Byte.SIZE; index++) {
+            future.addListener(listener);
+            assertEquals("Mismatched number of added listeners", index, future.getNumRegisteredListeners());
+        }
+
+        for (int index = future.getNumRegisteredListeners() - 1; index >= 0; index--) {
+            future.removeListener(listener);
+            assertEquals("Mismatched number of remaining listeners", index, future.getNumRegisteredListeners());
+        }
+    }
+
+    @Test
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    public void testListenerNotRemovedIfResultSet() {
+        DefaultSshFuture future = new DefaultSshFuture(getCurrentTestName(), null);
+        AtomicInteger listenerCount = new AtomicInteger(0);
+        Object expected = new Object();
+        SshFutureListener listener = f -> {
+            assertSame("Mismatched future instance", future, f);
+            assertSame("Mismatched value object", expected, future.getValue());
+            listenerCount.incrementAndGet();
+        };
+        future.addListener(listener);
+        future.setValue(expected);
+        assertEquals("Mismatched number of registered listeners", 1, future.getNumRegisteredListeners());
+        assertEquals("Listener not invoked", 1, listenerCount.get());
+
+        future.removeListener(listener);
+        assertEquals("Mismatched number of remaining listeners", 1, future.getNumRegisteredListeners());
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/keyprovider/KeyPairProviderTest.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/test/java/org/apache/sshd/common/keyprovider/KeyPairProviderTest.java b/sshd-common/src/test/java/org/apache/sshd/common/keyprovider/KeyPairProviderTest.java
new file mode 100644
index 0000000..021796b
--- /dev/null
+++ b/sshd-common/src/test/java/org/apache/sshd/common/keyprovider/KeyPairProviderTest.java
@@ -0,0 +1,79 @@
+/*
+ * 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.keyprovider;
+
+import java.security.KeyPair;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.function.Function;
+
+import org.apache.sshd.common.util.GenericUtils;
+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;
+import org.mockito.Mockito;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Category({ NoIoTestCase.class })
+public class KeyPairProviderTest extends JUnitTestSupport {
+    public KeyPairProviderTest() {
+        super();
+    }
+
+    @Test
+    public void testEmptyKeyProvider() {
+        KeyPairProvider provider = KeyPairProvider.EMPTY_KEYPAIR_PROVIDER;
+        assertTrue("Non empty loaded keys", GenericUtils.isEmpty(provider.loadKeys()));
+        assertTrue("Non empty key type", GenericUtils.isEmpty(provider.getKeyTypes()));
+
+        for (String keyType : new String[]{null, "", getCurrentTestName()}) {
+            assertNull("Unexpected key-pair loaded for type='" + keyType + "'", provider.loadKey(keyType));
+        }
+    }
+
+    @Test
+    public void testMapToKeyPairProvider() {
+        PublicKey pubKey = Mockito.mock(PublicKey.class);
+        PrivateKey prvKey = Mockito.mock(PrivateKey.class);
+        String[] testKeys = {getCurrentTestName(), getClass().getSimpleName()};
+        Map<String, KeyPair> pairsMap = GenericUtils.toSortedMap(
+            Arrays.asList(testKeys),
+            Function.identity(),
+            k -> new KeyPair(pubKey, prvKey),
+            String.CASE_INSENSITIVE_ORDER);
+
+        KeyPairProvider provider = MappedKeyPairProvider.MAP_TO_KEY_PAIR_PROVIDER.apply(pairsMap);
+        assertEquals("Key types", pairsMap.keySet(), provider.getKeyTypes());
+        assertEquals("Key pairs", pairsMap.values(), provider.loadKeys());
+
+        pairsMap.forEach((keyType, expected) -> {
+            KeyPair actual = provider.loadKey(keyType);
+            assertSame(keyType, expected, actual);
+        });
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/mac/BuiltinMacsTest.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/test/java/org/apache/sshd/common/mac/BuiltinMacsTest.java b/sshd-common/src/test/java/org/apache/sshd/common/mac/BuiltinMacsTest.java
new file mode 100644
index 0000000..0d50c41
--- /dev/null
+++ b/sshd-common/src/test/java/org/apache/sshd/common/mac/BuiltinMacsTest.java
@@ -0,0 +1,166 @@
+/*
+ * 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.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Random;
+import java.util.Set;
+
+import org.apache.sshd.common.NamedResource;
+import org.apache.sshd.common.mac.BuiltinMacs.ParseResult;
+import org.apache.sshd.common.util.GenericUtils;
+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;
+import org.mockito.Mockito;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Category({ NoIoTestCase.class })
+public class BuiltinMacsTest extends JUnitTestSupport {
+    public BuiltinMacsTest() {
+        super();
+    }
+
+    @Test
+    public void testFromName() {
+        for (BuiltinMacs expected : BuiltinMacs.VALUES) {
+            String name = expected.getName();
+            BuiltinMacs actual = BuiltinMacs.fromFactoryName(name);
+            assertSame(name, expected, actual);
+        }
+    }
+
+    @Test
+    public void testAllConstantsCovered() throws Exception {
+        Set<BuiltinMacs> avail = EnumSet.noneOf(BuiltinMacs.class);
+        Field[] fields = BuiltinMacs.Constants.class.getFields();
+        for (Field f : fields) {
+            String name = (String) f.get(null);
+            BuiltinMacs value = BuiltinMacs.fromFactoryName(name);
+            assertNotNull("No match found for " + name, value);
+            assertTrue(name + " re-specified", avail.add(value));
+        }
+
+        assertEquals("Incomplete coverage", BuiltinMacs.VALUES, avail);
+    }
+
+    @Test
+    public void testParseMacsList() {
+        List<String> builtin = NamedResource.getNameList(BuiltinMacs.VALUES);
+        List<String> unknown = Arrays.asList(getClass().getPackage().getName(), getClass().getSimpleName(), getCurrentTestName());
+        Random rnd = new Random();
+        for (int index = 0; index < (builtin.size() + unknown.size()); index++) {
+            Collections.shuffle(builtin, rnd);
+            Collections.shuffle(unknown, rnd);
+
+            List<String> weavedList = new ArrayList<>(builtin.size() + unknown.size());
+            for (int bIndex = 0, uIndex = 0; (bIndex < builtin.size()) || (uIndex < unknown.size());) {
+                boolean useBuiltin = false;
+                if (bIndex < builtin.size()) {
+                    useBuiltin = uIndex >= unknown.size() || rnd.nextBoolean();
+                }
+
+                if (useBuiltin) {
+                    weavedList.add(builtin.get(bIndex));
+                    bIndex++;
+                } else if (uIndex < unknown.size()) {
+                    weavedList.add(unknown.get(uIndex));
+                    uIndex++;
+                }
+            }
+
+            String fullList = GenericUtils.join(weavedList, ',');
+            ParseResult result = BuiltinMacs.parseMacsList(fullList);
+            List<String> parsed = NamedResource.getNameList(result.getParsedFactories());
+            List<String> missing = result.getUnsupportedFactories();
+
+            // makes sure not only that the contents are the same but also the order
+            assertListEquals(fullList + "[parsed]", builtin, parsed);
+            assertListEquals(fullList + "[unsupported]", unknown, missing);
+        }
+    }
+
+    @Test
+    public void testResolveFactoryOnBuiltinValues() {
+        for (MacFactory expected : BuiltinMacs.VALUES) {
+            String name = expected.getName();
+            MacFactory actual = BuiltinMacs.resolveFactory(name);
+            assertSame(name, expected, actual);
+        }
+    }
+
+    @Test
+    public void testNotAllowedToRegisterBuiltinFactories() {
+        for (MacFactory expected : BuiltinMacs.VALUES) {
+            try {
+                BuiltinMacs.registerExtension(expected);
+                fail("Unexpected success for " + expected.getName());
+            } catch (IllegalArgumentException e) {
+                // expected - ignored
+            }
+        }
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testNotAllowedToOverrideRegisteredFactories() {
+        MacFactory expected = Mockito.mock(MacFactory.class);
+        Mockito.when(expected.getName()).thenReturn(getCurrentTestName());
+
+        String name = expected.getName();
+        try {
+            for (int index = 1; index <= Byte.SIZE; index++) {
+                BuiltinMacs.registerExtension(expected);
+                assertEquals("Unexpected success at attempt #" + index, 1, index);
+            }
+        } finally {
+            BuiltinMacs.unregisterExtension(name);
+        }
+    }
+
+    @Test
+    public void testResolveFactoryOnRegisteredExtension() {
+        MacFactory expected = Mockito.mock(MacFactory.class);
+        Mockito.when(expected.getName()).thenReturn(getCurrentTestName());
+
+        String name = expected.getName();
+        try {
+            assertNull("Extension already registered", BuiltinMacs.resolveFactory(name));
+            BuiltinMacs.registerExtension(expected);
+
+            MacFactory actual = BuiltinMacs.resolveFactory(name);
+            assertSame("Mismatched resolved instance", expected, actual);
+        } finally {
+            MacFactory actual = BuiltinMacs.unregisterExtension(name);
+            assertSame("Mismatched unregistered instance", expected, actual);
+            assertNull("Extension not un-registered", BuiltinMacs.resolveFactory(name));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/mac/MacVectorsTest.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/test/java/org/apache/sshd/common/mac/MacVectorsTest.java b/sshd-common/src/test/java/org/apache/sshd/common/mac/MacVectorsTest.java
new file mode 100644
index 0000000..f330d22
--- /dev/null
+++ b/sshd-common/src/test/java/org/apache/sshd/common/mac/MacVectorsTest.java
@@ -0,0 +1,311 @@
+/*
+ * 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.nio.charset.StandardCharsets;
+import java.util.AbstractMap.SimpleImmutableEntry;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+import org.apache.sshd.common.Factory;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.ValidateUtils;
+import org.apache.sshd.common.util.buffer.BufferUtils;
+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;
+
+/**
+ * @see <A HREF="https://tools.ietf.org/html/rfc4231">RFC 4321</A>
+ * @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 MacVectorsTest extends JUnitTestSupport {
+    private final VectorSeed seed;
+    private final Factory<? extends Mac> macFactory;
+    private final byte[] expected;
+
+    public MacVectorsTest(VectorSeed seed, String factoryName, String expected) {
+        this.seed = Objects.requireNonNull(seed, "No seed");
+        this.macFactory = ValidateUtils.checkNotNull(BuiltinMacs.fromFactoryName(factoryName), "Unknown MAC: %s", factoryName);
+        this.expected = BufferUtils.decodeHex(BufferUtils.EMPTY_HEX_SEPARATOR, expected);
+    }
+
+    @Parameters(name = "factory={1}, expected={2}, seed={0}")
+    public static Collection<Object[]> parameters() {
+        List<Object[]> ret = new ArrayList<>();
+        for (VectorTestData vector : Collections.unmodifiableList(
+                Arrays.asList(
+                    ///////////////// Test Cases for HMAC-MD5 ///////////////////////
+                    // see https://tools.ietf.org/html/rfc2202
+                    new VectorTestData("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", false, "Hi There",
+                       Arrays.asList(new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_MD5,     // test case 1
+                                                "9294727a3638bb1c13f48ef8158bfc9d"))),
+                    new VectorTestData("Jefe", "what do ya want for nothing?",
+                        Arrays.asList(new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_MD5,    // test case 2
+                                                 "750c783e6ab0b503eaa86e310a5db738"))),
+                    new VectorTestData("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", false, repeat("dd", 50), false,
+                        Arrays.asList(new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_MD5,    // test case 3
+                                                 "56be34521d144c88dbb8c733f0e8b3f6"))),
+                    /* TODO see why it fails
+                    new VectorTestData("0102030405060708090a0b0c0d0e0f10111213141516171819", false, repeat("cd", 50), false,
+                        Arrays.asList(new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_MD5,    // test case 4
+                                                 "697eaf0aca3a3aea3a75164746ffaa79"))),
+                    */
+                    new VectorTestData("0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c", false, "Test With Truncation",
+                        Arrays.asList(new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_MD5,    // test case 5
+                                                 "56461ef2342edc00f9bab995690efd4c"),
+                                      new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_MD5_96,
+                                                 "56461ef2342edc00f9bab995"))),
+                    /* TODO see why it fails
+                    new VectorTestData(repeat("aa", 80), false, "Test Using Larger Than Block-Size Key - Hash Key First",
+                        Arrays.asList(new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_MD5,    // test case 6
+                                                 "6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd"))),
+                    */
+                    /* TODO see why it fails
+                    new VectorTestData(repeat("aa", 80), false, "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data",
+                        Arrays.asList(new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_MD5,    // test case 7
+                                                 "6f630fad67cda0ee1fb1f562db3aa53e"))),
+                    */
+                    ///////////////// Test Cases for HMAC-SHA-1 ///////////////////////
+                    // see https://tools.ietf.org/html/rfc2202
+                    new VectorTestData("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", false, "Hi There",
+                        Arrays.asList(new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_SHA1,     // test case 1
+                                                 "b617318655057264e28bc0b6fb378c8ef146be00"))),
+                    new VectorTestData("Jefe", "what do ya want for nothing?",
+                        Arrays.asList(new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_SHA1,     // test case 2
+                                                 "effcdf6ae5eb2fa2d27416d5f184df9c259a7c79"))),
+                    new VectorTestData("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", false, repeat("dd", 50), false,
+                        Arrays.asList(new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_SHA1,     // test case 3
+                                                 "125d7342b9ac11cd91a39af48aa17b4f63f175d3"))),
+                    /* TODO see why it fails
+                    new VectorTestData("0102030405060708090a0b0c0d0e0f10111213141516171819", false, repeat("cd", 50), false,
+                        Arrays.asList(new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_SHA1,     // test case 4
+                                                 "4c9007f4026250c6bc8414f9bf50c86c2d7235da"))),
+                    */
+                    new VectorTestData("0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c", false, "Test With Truncation",
+                        Arrays.asList(new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_SHA1,     // test case 5
+                                                 "4c1a03424b55e07fe7f27be1d58bb9324a9a5a04"),
+                                      new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_SHA1_96,
+                                                 "4c1a03424b55e07fe7f27be1"))),
+                    /* TODO see why this fails
+                    new VectorTestData(repeat("aa", 80), false, "Test Using Larger Than Block-Size Key - Hash Key First",
+                        Arrays.asList(new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_SHA1,     // test case 6
+                                                 "aa4ae5e15272d00e95705637ce8a3b55ed402112"))),
+                    */
+
+                    /* TODO see why it fails
+                    new VectorTestData(repeat("aa", 80), false, "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data",
+                        Arrays.asList(new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_SHA1,     // test case 7
+                                                 "4c1a03424b55e07fe7f27be1d58bb9324a9a5a04"),
+                                      new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_SHA1_96,
+                                                 "4c1a03424b55e07fe7f27be1"))),
+                    */
+
+                    /* TODO see why it fails
+                    new VectorTestData(repeat("aa", 80), false, "Test Using Larger Than Block-Size Key - Hash Key First",
+                        Arrays.asList(new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_SHA1,     // test case 8
+                                                 "aa4ae5e15272d00e95705637ce8a3b55ed402112"))),
+                    */
+
+                    /* TODO see why it fails
+                    new VectorTestData(repeat("aa", 80), false, "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data",
+                        Arrays.asList(new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_SHA1,     // test case 9
+                                                 "e8e99d0f45237d786d6bbaa7965c7808bbff1a91"))),
+                    */
+
+                    ///////////////// Test Cases for HMAC-SHA-2 ///////////////////////
+                    // see https://tools.ietf.org/html/rfc4231
+                    new VectorTestData(repeat("0b", 20), false, "Hi There",
+                       // test case 1
+                       Arrays.asList(
+                           new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_SHA2_256,
+                                      "b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7"),
+                           new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_SHA2_512,
+                                      "87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b30545e17cdedaa833b7d6b8a702038b274eaea3f4e4be9d914eeb61f1702e696c203a126854"))),
+                    new VectorTestData("Jefe", "what do ya want for nothing?",
+                        // test case 2
+                        Arrays.asList(
+                            new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_SHA2_256,
+                                       "5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843"),
+                            new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_SHA2_512,
+                                       "164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea2505549758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737"))),
+                    new VectorTestData(repeat("aa", 20), false, repeat("dd", 50), false,
+                        // test case 3
+                        Arrays.asList(
+                            new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_SHA2_256,
+                                       "773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe"),
+                            new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_SHA2_512,
+                                       "fa73b0089d56a284efb0f0756c890be9b1b5dbdd8ee81a3655f83e33b2279d39bf3e848279a722c806b485a47e67c807b946a337bee8942674278859e13292fb"))),
+                    new VectorTestData("0102030405060708090a0b0c0d0e0f10111213141516171819", false, repeat("cd", 50), false,
+                        // test case 4
+                        Arrays.asList(
+                            new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_SHA2_256,
+                                       "82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b"),
+                            new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_SHA2_512,
+                                       "b0ba465637458c6990e5a8c5f61d4af7e576d97ff94b872de76f8050361ee3dba91ca5c11aa25eb4d679275cc5788063a5f19741120c4f2de2adebeb10a298dd"))),
+
+                    /* TODO see why it fails
+                    new VectorTestData(repeat("0c", 20), false, "Test With Truncation",
+                        Arrays.asList(   // test case 5
+                            new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_SHA2_256,
+                                       "a3b6167473100ee06e0c796c2955552b"),
+                            new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_SHA2_512,
+                                       "415fad6271580a531d4179bc891d87a6"))),
+                    */
+
+                    /* TODO see why it fails
+                    new VectorTestData(repeat("aa", 131), false, "Test Using Larger Than Block-Size Key - Hash Key First",
+                        Arrays.asList(   // test case 6
+                            new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_SHA2_256,
+                                       "60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54"),
+                            new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_SHA2_512,
+                                       "80b24263c7c1a3ebb71493c1dd7be8b49b46d1f41b4aeec1121b013783f8f3526b56d037e05f2598bd0fd2215d6a1e5295e64f73f63f0aec8b915a985d786598"))),
+                    */
+
+                    /* TODO see why it fails
+                    new VectorTestData(repeat("aa", 131), false, "This is a test using a larger than block-size"
+                                                               + " key and a larger than block-size data."
+                                                               + " The key needs to be hashed before being used"
+                                                               + " by the HMAC algorithm",
+                        Arrays.asList(   // test case 7
+                            new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_SHA2_256,
+                                       "9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2"),
+                            new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_SHA2_512,
+                                       "e37b6a775dc87dbaa4dfa9f96e5e3ffddebd71f8867289865df5a32d20cdc944b6022cac3c4982b10d5eeb55c3e4de15134676fb6de0446065c97440fa8c6a58")))
+                    */
+
+                    // mark end
+                    new VectorTestData("", false, "", false, Collections.emptyList())))) {
+            for (Map.Entry<String, String> tc : vector.getResults()) {
+                ret.add(new Object[]{vector, tc.getKey(), tc.getValue()});
+            }
+        }
+
+        return ret;
+    }
+
+    @Test
+    public void testStandardVectorMac() throws Exception {
+        Mac mac = macFactory.create();
+        mac.init(seed.getKey());
+        mac.update(seed.getData());
+
+        byte[] actual = new byte[mac.getBlockSize()];
+        mac.doFinal(actual);
+        assertArrayEquals("Mismatched results for actual=" + BufferUtils.toHex(BufferUtils.EMPTY_HEX_SEPARATOR, actual), expected, actual);
+    }
+
+    private static class VectorSeed {
+        private final byte[] key;
+        private final String keyString;
+        private final byte[] data;
+        private final String dataString;
+
+        VectorSeed(String key, String data) {
+            this.key = key.getBytes(StandardCharsets.UTF_8);
+            this.keyString = key;
+            this.data = data.getBytes(StandardCharsets.UTF_8);
+            this.dataString = data;
+        }
+
+        VectorSeed(String key, boolean useKeyString, String data) {
+            this.key = BufferUtils.decodeHex(BufferUtils.EMPTY_HEX_SEPARATOR, key);
+            this.keyString = useKeyString ? new String(this.key, StandardCharsets.UTF_8) : key;
+            this.data = data.getBytes(StandardCharsets.UTF_8);
+            this.dataString = data;
+        }
+
+        VectorSeed(String key, boolean useKeyString, String data, boolean useDataString) {
+            this.key = BufferUtils.decodeHex(BufferUtils.EMPTY_HEX_SEPARATOR, key);
+            this.keyString = useKeyString ? new String(this.key, StandardCharsets.UTF_8) : key;
+            this.data = BufferUtils.decodeHex(BufferUtils.EMPTY_HEX_SEPARATOR, data);
+            this.dataString = useDataString ? new String(this.data, StandardCharsets.UTF_8) : data;
+        }
+
+        public byte[] getKey() {
+            return key.clone(); // clone to avoid inadvertent change
+        }
+
+        public String getKeyString() {
+            return keyString;
+        }
+
+        public byte[] getData() {
+            return data.clone();  // clone to avoid inadvertent change
+        }
+
+        public String getDataString() {
+            return dataString;
+        }
+
+        @Override
+        public String toString() {
+            return "key=" + trimToLength(getKeyString(), 32) + ", data=" + trimToLength(getDataString(), 32);
+        }
+
+        private static CharSequence trimToLength(CharSequence csq, int maxLen) {
+            if (GenericUtils.length(csq) <= maxLen) {
+                return csq;
+            }
+
+            return csq.subSequence(0, maxLen) + "...";
+        }
+    }
+
+    private static class VectorTestData extends VectorSeed {
+        private final Collection<Map.Entry<String, String>> results;
+
+        VectorTestData(String key, String data, Collection<Map.Entry<String, String>> results) {
+            super(key, data);
+            this.results = results;
+        }
+
+        VectorTestData(String key, boolean useKeyString, String data, Collection<Map.Entry<String, String>> results) {
+            super(key, useKeyString, data);
+            this.results = results;
+        }
+
+        VectorTestData(String key, boolean useKeyString, String data, boolean useDataString, Collection<Map.Entry<String, String>> results) {
+            super(key, useKeyString, data, useDataString);
+            this.results = results;
+        }
+
+        public Collection<Map.Entry<String, String>> getResults() {
+            return results;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/random/RandomFactoryTest.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/test/java/org/apache/sshd/common/random/RandomFactoryTest.java b/sshd-common/src/test/java/org/apache/sshd/common/random/RandomFactoryTest.java
new file mode 100644
index 0000000..08872d9
--- /dev/null
+++ b/sshd-common/src/test/java/org/apache/sshd/common/random/RandomFactoryTest.java
@@ -0,0 +1,83 @@
+/*
+ * 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.random;
+
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.concurrent.TimeUnit;
+
+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.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 RandomFactoryTest extends JUnitTestSupport {
+    private final RandomFactory factory;
+
+    public RandomFactoryTest(RandomFactory factory) {
+        this.factory = factory;
+    }
+
+    @Parameters(name = "type={0}")
+    public static Collection<Object[]> parameters() {
+        Collection<RandomFactory> testCases = new LinkedList<>();
+        testCases.add(JceRandomFactory.INSTANCE);
+        if (SecurityUtils.isBouncyCastleRegistered()) {
+            testCases.add(SecurityUtils.getRandomFactory());
+        } else {
+            System.out.println("Skip BouncyCastleRandomFactory - unsupported");
+        }
+
+        return parameterize(testCases);
+    }
+
+    @Test
+    public void testRandomFactory() {
+        Assume.assumeTrue("Skip unsupported factory: " + factory.getName(), factory.isSupported());
+        long t = testRandom(factory.create());
+        System.out.println(factory.getName() + " duration: " + t + " " + TimeUnit.MICROSECONDS);
+    }
+
+    // returns duration in microseconds
+    private static long testRandom(Random random) {
+        byte[] bytes = new byte[32];
+        long l0 = System.nanoTime();
+        for (int i = 0; i < 1000; i++) {
+            random.fill(bytes, 8, 16);
+        }
+        long l1 = System.nanoTime();
+        return TimeUnit.NANOSECONDS.toMicros(l1 - l0);
+    }
+}