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

[1/2] mina-sshd git commit: [SSHD-495] Move all code that calls Bouncycastle code to SecurityUtils

Repository: mina-sshd
Updated Branches:
  refs/heads/master 189d8cb90 -> 06d37a2d5


http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/06d37a2d/sshd-core/src/main/java/org/apache/sshd/server/sftp/SftpSubsystem.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/sftp/SftpSubsystem.java b/sshd-core/src/main/java/org/apache/sshd/server/sftp/SftpSubsystem.java
index e3f4152..d696a4f 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/sftp/SftpSubsystem.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/sftp/SftpSubsystem.java
@@ -797,7 +797,7 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
                 Path f = resolveFile(path);
                 Path abs = f.toAbsolutePath();
                 Path p = abs.normalize();
-                Boolean status = IoUtils.checkFileExists(p, IoUtils.EMPTY_OPTIONS);
+                Boolean status = IoUtils.checkFileExists(p, IoUtils.EMPTY_LINK_OPTIONS);
                 if (status == null) {
                     p = handleUnknownRealPathStatus(path, abs, p);
                 } else if (!status.booleanValue()) {

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/06d37a2d/sshd-core/src/test/java/org/apache/sshd/SinglePublicKeyAuthTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/SinglePublicKeyAuthTest.java b/sshd-core/src/test/java/org/apache/sshd/SinglePublicKeyAuthTest.java
index bfd170e..0961bc5 100644
--- a/sshd-core/src/test/java/org/apache/sshd/SinglePublicKeyAuthTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/SinglePublicKeyAuthTest.java
@@ -58,9 +58,15 @@ public class SinglePublicKeyAuthTest extends BaseTestSupport {
     private SshServer sshd;
     private int port = 0;
     private KeyPair pairRsa = Utils.createTestHostKeyProvider().loadKey(KeyPairProvider.SSH_RSA);
-    private KeyPair pairRsaBad = new SimpleGeneratorHostKeyProvider(null, "RSA").loadKey(KeyPairProvider.SSH_RSA);
+    private KeyPair pairRsaBad;
     private PublickeyAuthenticator delegate;
 
+    public SinglePublicKeyAuthTest() {
+        SimpleGeneratorHostKeyProvider provider = new SimpleGeneratorHostKeyProvider();
+        provider.setAlgorithm("RSA");
+        pairRsaBad = provider.loadKey(KeyPairProvider.SSH_RSA);
+    }
+
     @Before
     public void setUp() throws Exception {
         sshd = SshServer.setUpDefaultServer();

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/06d37a2d/sshd-core/src/test/java/org/apache/sshd/client/ClientTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/ClientTest.java b/sshd-core/src/test/java/org/apache/sshd/client/ClientTest.java
index 8285002..571255f 100644
--- a/sshd-core/src/test/java/org/apache/sshd/client/ClientTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/client/ClientTest.java
@@ -679,8 +679,11 @@ public class ClientTest extends BaseTestSupport {
         client.setUserAuthFactories(Arrays.<NamedFactory<UserAuth>>asList(UserAuthPublicKey.UserAuthPublicKeyFactory.INSTANCE));
         client.start();
 
+        SimpleGeneratorHostKeyProvider provider = new SimpleGeneratorHostKeyProvider();
+        provider.setAlgorithm("RSA");
+
         try(ClientSession session = client.connect(getCurrentTestName(), "localhost", port).await().getSession()) {
-            session.addPublicKeyIdentity(new SimpleGeneratorHostKeyProvider(null, "RSA").loadKey(KeyPairProvider.SSH_RSA));
+            session.addPublicKeyIdentity(provider.loadKey(KeyPairProvider.SSH_RSA));
             session.addPublicKeyIdentity(pair);
             session.auth().verify(5L, TimeUnit.SECONDS);
         } finally {

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/06d37a2d/sshd-core/src/test/java/org/apache/sshd/client/session/ClientSessionImplTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/session/ClientSessionImplTest.java b/sshd-core/src/test/java/org/apache/sshd/client/session/ClientSessionImplTest.java
index c17e711..5805910 100644
--- a/sshd-core/src/test/java/org/apache/sshd/client/session/ClientSessionImplTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/client/session/ClientSessionImplTest.java
@@ -31,7 +31,7 @@ import org.apache.sshd.common.Factory;
 import org.apache.sshd.common.ServiceFactory;
 import org.apache.sshd.common.forward.DefaultTcpipForwarderFactory;
 import org.apache.sshd.common.io.IoSession;
-import org.apache.sshd.common.random.JceRandom;
+import org.apache.sshd.common.random.JceRandomFactory;
 import org.apache.sshd.common.random.Random;
 import org.apache.sshd.common.random.SingletonRandomFactory;
 import org.apache.sshd.util.BaseTestSupport;
@@ -54,7 +54,7 @@ public class ClientSessionImplTest extends BaseTestSupport {
         ClientFactoryManager client = Mockito.mock(ClientFactoryManager.class);
         Mockito.when(client.getTcpipForwarderFactory()).thenReturn(DefaultTcpipForwarderFactory.INSTANCE);
         
-        Factory<Random> randomFactory = new SingletonRandomFactory(JceRandom.JceRandomFactory.INSTANCE);
+        Factory<Random> randomFactory = new SingletonRandomFactory(JceRandomFactory.INSTANCE);
         Mockito.when(client.getRandomFactory()).thenReturn(randomFactory);
         
         List<ServiceFactory> serviceFactories = Arrays.asList(

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/06d37a2d/sshd-core/src/test/java/org/apache/sshd/common/cipher/CipherTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/common/cipher/CipherTest.java b/sshd-core/src/test/java/org/apache/sshd/common/cipher/CipherTest.java
index bc2d2ff..3cacfbc 100644
--- a/sshd-core/src/test/java/org/apache/sshd/common/cipher/CipherTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/common/cipher/CipherTest.java
@@ -23,9 +23,6 @@ import java.io.OutputStream;
 import java.util.Arrays;
 
 import org.apache.sshd.common.NamedFactory;
-import org.apache.sshd.common.cipher.BuiltinCiphers;
-import org.apache.sshd.common.cipher.Cipher;
-import org.apache.sshd.common.random.BouncyCastleRandom;
 import org.apache.sshd.common.random.Random;
 import org.apache.sshd.server.SshServer;
 import org.apache.sshd.util.BaseTestSupport;
@@ -99,7 +96,7 @@ public class CipherTest extends BaseTestSupport {
 
     @Test
     public void loadTest() throws Exception {
-        Random random = new BouncyCastleRandom();
+        Random random = Utils.getRandomizerInstance();
         loadTest(BuiltinCiphers.aes128cbc, random);
         loadTest(BuiltinCiphers.blowfishcbc, random);
         loadTest(BuiltinCiphers.tripledescbc, random);

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/06d37a2d/sshd-core/src/test/java/org/apache/sshd/common/mac/MacTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/common/mac/MacTest.java b/sshd-core/src/test/java/org/apache/sshd/common/mac/MacTest.java
index ea9c555..3b61822 100644
--- a/sshd-core/src/test/java/org/apache/sshd/common/mac/MacTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/common/mac/MacTest.java
@@ -25,9 +25,6 @@ import java.util.Arrays;
 import org.apache.sshd.common.NamedFactory;
 import org.apache.sshd.common.cipher.BuiltinCiphers;
 import org.apache.sshd.common.cipher.Cipher;
-import org.apache.sshd.common.mac.BuiltinMacs;
-import org.apache.sshd.common.mac.Mac;
-import org.apache.sshd.common.random.BouncyCastleRandom;
 import org.apache.sshd.common.random.Random;
 import org.apache.sshd.server.SshServer;
 import org.apache.sshd.util.BaseTestSupport;
@@ -94,7 +91,7 @@ public class MacTest extends BaseTestSupport {
 
     @Test
     public void loadTest() throws Exception {
-        Random random = new BouncyCastleRandom();
+        Random random = Utils.getRandomizerInstance();
         loadTest(BuiltinCiphers.aes128cbc, random);
         loadTest(BuiltinCiphers.blowfishcbc, random);
         loadTest(BuiltinCiphers.tripledescbc, random);

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/06d37a2d/sshd-core/src/test/java/org/apache/sshd/common/random/RandomTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/common/random/RandomTest.java b/sshd-core/src/test/java/org/apache/sshd/common/random/RandomTest.java
index bd293f6..3f0511c 100644
--- a/sshd-core/src/test/java/org/apache/sshd/common/random/RandomTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/common/random/RandomTest.java
@@ -18,10 +18,10 @@
  */
 package org.apache.sshd.common.random;
 
-import org.apache.sshd.common.random.BouncyCastleRandom;
-import org.apache.sshd.common.random.JceRandom;
-import org.apache.sshd.common.random.Random;
+import org.apache.sshd.common.util.SecurityUtils;
 import org.apache.sshd.util.BaseTestSupport;
+import org.apache.sshd.util.Utils;
+import org.junit.Assume;
 import org.junit.FixMethodOrder;
 import org.junit.Test;
 import org.junit.runners.MethodSorters;
@@ -33,20 +33,24 @@ import org.junit.runners.MethodSorters;
  */
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
 public class RandomTest extends BaseTestSupport {
+    public RandomTest() {
+        super();
+    }
 
     @Test
     public void testJce() {
-        long t = test(new JceRandom());
+        long t = testRandom(new JceRandom());
         System.out.println("JCE: " + t + " micro");
     }
 
     @Test
     public void testBc() {
-        long t = test(new BouncyCastleRandom());
+        Assume.assumeTrue("BouncyCastle not registered", SecurityUtils.isBouncyCastleRegistered());
+        long t = testRandom(Utils.getRandomizerInstance());
         System.out.println("BC:  " + t + " micro");
     }
 
-    protected long test(Random random) {
+    private static long testRandom(Random random) {
         byte[] bytes = new byte[32];
         long l0 = System.nanoTime();
         for (int i = 0; i < 1000; i++) {

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/06d37a2d/sshd-core/src/test/java/org/apache/sshd/common/util/SecurityUtilsTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/common/util/SecurityUtilsTest.java b/sshd-core/src/test/java/org/apache/sshd/common/util/SecurityUtilsTest.java
new file mode 100644
index 0000000..7184c0e
--- /dev/null
+++ b/sshd-core/src/test/java/org/apache/sshd/common/util/SecurityUtilsTest.java
@@ -0,0 +1,173 @@
+/*
+ * 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;
+
+import java.io.File;
+import java.io.IOException;
+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.Collections;
+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.keyprovider.AbstractClassLoadableResourceKeyPairProvider;
+import org.apache.sshd.common.keyprovider.AbstractFileKeyPairProvider;
+import org.apache.sshd.common.keyprovider.AbstractResourceKeyPairProvider;
+import org.apache.sshd.util.BaseTestSupport;
+import org.junit.Assume;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class SecurityUtilsTest extends BaseTestSupport {
+    private static final String DEFAULT_PASSWORD="super secret passphrase";
+    private static final FilePasswordProvider passwordProvider = new FilePasswordProvider() {
+            @Override
+            public String getPassword(String file) throws IOException {
+                return DEFAULT_PASSWORD;
+            }
+        };
+
+    public SecurityUtilsTest() {
+        super();
+    }
+
+    @Test
+    public void testLoadEncryptedDESPrivateKey() {
+        Assume.assumeTrue("Bouncycastle not registered", SecurityUtils.isBouncyCastleRegistered());
+        testLoadEncryptedRSAPrivateKey("DES-EDE3");
+    }
+
+    @Test
+    public void testLoadEncryptedAESPrivateKey() {
+        Assume.assumeTrue("Bouncycastle not registered", SecurityUtils.isBouncyCastleRegistered());
+        for (BuiltinCiphers c : new BuiltinCiphers[] {
+                BuiltinCiphers.aes128cbc, BuiltinCiphers.aes192cbc, BuiltinCiphers.aes256cbc }) {
+            if (!c.isSupported()) {
+                System.out.println("Skip unsupported encryption scheme: " + c.getName());
+                continue;
+            }
+            
+            testLoadEncryptedRSAPrivateKey("AES-" + c.getKeySize());
+        }
+    }
+
+    private KeyPair testLoadEncryptedRSAPrivateKey(String algorithm) {
+        return testLoadRSAPrivateKey(DEFAULT_PASSWORD.replace(' ', '-') + "-RSA-" + algorithm.toUpperCase() + "-key");
+    }
+
+    @Test
+    public void testLoadUnencryptedRSAPrivateKey() {
+        Assume.assumeTrue("Bouncycastle not registered", SecurityUtils.isBouncyCastleRegistered());
+        testLoadRSAPrivateKey(getClass().getSimpleName() + "-RSA-KeyPair");
+    }
+
+    @Test
+    public void testLoadUnencryptedDSSPrivateKey() {
+        Assume.assumeTrue("Bouncycastle not registered", SecurityUtils.isBouncyCastleRegistered());
+        testLoadDSSPrivateKey(getClass().getSimpleName() + "-DSA-KeyPair");
+    }
+
+    private KeyPair testLoadDSSPrivateKey(String name) {
+        return testLoadPrivateKey(name, DSAPublicKey.class, DSAPrivateKey.class);
+    }
+
+    @Test
+    public void testLoadUnencryptedECPrivateKey() {
+        Assume.assumeTrue("Bouncycastle not registered", SecurityUtils.isBouncyCastleRegistered());
+        Assume.assumeTrue("EC not supported", SecurityUtils.hasEcc());
+        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) {
+        return testLoadPrivateKey(name, ECPublicKey.class, ECPrivateKey.class);
+    }
+
+    private KeyPair testLoadRSAPrivateKey(String name) {
+        return testLoadPrivateKey(name, RSAPublicKey.class, RSAPrivateKey.class);
+    }
+
+    private KeyPair testLoadPrivateKey(String name, Class<? extends PublicKey> pubType, Class<? extends PrivateKey> prvType) {
+        File folder = getClassResourcesFolder(TEST_SUBFOLDER);
+        KeyPair kpFile = testLoadPrivateKeyFile(new File(folder, name), pubType, prvType);
+        Class<?> clazz = getClass();
+        Package pkg = clazz.getPackage();
+        KeyPair kpResource = testLoadPrivateKeyResource(pkg.getName().replace('.', '/') + "/" + name, pubType, prvType);
+
+        assertTrue("Mismatched key pairs values", KeyUtils.compareKeyPairs(kpFile, kpResource));
+        return kpResource;
+    }
+
+    private static KeyPair testLoadPrivateKeyResource(String name, Class<? extends PublicKey> pubType, Class<? extends PrivateKey> prvType) {
+        AbstractClassLoadableResourceKeyPairProvider  provider = SecurityUtils.createClassLoadableResourceKeyPairProvider();
+        provider.setResources(Collections.singletonList(name));
+        return testLoadPrivateKey(name, provider, pubType, prvType);
+    }
+
+    private static KeyPair testLoadPrivateKeyFile(File file, Class<? extends PublicKey> pubType, Class<? extends PrivateKey> prvType) {
+        AbstractFileKeyPairProvider provider = SecurityUtils.createFileKeyPairProvider();
+        provider.setFiles(Collections.singletonList(file));
+        return testLoadPrivateKey(file.getAbsolutePath(), provider, pubType, prvType);
+    }
+    
+    private static KeyPair testLoadPrivateKey(String resourceKey, AbstractResourceKeyPairProvider<?> provider, Class<? extends PublicKey> pubType, Class<? extends PrivateKey> prvType) {
+        provider.setPasswordFinder(passwordProvider);
+        Iterable<KeyPair> iterator = provider.loadKeys();
+        List<KeyPair> pairs = new ArrayList<KeyPair>();
+        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;
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/06d37a2d/sshd-core/src/test/java/org/apache/sshd/server/keyprovider/AbstractGeneratorHostKeyProviderTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/server/keyprovider/AbstractGeneratorHostKeyProviderTest.java b/sshd-core/src/test/java/org/apache/sshd/server/keyprovider/AbstractGeneratorHostKeyProviderTest.java
index 7d5d01f..7166b29 100644
--- a/sshd-core/src/test/java/org/apache/sshd/server/keyprovider/AbstractGeneratorHostKeyProviderTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/server/keyprovider/AbstractGeneratorHostKeyProviderTest.java
@@ -19,8 +19,10 @@
 package org.apache.sshd.server.keyprovider;
 
 import java.io.File;
+import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.security.GeneralSecurityException;
 import java.security.KeyPair;
 import java.util.concurrent.atomic.AtomicInteger;
 
@@ -56,16 +58,17 @@ public class AbstractGeneratorHostKeyProviderTest extends BaseTestSupport {
         private final AtomicInteger writes = new AtomicInteger(0);
 
         private TestProvider(File file) {
-            super(file.getAbsolutePath(), "DSA", 512);
+            setKeySize(512);
+            setPath(file.toPath());
         }
 
         @Override
-        protected KeyPair doReadKeyPair(InputStream is) throws Exception {
+        protected KeyPair doReadKeyPair(String resourceKey, InputStream inputStream) throws IOException, GeneralSecurityException {
             return null;
         }
 
         @Override
-        protected void doWriteKeyPair(KeyPair kp, OutputStream os) throws Exception {
+        protected void doWriteKeyPair(String resourceKey, KeyPair kp, OutputStream outputStream) throws IOException, GeneralSecurityException {
             writes.incrementAndGet();
         }
 

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/06d37a2d/sshd-core/src/test/java/org/apache/sshd/server/keyprovider/PEMGeneratorHostKeyProviderTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/server/keyprovider/PEMGeneratorHostKeyProviderTest.java b/sshd-core/src/test/java/org/apache/sshd/server/keyprovider/PEMGeneratorHostKeyProviderTest.java
index 56f3194..ece0710 100644
--- a/sshd-core/src/test/java/org/apache/sshd/server/keyprovider/PEMGeneratorHostKeyProviderTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/server/keyprovider/PEMGeneratorHostKeyProviderTest.java
@@ -56,18 +56,21 @@ public class PEMGeneratorHostKeyProviderTest extends BaseTestSupport {
     @Test
     public void testEC_NISTP256() {
         Assume.assumeTrue("BouncyCastle not registered", SecurityUtils.isBouncyCastleRegistered());
+        Assume.assumeTrue("ECC not supported", SecurityUtils.hasEcc());
         testPEMGeneratorHostKeyProvider("EC", KeyPairProvider.ECDSA_SHA2_NISTP256, -1, new ECGenParameterSpec("prime256v1"));
     }
 
     @Test
     public void testEC_NISTP384() {
         Assume.assumeTrue("BouncyCastle not registered", SecurityUtils.isBouncyCastleRegistered());
+        Assume.assumeTrue("ECC not supported", SecurityUtils.hasEcc());
         testPEMGeneratorHostKeyProvider("EC", KeyPairProvider.ECDSA_SHA2_NISTP384, -1, new ECGenParameterSpec("P-384"));
     }
 
     @Test
     public void testEC_NISTP521() {
         Assume.assumeTrue("BouncyCastle not registered", SecurityUtils.isBouncyCastleRegistered());
+        Assume.assumeTrue("ECC not supported", SecurityUtils.hasEcc());
         testPEMGeneratorHostKeyProvider("EC", KeyPairProvider.ECDSA_SHA2_NISTP521, -1, new ECGenParameterSpec("P-521"));
     }
 
@@ -88,10 +91,9 @@ public class PEMGeneratorHostKeyProviderTest extends BaseTestSupport {
     }
 
     private static KeyPair invokePEMGeneratorHostKeyProvider(File path, String algorithm, String keyType, int keySize, AlgorithmParameterSpec keySpec) {
-        PEMGeneratorHostKeyProvider provider = new PEMGeneratorHostKeyProvider();
+        AbstractGeneratorHostKeyProvider provider = SecurityUtils.createGeneratorHostKeyProvider(path.toPath().toAbsolutePath());
         provider.setAlgorithm(algorithm);
         provider.setOverwriteAllowed(true);
-        provider.setPath(path.getAbsolutePath());
         if (keySize > 0) {
             provider.setKeySize(keySize);
         }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/06d37a2d/sshd-core/src/test/java/org/apache/sshd/server/keyprovider/SimpleGeneratorHostKeyProviderTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/server/keyprovider/SimpleGeneratorHostKeyProviderTest.java b/sshd-core/src/test/java/org/apache/sshd/server/keyprovider/SimpleGeneratorHostKeyProviderTest.java
index 63d5b65..a5f6edd 100644
--- a/sshd-core/src/test/java/org/apache/sshd/server/keyprovider/SimpleGeneratorHostKeyProviderTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/server/keyprovider/SimpleGeneratorHostKeyProviderTest.java
@@ -81,7 +81,7 @@ public class SimpleGeneratorHostKeyProviderTest extends BaseTestSupport {
         SimpleGeneratorHostKeyProvider provider = new SimpleGeneratorHostKeyProvider();
         provider.setAlgorithm(algorithm);
         provider.setOverwriteAllowed(true);
-        provider.setPath(path.getAbsolutePath());
+        provider.setFile(path.getAbsoluteFile());
         if (keySize > 0) {
             provider.setKeySize(keySize);
         }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/06d37a2d/sshd-core/src/test/java/org/apache/sshd/util/BaseTestSupport.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/util/BaseTestSupport.java b/sshd-core/src/test/java/org/apache/sshd/util/BaseTestSupport.java
index c6cd954..f03965c 100644
--- a/sshd-core/src/test/java/org/apache/sshd/util/BaseTestSupport.java
+++ b/sshd-core/src/test/java/org/apache/sshd/util/BaseTestSupport.java
@@ -45,6 +45,7 @@ import java.util.Iterator;
 import java.util.List;
 
 import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.ValidateUtils;
 import org.junit.Assert;
 import org.junit.Rule;
 import org.junit.rules.TestName;
@@ -100,20 +101,46 @@ public abstract class BaseTestSupport extends Assert {
      * associated with the project that contains the actual class extending this
      * base class
      * @return The {@link File} representing the location of the &quot;target&quot; folder
-     * @throws IllegalStateException If failed to detect the folder
+     * @throws IllegalArgumentException If failed to detect the folder
      */
     protected File detectTargetFolder() throws IllegalStateException {
         synchronized(TEMP_SUBFOLDER_NAME) {
             if (targetFolder == null) {
-                if ((targetFolder=Utils.detectTargetFolder(getClass())) == null) {
-                    throw new IllegalStateException("Failed to detect target folder");
-                }
+                targetFolder = ValidateUtils.checkNotNull(Utils.detectTargetFolder(getClass()), "Failed to detect target folder", GenericUtils.EMPTY_OBJECT_ARRAY);
             }
         }
 
         return targetFolder;
     }
 
+    protected File detectSourcesFolder() throws IllegalStateException {
+        File target = detectTargetFolder();
+        File parent = target.getParentFile();
+        return new File(parent, "src");
+    }
+
+    public static final String MAIN_SUBFOLDER = "main", TEST_SUBFOLDER = "test";
+    public static final String RESOURCES_SUBFOLDER = "resources";
+
+    protected File getClassResourcesFolder(String resType /* test or main */) {
+        return getClassResourcesFolder(resType, getClass());
+    }
+
+    protected File getClassResourcesFolder(String resType /* test or main */, Class<?> clazz) {
+        return getPackageResourcesFolder(resType, clazz.getPackage());
+    }
+
+    protected File getPackageResourcesFolder(String resType /* test or main */, Package pkg) {
+        return getPackageResourcesFolder(resType, pkg.getName());
+    }
+
+    protected File getPackageResourcesFolder(String resType /* test or main */, String pkgName) {
+        File src = detectSourcesFolder();
+        File root = new File(src, resType);
+        File resources = new File(root, RESOURCES_SUBFOLDER);
+        return new File(resources, pkgName.replace('.', File.separatorChar));
+    }
+
     /* ------------------- Useful extra test helpers ---------------------- */
 
     public static String shuffleCase(CharSequence cs) {

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/06d37a2d/sshd-core/src/test/java/org/apache/sshd/util/Utils.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/util/Utils.java b/sshd-core/src/test/java/org/apache/sshd/util/Utils.java
index a7d8185..6c91836 100644
--- a/sshd-core/src/test/java/org/apache/sshd/util/Utils.java
+++ b/sshd-core/src/test/java/org/apache/sshd/util/Utils.java
@@ -41,9 +41,12 @@ import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicReference;
 
-import org.apache.sshd.common.keyprovider.FileKeyPairProvider;
+import org.apache.sshd.common.Factory;
+import org.apache.sshd.common.keyprovider.AbstractFileKeyPairProvider;
 import org.apache.sshd.common.keyprovider.KeyPairProvider;
+import org.apache.sshd.common.random.Random;
 import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.SecurityUtils;
 import org.apache.sshd.common.util.ValidateUtils;
 import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
 
@@ -60,7 +63,10 @@ public class Utils {
         
         File targetFolder = ValidateUtils.checkNotNull(detectTargetFolder(Utils.class), "Failed to detect target folder", GenericUtils.EMPTY_OBJECT_ARRAY);
         File file = new File(targetFolder, "hostkey." + DEFAULT_TEST_HOST_KEY_PROVIDER_ALGORITHM.toLowerCase());
-        provider = validateKeyPairProvider(new SimpleGeneratorHostKeyProvider(file.getAbsolutePath(), DEFAULT_TEST_HOST_KEY_PROVIDER_ALGORITHM.toUpperCase()));
+        SimpleGeneratorHostKeyProvider keyProvider = new SimpleGeneratorHostKeyProvider();
+        keyProvider.setFile(file);
+        keyProvider.setAlgorithm(DEFAULT_TEST_HOST_KEY_PROVIDER_ALGORITHM);
+        provider = validateKeyPairProvider(keyProvider);
         
         KeyPairProvider prev = keyPairProviderHolder.getAndSet(provider);
         if (prev != null) { // check if somebody else beat us to it
@@ -71,17 +77,20 @@ public class Utils {
     }
 
     // uses a cached instance to avoid re-creating the keys as it is a time-consuming effort
-    private static final Map<String, FileKeyPairProvider> providersMap = new ConcurrentHashMap<String, FileKeyPairProvider>(); 
-    public static FileKeyPairProvider createTestKeyPairProvider(String resource) {
-        String file = getFile(resource);
-        FileKeyPairProvider provider = providersMap.get(file);
+    private static final Map<String, AbstractFileKeyPairProvider> providersMap = new ConcurrentHashMap<String, AbstractFileKeyPairProvider>(); 
+    public static AbstractFileKeyPairProvider createTestKeyPairProvider(String resource) {
+        File file = getFile(resource);
+        String filePath = file.getAbsolutePath();
+        AbstractFileKeyPairProvider provider = providersMap.get(filePath);
         if (provider != null) {
             return provider;
         }
 
-        provider = validateKeyPairProvider(new FileKeyPairProvider(file));
-            
-        FileKeyPairProvider prev = providersMap.put(file, provider);
+        provider = SecurityUtils.createFileKeyPairProvider();
+        provider.setFiles(Collections.singletonList(file));
+        provider = validateKeyPairProvider(provider);
+
+        AbstractFileKeyPairProvider prev = providersMap.put(filePath, provider);
         if (prev != null) { // check if somebody else beat us to it
             return prev;
         } else {
@@ -100,6 +109,11 @@ public class Utils {
         
         return provider;
     }
+    
+    public static Random getRandomizerInstance() {
+        Factory<Random> factory = SecurityUtils.getRandomFactory();
+        return factory.create();
+    }
 
     public static int getFreePort() throws Exception {
         try(ServerSocket s = new ServerSocket()) {
@@ -109,15 +123,13 @@ public class Utils {
         }
     }
 
-    private static String getFile(String resource) {
+    private static File getFile(String resource) {
         URL url = Utils.class.getClassLoader().getResource(resource);
-        File f;
         try {
-            f = new File(url.toURI());
+            return new File(url.toURI());
         } catch(URISyntaxException e) {
-            f = new File(url.getPath());
+            return new File(url.getPath());
         }
-        return f.toString();
     }
 
     public static Path resolve(Path root, String ... children) {

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/06d37a2d/sshd-core/src/test/resources/org/apache/sshd/common/util/SecurityUtilsTest-DSA-KeyPair
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/resources/org/apache/sshd/common/util/SecurityUtilsTest-DSA-KeyPair b/sshd-core/src/test/resources/org/apache/sshd/common/util/SecurityUtilsTest-DSA-KeyPair
new file mode 100644
index 0000000..1d3ef24
--- /dev/null
+++ b/sshd-core/src/test/resources/org/apache/sshd/common/util/SecurityUtilsTest-DSA-KeyPair
@@ -0,0 +1,12 @@
+-----BEGIN DSA PRIVATE KEY-----
+MIIBvAIBAAKBgQDIPyMbBuQcZxeYDOyCqqkdK37cWQvp+RpWzvieB/oiG/ykfDQX
+oZMRtwqwWTBfejNitbBBmC6G/t5OK+9aFmj7pfJ+a7fZKXfiUquIg9soDsoOindf
+2AwR6MZ3os8uiP2xrC8IQAClnETa15mFShs4a4b2VjddgCQ6tphnY97MywIVAPtr
+YyW11RIXsVTf/9KlbhYaNlt5AoGAX9JzbHykC/0xDKOyKU6xDIOVdEZ0ooAl9Psl
+BEUuNhlv2XgmQScO6C9l2W7gbbut7zIw4FaZ2/dgXa3D4IyexBVug5XMnrssErZo
+NcoF5g0dgEAsb9Hl9gkIK3VHM5kWteeUg1VE700JTtSMisdL8CgIdR+xN8iVH5Ew
+CbLWxmECgYEAtv+cdRfNevYFkp55jVqazc8zRLvfb64jzgc5oSJVc64kFs4yx+ab
+YpGX9WxNxDlG6g2WiY8voDBB0YnUJsn0kVRjBKX9OceROxrfT4K4dVbQZsdt+SLa
+XWL4lGJFrFZL3LZqvySvq6xfhJfakQDDivW4hUOhFPXPHrE5/Ia3T7ACFQCE6flG
+nmVCAbzo9YsbdJWBnxMnBA==
+-----END DSA PRIVATE KEY-----
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/06d37a2d/sshd-core/src/test/resources/org/apache/sshd/common/util/SecurityUtilsTest-DSA-KeyPair.pub
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/resources/org/apache/sshd/common/util/SecurityUtilsTest-DSA-KeyPair.pub b/sshd-core/src/test/resources/org/apache/sshd/common/util/SecurityUtilsTest-DSA-KeyPair.pub
new file mode 100644
index 0000000..c0790ed
--- /dev/null
+++ b/sshd-core/src/test/resources/org/apache/sshd/common/util/SecurityUtilsTest-DSA-KeyPair.pub
@@ -0,0 +1 @@
+ssh-dss AAAAB3NzaC1kc3MAAACBAMg/IxsG5BxnF5gM7IKqqR0rftxZC+n5GlbO+J4H+iIb/KR8NBehkxG3CrBZMF96M2K1sEGYLob+3k4r71oWaPul8n5rt9kpd+JSq4iD2ygOyg6Kd1/YDBHoxneizy6I/bGsLwhAAKWcRNrXmYVKGzhrhvZWN12AJDq2mGdj3szLAAAAFQD7a2MltdUSF7FU3//SpW4WGjZbeQAAAIBf0nNsfKQL/TEMo7IpTrEMg5V0RnSigCX0+yUERS42GW/ZeCZBJw7oL2XZbuBtu63vMjDgVpnb92BdrcPgjJ7EFW6DlcyeuywStmg1ygXmDR2AQCxv0eX2CQgrdUczmRa155SDVUTvTQlO1IyKx0vwKAh1H7E3yJUfkTAJstbGYQAAAIEAtv+cdRfNevYFkp55jVqazc8zRLvfb64jzgc5oSJVc64kFs4yx+abYpGX9WxNxDlG6g2WiY8voDBB0YnUJsn0kVRjBKX9OceROxrfT4K4dVbQZsdt+SLaXWL4lGJFrFZL3LZqvySvq6xfhJfakQDDivW4hUOhFPXPHrE5/Ia3T7A= dsa-key-20130709
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/06d37a2d/sshd-core/src/test/resources/org/apache/sshd/common/util/SecurityUtilsTest-EC-256-KeyPair
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/resources/org/apache/sshd/common/util/SecurityUtilsTest-EC-256-KeyPair b/sshd-core/src/test/resources/org/apache/sshd/common/util/SecurityUtilsTest-EC-256-KeyPair
new file mode 100644
index 0000000..31b1268
--- /dev/null
+++ b/sshd-core/src/test/resources/org/apache/sshd/common/util/SecurityUtilsTest-EC-256-KeyPair
@@ -0,0 +1,5 @@
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIPKmiQzAASg656IP4PuuElLdLdO/MIXrGxQG6tGkKZ1HoAoGCCqGSM49
+AwEHoUQDQgAEobHtw9wkL332ep9fi8Gw5g8sEGwslNonPUCDR6YUZ9mjOehliLpF
+DLHLxlIFafrVM+LIpagjpRKZcnpGPWQDnA==
+-----END EC PRIVATE KEY-----

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/06d37a2d/sshd-core/src/test/resources/org/apache/sshd/common/util/SecurityUtilsTest-EC-256-KeyPair.pub
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/resources/org/apache/sshd/common/util/SecurityUtilsTest-EC-256-KeyPair.pub b/sshd-core/src/test/resources/org/apache/sshd/common/util/SecurityUtilsTest-EC-256-KeyPair.pub
new file mode 100644
index 0000000..1c9763f
--- /dev/null
+++ b/sshd-core/src/test/resources/org/apache/sshd/common/util/SecurityUtilsTest-EC-256-KeyPair.pub
@@ -0,0 +1 @@
+ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBKGx7cPcJC999nqfX4vBsOYPLBBsLJTaJz1Ag0emFGfZoznoZYi6RQyxy8ZSBWn61TPiyKWoI6USmXJ6Rj1kA5w= root@osv-linux
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/06d37a2d/sshd-core/src/test/resources/org/apache/sshd/common/util/SecurityUtilsTest-EC-384-KeyPair
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/resources/org/apache/sshd/common/util/SecurityUtilsTest-EC-384-KeyPair b/sshd-core/src/test/resources/org/apache/sshd/common/util/SecurityUtilsTest-EC-384-KeyPair
new file mode 100644
index 0000000..29af76f
--- /dev/null
+++ b/sshd-core/src/test/resources/org/apache/sshd/common/util/SecurityUtilsTest-EC-384-KeyPair
@@ -0,0 +1,6 @@
+-----BEGIN EC PRIVATE KEY-----
+MIGkAgEBBDB15z4n/vjug4fcEXPcgeonCHQuxJOwgFDIap/rgtM3EwuFDpE9wkfM
+K64UwV1ZSlygBwYFK4EEACKhZANiAARSJmbXE4/ONrLZXFRyxQRcUxMe5bt41vWm
+Qr3dK/X1DSmei20T4epdaCeKMwK58O163kAVHOaDXfRweUTSfI5dZ1l2OXFwQOzH
+Gayma2JpPs8TYR+lC/pDC2iZMp4CR0M=
+-----END EC PRIVATE KEY-----

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/06d37a2d/sshd-core/src/test/resources/org/apache/sshd/common/util/SecurityUtilsTest-EC-384-KeyPair.pub
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/resources/org/apache/sshd/common/util/SecurityUtilsTest-EC-384-KeyPair.pub b/sshd-core/src/test/resources/org/apache/sshd/common/util/SecurityUtilsTest-EC-384-KeyPair.pub
new file mode 100644
index 0000000..93ceef0
--- /dev/null
+++ b/sshd-core/src/test/resources/org/apache/sshd/common/util/SecurityUtilsTest-EC-384-KeyPair.pub
@@ -0,0 +1 @@
+ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBFImZtcTj842stlcVHLFBFxTEx7lu3jW9aZCvd0r9fUNKZ6LbRPh6l1oJ4ozArnw7XreQBUc5oNd9HB5RNJ8jl1nWXY5cXBA7McZrKZrYmk+zxNhH6UL+kMLaJkyngJHQw== root@osv-linux
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/06d37a2d/sshd-core/src/test/resources/org/apache/sshd/common/util/SecurityUtilsTest-EC-521-KeyPair
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/resources/org/apache/sshd/common/util/SecurityUtilsTest-EC-521-KeyPair b/sshd-core/src/test/resources/org/apache/sshd/common/util/SecurityUtilsTest-EC-521-KeyPair
new file mode 100644
index 0000000..43f79d7
--- /dev/null
+++ b/sshd-core/src/test/resources/org/apache/sshd/common/util/SecurityUtilsTest-EC-521-KeyPair
@@ -0,0 +1,7 @@
+-----BEGIN EC PRIVATE KEY-----
+MIHcAgEBBEIBUacw+zn8Mw0PYaqqtAlOyaVXARegI6sK5YBhl5E1l9sqTzVN77ce
+1RrqQ8smfvZ6Hiw5gdGcPTszbiorVV5npg6gBwYFK4EEACOhgYkDgYYABACg4siC
+q1iqr4U/spXmw6b2VwBMsof7XLQGoD9wfwUikb8XWthNSmPP1nL6rlzJ5j8Bezn9
+BSSDfVAJfgqxmGIHdgHRVc0mkdq1/Q/DKhBgRyjZc29eo0o2ck3SNGNVaAabRYj6
+ck/iub/U6trKM7bdqy/joYYMwZdxLyYW5YxkPbqEfQ==
+-----END EC PRIVATE KEY-----

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/06d37a2d/sshd-core/src/test/resources/org/apache/sshd/common/util/SecurityUtilsTest-EC-521-KeyPair.pub
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/resources/org/apache/sshd/common/util/SecurityUtilsTest-EC-521-KeyPair.pub b/sshd-core/src/test/resources/org/apache/sshd/common/util/SecurityUtilsTest-EC-521-KeyPair.pub
new file mode 100644
index 0000000..520b64e
--- /dev/null
+++ b/sshd-core/src/test/resources/org/apache/sshd/common/util/SecurityUtilsTest-EC-521-KeyPair.pub
@@ -0,0 +1 @@
+ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBACg4siCq1iqr4U/spXmw6b2VwBMsof7XLQGoD9wfwUikb8XWthNSmPP1nL6rlzJ5j8Bezn9BSSDfVAJfgqxmGIHdgHRVc0mkdq1/Q/DKhBgRyjZc29eo0o2ck3SNGNVaAabRYj6ck/iub/U6trKM7bdqy/joYYMwZdxLyYW5YxkPbqEfQ== root@osv-linux
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/06d37a2d/sshd-core/src/test/resources/org/apache/sshd/common/util/SecurityUtilsTest-RSA-KeyPair
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/resources/org/apache/sshd/common/util/SecurityUtilsTest-RSA-KeyPair b/sshd-core/src/test/resources/org/apache/sshd/common/util/SecurityUtilsTest-RSA-KeyPair
new file mode 100644
index 0000000..afc6aa8
--- /dev/null
+++ b/sshd-core/src/test/resources/org/apache/sshd/common/util/SecurityUtilsTest-RSA-KeyPair
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEoQIBAAKCAQEAxr3N5fkt966xJINl0hH7Q6lLDRR1D0yMjcXCE5roE9VFut2c
+tGFuo90TCOxkPOMnwzwConeyScVF4ConZeWsxbG9VtRh61IeZ6R5P5ZTvE9xPdZB
+gIEWvU1bRfrrOfSMihqF98pODspE6NoTtND2eglwSGwxcYFmpdTAmu+8qgxgGxlE
+aaCjqwdiNPZhygrH81Mv2ruolNeZkn4Bj+wFFmZTD/waN1pQaMf+SO1+kEYIYFNl
+5+8JRGuUcr8MhHHJB+gwqMTF2BSBVITJzZUiQR0TMtkK6Vbs7yt1F9hhzDzAFDwh
+V+rsfNQaOHpl3zP07qH+/99A0XG1CVcEdHqVMwIBIwKCAQALW02YHN4OJz1Siypj
+xoNi87slUaBKBF/NlkWauGUIcpZFMTwnkIn6vCz5MhRbQC4oadRDzFNUrC/g7HdH
+prlqYe2P7uEGIfMb3YNFdk3tgOHmRsHqFgFMpVWsOjlTxNTUsQ74N3Isuxnha4wY
+9f90sBULc+WRdRvO9jbkSDaqoYVKAqCFWtocL+ZWwBXWrIrsQW4PElgZ/duc5DX7
+eeJ5DXCSj9dO+1KxsWEOKaoeABEegrRVys1/shcDNPhf/p0QShKIdPcpnDUc8cny
+1bq8GSt6jEQ+tuRoSnYrY+RD+mlkHrx373Xc1a9woV+QKTThmd9TQ8gzHMHNqq0a
+7kR7AoGBAOuPOTRiKaDtQyMTEX7eeHsPNE24EgvONjNpxyQ6gKGthG5SiB0IO7mP
+r7EggbR2EY8eMCY5HjvxzxgH86n2Pqbzsr6UlQq7YTPupCm/7fPgRknu917GA20f
+1cuY8B04Jp4FIGryBmCcScX6usXXhjfAvYCWWfkSytA8gX9+b1TNAoGBANf8shbp
+wRnQfgAzw2S+xs29pdwa6Jb/xuLvHSyklmgidrK4nsVI8G+zeCqwkqkNM02sM+vR
+c8EX7+myrGf+S2V3JS3AMNXEhavrWVH0CuqFHlBjSwHZ0uKuPpWHlCnud+23AdQz
+Bf1H7tYKt5es3J/B37o4YxhAL6U9qq+ewZH/AoGBAOTURjLjA94oT9jt870SoOyS
+bVLQEYfPol3UeE8UQnEsN4Ec+UDGK2PNaNfzsTL2WjNB5aF5UJIA184znD60seQC
+raMxQFORdF5ViYekgMEFwJ+XrnlSpD4e7PGqgtqOUWZOH33VKsRADSa5DTU3xDYo
+8porp9wDoHKD64MqXYWTAoGADFeVJeF4v6WDivukw+2k9dBSntz3WRXuG5iilNY0
+evqnsnDzITdeMkTFCcDycA9iBHA9ezCKRYxW2id3kOn1rgbO7KvliI7jESNkMJGa
+OUlvck7RFgxyc1pp+ep9fr0rbKtfMLJ1Xu4q56jXSn7oCSEFeFr+WSg9PKRwJ0rm
+fV8CgYAkYOiNY8jH5lwwoPWOIPJg62zdzmRQktrU3z7Nzk5udN6JnG3g57QjkozX
+AgHARKQ2MuXW9OfOnYNhbGeavcBQmg5XUx3eL4PRFw8mFZdjpBD/kM/dfCEwEta3
+FpRlVGn0RNqVV5xxClObD/CikkDqKZG4MSj3CrO3JK33gl1Lgg==
+-----END RSA PRIVATE KEY-----

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/06d37a2d/sshd-core/src/test/resources/org/apache/sshd/common/util/SecurityUtilsTest-RSA-KeyPair.pub
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/resources/org/apache/sshd/common/util/SecurityUtilsTest-RSA-KeyPair.pub b/sshd-core/src/test/resources/org/apache/sshd/common/util/SecurityUtilsTest-RSA-KeyPair.pub
new file mode 100644
index 0000000..9fac6f7
--- /dev/null
+++ b/sshd-core/src/test/resources/org/apache/sshd/common/util/SecurityUtilsTest-RSA-KeyPair.pub
@@ -0,0 +1 @@
+ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAxr3N5fkt966xJINl0hH7Q6lLDRR1D0yMjcXCE5roE9VFut2ctGFuo90TCOxkPOMnwzwConeyScVF4ConZeWsxbG9VtRh61IeZ6R5P5ZTvE9xPdZBgIEWvU1bRfrrOfSMihqF98pODspE6NoTtND2eglwSGwxcYFmpdTAmu+8qgxgGxlEaaCjqwdiNPZhygrH81Mv2ruolNeZkn4Bj+wFFmZTD/waN1pQaMf+SO1+kEYIYFNl5+8JRGuUcr8MhHHJB+gwqMTF2BSBVITJzZUiQR0TMtkK6Vbs7yt1F9hhzDzAFDwhV+rsfNQaOHpl3zP07qH+/99A0XG1CVcEdHqVMw== lgoldstein@LGOLDSTEIN-WIN7

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/06d37a2d/sshd-core/src/test/resources/org/apache/sshd/common/util/super-secret-passphrase-RSA-AES-128-key
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/resources/org/apache/sshd/common/util/super-secret-passphrase-RSA-AES-128-key b/sshd-core/src/test/resources/org/apache/sshd/common/util/super-secret-passphrase-RSA-AES-128-key
new file mode 100644
index 0000000..2b93a42
--- /dev/null
+++ b/sshd-core/src/test/resources/org/apache/sshd/common/util/super-secret-passphrase-RSA-AES-128-key
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-128-CBC,D41AC063160FCC09B1E1931FB43BCEAA
+
+V218dGT2pUpimnwEVn+2ljvK6mvm2aNLlaakMunlHfIswrakJ1WTs8a61pYILOn9
+MGHrCiqe6ZI7FBJ2wXpSxhcuM3fzk6/dW4Ghh4EHG1Y94w97EizxNfyz/iI2XQw0
+i6ttaDLVzP8UcSRElqG+Zpe1A7EE/DkdkXD3f/DaGHtu1zirVeaEIggMLjfTdwnR
+sH9VnUZhe74VdPV0x16h7JjLt5fcbIjqJ6NWW4QvQpPBv3k0oiUy/nP4FXg1b7VW
+7SowuCPi+mF821hj4xSO8ETlAU1eZdtgXqtejtKm0iDtsjnTBZPvDDrq5ephBlxO
+k7JBJG1LFUiDIGnpxos5nCsKEo8UAw9a5/D4xE3C6UTocXon28XGzVCbkZBN6jcd
+UbpjCVwKMJmFL97487u9S57xrGTmJdi1AtF9Rei8juTTQY4+r3l2c7JtdtcbLUhj
+iLvdYnbh6kUEyE19/+omJaWGQlFhYp7ZMRRQSiz6TD8lhSIBPpXzs+uMfhkrifVk
+3WpjRoikmPOOFLtecee5Rp+SpGd700XgLnxwZ47l0FNfrKKqd3+nZX4JILQ2M0JP
+sBx8gcIew8aUqMzWrwZxbrt9Pd1+2kSNVG9hpLoNoA4WpQnYQMo4L0eTCeMNUOap
+f9H0Hh3QnqXTPHbcYZJCGE2RUxLzn/d7rUxUdEzER+pkhJcw9JbV/izTrpDHs9bM
+cfBLggQvs+UIBww2OFz2BztwoQzsSEuNW/SxG/y6SfRUQq5TZw9NxYnrrqfBXKtx
+svB1JVbn2fKq2Lvi8AZ1fF3tyrNot/tptDf0yDHejWDUvVx5cXsKVK2BbVjbZ88k
+mBtUbw7ea9Ev7ZsihNB2EdhPjLhhKlKLIZznPKeXL3GDTXqCgCxTVh4wLvaR8rDU
+C3Isil4WprCeynmZpOe7bxAZDm2QCobnDB8sLQqBI4zgH8X/1iyXJVdSKfK9vxcB
+sJ5pYCcS2q0C+CJkn6HVTlMQ5CyyzvPaDJukJoxwxsZ5hgCsUHFzrvyGnXqGfTBD
+qEW+oA7cj48CfweV5pXHj+mZpCrpn1zRVJRz4h1FZRsttPGtBRAlns5I3kh5BPRs
+4m1BO1jiWyp/7HkUrDRhEf/QeJsP+mTH32pQgnngZ/AGA0PUcKanMUpe1d2ju83V
+EIcTz9ycTHPiOAM6GaVt54fKj9WRBU+7pf14ZdJmfhp6twc0jNtaTh+/I6Pfb0jN
+0d6yKV//pOeJJBNhuOJgm/0vfkOnOojIJchOQCRt5Lg/a4fD/JXtLOed2zOQa+0J
+3d8Y93mQX/iN1wi95/sG79YBYF3FkJYVhjosSKbiIaxIn76zIx4IAlziycDKvgpr
+JgZcVvCDc4flwrf3Cv/uHK7UWOE+16X1CfAy8JzFg5bhiMmhgsJyHmd+zDGrY6NX
+zz+wLmwOenEwC40gpt89OXbgMcwJMtfiSusatRtZ+AAs0jb/8jExVXfcYE3m3r1/
+FqLZ7seTQT2D01YoPlwUtSPxzaZbziAJ/NaGmURnBGVibDCJxwUAiOSIQH4prIfg
+Q2FCJeMTbLV43Lanlby5nrmLkzsw3uo1MO8Of1DbcnVUHNSwrp/nNzrYdxBLIvqS
+-----END RSA PRIVATE KEY-----

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/06d37a2d/sshd-core/src/test/resources/org/apache/sshd/common/util/super-secret-passphrase-RSA-AES-128-key.pub
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/resources/org/apache/sshd/common/util/super-secret-passphrase-RSA-AES-128-key.pub b/sshd-core/src/test/resources/org/apache/sshd/common/util/super-secret-passphrase-RSA-AES-128-key.pub
new file mode 100644
index 0000000..b1d66a6
--- /dev/null
+++ b/sshd-core/src/test/resources/org/apache/sshd/common/util/super-secret-passphrase-RSA-AES-128-key.pub
@@ -0,0 +1 @@
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC/oDbs/yYxBdT02ldP6JIrcETJQ+TCml1tHYuo8cIQp0DZCgRZiEZ4foucAT8R/vLK01nnjRzrI42MXiCzyAHb1sPRD0Fsbpa4TFJczPBBRM2mp56airnArQUMmg/ZKlOf82hn+u7Kgn+ljyjYG5FrdoUBju62i0H4+oBfX+pTkd5ruUgqLyPUC3qtNLwjS4PIPAda/pfpsi9UawQ4ommWCCLlwK55NiSrPDBwKNuVWROcQps2NZRxzRLQEiiCEVBEdiUqqUQ+dg2beLV/4cCS860ZZRvCfe+ko8TUBJ7SLtcrvOEYJOKIZDVhcnQKN/wyXCHExSYytUconlFn/9YX root@devenv-aas
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/06d37a2d/sshd-core/src/test/resources/org/apache/sshd/common/util/super-secret-passphrase-RSA-AES-192-key
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/resources/org/apache/sshd/common/util/super-secret-passphrase-RSA-AES-192-key b/sshd-core/src/test/resources/org/apache/sshd/common/util/super-secret-passphrase-RSA-AES-192-key
new file mode 100644
index 0000000..014410d
--- /dev/null
+++ b/sshd-core/src/test/resources/org/apache/sshd/common/util/super-secret-passphrase-RSA-AES-192-key
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-192-CBC,EDF8E3E634D2106991113815A3C1F11F
+
+PZaaf2TCSCRmPZDnUa9Hq+RVGAXRXl8T8rduiqFLKG2Vk192AEo4WRPWhIcJ4ov+
+o6N69V0Fj/NrRyuwjihQQM27gTK2JK8cvDen+WB3mp5wmfFaazHXO21xNGMAp3bm
+obEeO+NHaG0080yxQ4AU2BzPZ1q/ePjDGBiENUsBAHeZvN2fM5uI4Cs9pqko2OM/
+ZiJQkn2QlnpSPm8B7kspqpEV9bn1peVYAMIkp/yES18Kw50kan3R2CqccutVQfdP
+8ddTPPUvWUrDSrW/Ae2qZvRoCXVLDhy1jBKQDMUCrxqDJCo58GR0FWxK4nhCgfeL
+wmxGaKL/3uKDl5otkj93C1qCbEvQCJm5rcwEjkRVfeSPvNNh+WQrJE7uNcJB4kXX
+tF8c5peZI8ymdlFFXlCqjVpdhJh0YKRhpxhWKLA15I1bbwwY4/mwIIMyXOcAQo58
+G7XOwBPw01/lSJ/YTR8y1ubFbWJ6LgoLgSzsOLnBxJJji148UiNDPPbal0FN8vK2
+VsSRBrjrNHSmh+BSA0AStq4QtQpwNMU0qKFLzx5HvoYiaSG+OKtJLZNqTGzDG5aS
+Xe8rNoTQTaZBy5yTY1zTn2lMFngWSt/aYyXfc1BXdYyTOk/eoGHtXxp91nQtCdkG
+4VMMfPlnbW1Q2Cq4ATdcIUPPKLaNVlP2TbloBb1wYjXy8RfFFqZVNOLnxXnXOXUG
+U5SlG44XV5AouwhrlUPrm+0+9jIh4pO4sfG0ldGwabGbUMZ6vvgcU9w1yRcsjycG
+v9yH7CfFKKXjUL5RR2weZVD8vRjQMbfVHRt3P4NFClI6e1gXx92FmT7x97866e+T
+TohyC7uZQq2prBzt8BwxFP0h19+CiTVzofe2I9x+Hce67F+ATnLq9fxOnjZlwK1i
+K95eK+Itc9zSu9tIZGaLvghOExZ24893Ncz5NJ2nn0YptxSi24e8PcECHhSUrjv9
+1VOi8JUmv58bQ5ocuUlHmB2FkpnsYUNjtQx1OT2IRovQJIDCttHhT3QIGoiqoeTw
+sSwyz0gDYzAJtuVkSZxqXJ4LEMozaA3uwxv0TfaQordm+GuGKuV5MsKyEQtITUk5
+5bgQfS0VQqkbq2fRjtd3nIJWCF5otrVulY0tzoTBjGZ2trNj5nz5ZEUTFdRSAaxb
+F+i3Mv8gGPC+2YIo8feDCHnRQ1AALjLon8nKefRsWAOYUozNCtHvu4g7WK6+GcPd
+eiYM7tbSrNCHg+KdB+eWrJCfVCgVHTj8mGb3EiH6oxgx51TmlyuQYJAVseWjQOdm
+IDKiAsNNZijmgMWLsFZG1VvF/446VWIGkSW9eB6bB7aR1Kg4F18VkXdn+SPmaHrC
+NHhNa9dOmcOvlNXIs7jlTjRVEC0pp8DH0AUdPjqlR/F1IHb7uFyqlza8Cqb7PZJs
+x+9GbSwuyKLKLvMzmsnBtpRT32Srsbx6pWst40gaoOMFxto22vmGxz4IABGi96V/
+NrrDHtuZ5OaePl7GihKcUCSSVcoFO2jKKNMMHSSVGhxkfir7qGzMe5LZ9/zl+bvW
+vBS0wSPUd+P3mLc0m53mH+g26I479ryX6/2W+GecB1h5p7S7vJMPQjqZAJskogf5
+-----END RSA PRIVATE KEY-----

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/06d37a2d/sshd-core/src/test/resources/org/apache/sshd/common/util/super-secret-passphrase-RSA-AES-192-key.pub
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/resources/org/apache/sshd/common/util/super-secret-passphrase-RSA-AES-192-key.pub b/sshd-core/src/test/resources/org/apache/sshd/common/util/super-secret-passphrase-RSA-AES-192-key.pub
new file mode 100644
index 0000000..3fda036
--- /dev/null
+++ b/sshd-core/src/test/resources/org/apache/sshd/common/util/super-secret-passphrase-RSA-AES-192-key.pub
@@ -0,0 +1 @@
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCutvykV6G6t4JlLhlJOQKknSB++PXLTtuSjXaH77hUUEl/yc9VbEsfOz1NySBRQDWT0sgRZ1D2YAxaIvK9+0wZPnRNO1ptDrwj650Gflh8vKkEQOlHH7ISTxQTHtyHGeXfm3Bl+qqxTMPG5gcxxkKINMvKAkNYBnOyVX1OXUvqtM1jx6THlfWPQ9yFuVmZDVj1W5VItxjG293RejbjN1EjhhGRBiqwczcIPgPiMDfR0+xFNEQt6YD4k9TFEkLmIfCn+fcqKJhP/z99bRosMHtkRwfX/Rco+G9dRwe1sHvVH7ETeS7v3vl3WoM58AlpYYGUIXsxozRdGE93AmTkaSIj SecurityUtilsTest
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/06d37a2d/sshd-core/src/test/resources/org/apache/sshd/common/util/super-secret-passphrase-RSA-AES-256-key
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/resources/org/apache/sshd/common/util/super-secret-passphrase-RSA-AES-256-key b/sshd-core/src/test/resources/org/apache/sshd/common/util/super-secret-passphrase-RSA-AES-256-key
new file mode 100644
index 0000000..26b699e
--- /dev/null
+++ b/sshd-core/src/test/resources/org/apache/sshd/common/util/super-secret-passphrase-RSA-AES-256-key
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-256-CBC,4FF564F3E05187BEDEDA0529D44EE13E
+
+z7KGBVkxJzNS1Z8vMurcYmHhlbxnUYHry87VgzV38UkwsLSo5FIPNUaxvLPeD3Im
+YW4hQ/1Z+3onSwTgaUqxih6YK+fHS0RZD5R4HjOWaERCPZa5/oDciLrjOU3EKkSV
+n84/ezqUn8GlMJYcpB2sURCmnJZ6erHCVSPAhVlsrWPO9uZHx8BpaclqsvC4Gq7a
+C4liGjDNsFvVO998eDIDLmHeO+qGnyeQK+pu3/+Ausvd9QjUf4L3T+Lu+Cgr0w59
+tB3TxeGxPel9Av88VYIhCddIEvRyMcN8lzLrrYrsLNPMmaF1x2uNDORJCTlEjvLw
+QG6zugofiUVdZdsWRPFmM8DbujeoUHkPkwImXedhiKz1Tp0Rz6gqGx6tzsqEe0kD
+eS2e0Ibj41fFxpkQlaG/xDliUvntkoQ6v7ZKbXQrsBP4hyoMcjeUMhWL+5shkJEV
+RzvZOl7WKoovFnf3glLdiDFqlfLK5BhBJckLmdmnVvsD1HYeKqSDrx+r3hUF3yZ5
+Obxxk++QTC1qHhnyAwqW7Y2owq81pmOhgxKqh/4OoxYV0trIgzI47+5hKsp12Van
+7qBCfTtXv4IlBKaKARTroQ2sDPAi1B2j8mU5lrGm81BzsLSqh1IJjOMsccWNfjMS
+jQMKvcQN94y7AvxcBDGVn9FZftNWs9/ZwitRCFfrz/n0u6hLDQBbH6muDffo4ZhF
+ZiH23W743N/ZASC/kA7LZ3pmH6TNl2Zf1gP+tTrfXu17BRDJYi8VqHBcuck/M4Ox
+qOpP4mK2B/aAVmTkty67+QJerIwsW+h8LsjkQTnXGoneobsx2nL8OvJtPHkOUo4b
+1zFyFvQK+V8DWWAml4Y8V+4NCgrybqqK11ApRl7FfaOyCMgZ+AvqzjK3E5s1gsaf
+AaxORV0iDE0Y8nhq9EEhDNTr5Yi6FeHuRmVsack1AQqYn1U64k21x4ZEmDjslq9t
+WKizqG6jz6xtRtsypr0oCBYirt8p5qDmeO58MdES6A+nkOZC0ysyhizpDWdj01rQ
+6w3el0t/wUh1lBC3UCTeD7Vz20B1rAs5AlbdFmOUGHoH2Hjty1DQVZ+Fl5/K9AQi
+yaVR07IDE45i9rvl7DThRHT6Qd0KAb7bIo+Xlz/xKUgA0UVLkpfGtgDNi1DSTsBQ
+m6xlvR9M3tmMwnHlOEfX8YAGIQR9JLiImUtypjXnp6IdxCn682UIWC9XakqMFbzS
+Hm4Y0VBHYPisByl7PuavEP69pgYVdt1PqFFOc3xL42QVihYsM9huw1j4rlP7/jXB
+zJyH6yuqZHV7BYmurBByxRCe4joN24D6HYWTLKhPjgIG++n/IZ+PO7s0khrTh3Pl
+L3bOujyLtr88w6PPhBOCVDPgmJEC6lIGC8zhh+S9Knewr50PsvOoQVKGDTSPO+G7
+NNa/ugN9/eTeO2ru2y6HuahWrf2seKrTQB8JVYP0SZkOe4zVdMRR5M559iLIdh0e
+U/hrj6v/dYVbIkmSWdhtxx0jXbM2VlWTeQQjUYzeVumVhZ1pk2P0LeHrSWhHa5h2
+hadw69Ht0hRTbljZ1MHjK9BbQI1Ph+YBuDr0aPVBf2ePYFvPObw2Mik7ctiDlmQT
+-----END RSA PRIVATE KEY-----

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/06d37a2d/sshd-core/src/test/resources/org/apache/sshd/common/util/super-secret-passphrase-RSA-AES-256-key.pub
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/resources/org/apache/sshd/common/util/super-secret-passphrase-RSA-AES-256-key.pub b/sshd-core/src/test/resources/org/apache/sshd/common/util/super-secret-passphrase-RSA-AES-256-key.pub
new file mode 100644
index 0000000..6a3a0ac
--- /dev/null
+++ b/sshd-core/src/test/resources/org/apache/sshd/common/util/super-secret-passphrase-RSA-AES-256-key.pub
@@ -0,0 +1 @@
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDNUSajd7RzgqvQ2Q2em3CFA4Fh2f8YJkzJTPrcn9L9SFZnent2rABlVVr216jh3hAjhRFEkRhsoWUxUB7UYN6Ox/hGXrfCtD9wB0QbpOjNb0tnSovl3e+LfnWO5mpaRAb9croiuKVwQXuiwLNOQqs5C2wvLJhc77U4myuvFycYQ9Gh9g12g05Q8Qs+Du6hFSV1n1ZDMTtiVYknhe2gCLmBh1ghpaGeG3eWpd8EXumTrpwrylb1hJtj4yo748dXFa/YUJpqzCNyoA+0aY+v0MwgxZcS6zWt5VQ3yqRi4YrXX7vvhz80rKmJQlEhvM9rVKAwKc/qkJdTWlU+v0+/zY7/ hello@world
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/06d37a2d/sshd-core/src/test/resources/org/apache/sshd/common/util/super-secret-passphrase-RSA-DES-EDE3-key
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/resources/org/apache/sshd/common/util/super-secret-passphrase-RSA-DES-EDE3-key b/sshd-core/src/test/resources/org/apache/sshd/common/util/super-secret-passphrase-RSA-DES-EDE3-key
new file mode 100644
index 0000000..e6f6156
--- /dev/null
+++ b/sshd-core/src/test/resources/org/apache/sshd/common/util/super-secret-passphrase-RSA-DES-EDE3-key
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CBC,7DD956370CB0B83E
+
+oTBNWVUGIKQ3LX/bIE+upuTtiVSWQ9ooTxdNJRIpGsq6oTevtxgkuIF9oO+ShZJq
+zf/mTQPtAyRHSX8JsTKw9GZhd5w7c07V3wfzx689RHFCZDW1DIl67KvwyhRwfRtY
+HXZGYPW/XmOgh3Gw31csmLlJd42r8d+7MRIfmo25SO5Sy67mNccRJikdbYa/HH50
+yMVaf7o73tLLIS3WNnhaKjf9hRsSW370aICk3hfS/NMriae0xAMpqpYQmGkn9Zhh
+zTg+Kjo0FiEZEnMNKZQRRWx7VsoQRfrebOZq3LF7tfEnJcKneJ+grvQp0FpkEMzN
+JeiaEwtoIrXRU5KENQbEnXqF2Mpai6ejh5lVflcHqI01lwWGWkwxnNpxgMbWCKuB
+Unad3fQQLFQU67B8jQpES2AQVXO7UaaDHNtATftC2gFpBktlkSurT/KZBT4bVfS7
+z3K9gFB/lYrji2ef+xuzbLmq+eja9OlZIVxH7RTxODkyrxeNhtEUXJgezOB64Cny
+YFrsDPcR8rSRc5SjMMuAy2dSkyndSp3m2YmtVFHibPrX18K2lblRkiuVDci0EX4p
+1XzaCJ9mhdtMedpIzFdwgCOt/M8OBw9g02qgOK1uBu37tXdACNxhX/wrFPCtbJjD
+yBwnBbXoeca8ZF45uw1egKlHaY2d7kTsH+bdx04bTo4Xq0+lXMALxxkfwTOt27xL
+JQp15AFm6ZAshVt7hxCtm512HoSkkFYMPUPawH9HVZE6f4sbNBlbqgCmYhD5HPMN
+Kd3ssQWTXwiOSd+k8HuBUBhtdZsgdpSdR5xH9wEymS9fcGmrf2yLuRlxhvoqo44X
++go5CqLoAKoUtVJdtZrkmMdF1OxufDBZ16+fKN8NNE8vQv8Kt221yg/mmDy3t6mh
+axynBSxk1Qtjz2H9iZJ5nglF2Hceb1FQXHGlLCNv+cwA9vRC0pQJ25fPHVhvxhmW
+gnLJ5OY+zXENUWvMIeAGCSfjSVtnSVWAfdJ7kgHZc/wCWO6rYAwlfsPDq8ZdQ8Za
+4Hm6sUnkHHtagvJZahjdSPoziE68FiHqFU3PdmuQsZpCFOzloxahWImgx0UM9n8k
+2DlRPK6bMBCjpUrb5D0jp8YU2KDepw2D4O7RaFLh47w78oxrO1gABY23M4JQfUiP
+lzsfsGy9OI1twCcsJhFOX95nL9w+hlvFALTkY5UT3dB3eWP3k2nE12UxQhE3hVZ9
+vI100y2m/FUnKkeGYkvhRw9yD611jjYuRYGL3LsKNaOK97Ses+vAB0LNOss+12vz
+7bYvDUVJ5csfpPGqxyzYwIbytDwUcvxTLxRlgQNb2YMqzSmVodO0lyXdNF1/KUFF
+nIdlh0KSe4BALzYhya9V71MngLHFifp/erS4gdnFbbBCmZTEZhziBnqimRPoN5Co
+K+22blcRkDytiL+NTRybvfOYvy6Ulb4OK/So+Y5r1B5KGhJqFWSeo0g2ftAB6r1h
+HSbfoxYO/xCMQy7aNXuJI0giVRThcQsQapTO2DMeymt/0nj8qEPF0dubtbmgJ4dd
+aZuYaY1Qxk0umVfq9zHsRTbRb+16TuZtp+7brDDRpRe6lSzdbTNShg==
+-----END RSA PRIVATE KEY-----

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/06d37a2d/sshd-core/src/test/resources/org/apache/sshd/common/util/super-secret-passphrase-RSA-DES-EDE3-key.pub
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/resources/org/apache/sshd/common/util/super-secret-passphrase-RSA-DES-EDE3-key.pub b/sshd-core/src/test/resources/org/apache/sshd/common/util/super-secret-passphrase-RSA-DES-EDE3-key.pub
new file mode 100644
index 0000000..f5c8c85
--- /dev/null
+++ b/sshd-core/src/test/resources/org/apache/sshd/common/util/super-secret-passphrase-RSA-DES-EDE3-key.pub
@@ -0,0 +1 @@
+ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAxvz5QWkCxznYbBOUbMFsCf+PJLauyZTcPsHLPZ/lHYH7EIa9s8NWbfFyTJXVwcuJiDCoRZ8d7KBahAuNjGeXsuJQuCqlLLl6GKoFnI0hnbKbFHDDSub+s3WvLdaTeF22qlTmlPb3RFYUO0cWk9MVpVNM6ev33CUGv4Dmbr0dZNkgUOkcPHiQpxKizsED+EWSVh1Ptx8AEDObNyFHJljbHUeJrHTIlcaekJheRXQWLvsJqKD0TN+Dkvi044MDWG9VjVyNsyXBCz1Vk9VaK1dNkkH+RDGTsFvFj7IPwBS/FliEVRrKOUgjMrmKUPbAm8IblIsno+HLZ60OB6X6hu2iHw== lgoldstein@LGOLDSTEIN-WIN7

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/06d37a2d/sshd-git/src/test/java/org/apache/sshd/git/util/Utils.java
----------------------------------------------------------------------
diff --git a/sshd-git/src/test/java/org/apache/sshd/git/util/Utils.java b/sshd-git/src/test/java/org/apache/sshd/git/util/Utils.java
index 2ecbd01..81e88cc 100644
--- a/sshd-git/src/test/java/org/apache/sshd/git/util/Utils.java
+++ b/sshd-git/src/test/java/org/apache/sshd/git/util/Utils.java
@@ -23,16 +23,16 @@ import java.net.ServerSocket;
 import java.net.URISyntaxException;
 import java.net.URL;
 
-import org.apache.sshd.common.keyprovider.FileKeyPairProvider;
+import org.apache.sshd.common.keyprovider.AbstractFileKeyPairProvider;
 
 public class Utils {
 
-    public static FileKeyPairProvider createTestHostKeyProvider() {
+    public static AbstractFileKeyPairProvider createTestHostKeyProvider() {
         return createTestKeyPairProvider("hostkey.pem");
     }
 
-    public static FileKeyPairProvider createTestKeyPairProvider(String resource) {
-        return new FileKeyPairProvider(new String[] { getFile(resource) });
+    public static AbstractFileKeyPairProvider createTestKeyPairProvider(String resource) {
+        return new AbstractFileKeyPairProvider(new String[] { getFile(resource) });
     }
 
     public static int getFreePort() throws Exception {


[2/2] mina-sshd git commit: [SSHD-495] Move all code that calls Bouncycastle code to SecurityUtils

Posted by lg...@apache.org.
[SSHD-495] Move all code that calls Bouncycastle code to SecurityUtils


Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/06d37a2d
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/06d37a2d
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/06d37a2d

Branch: refs/heads/master
Commit: 06d37a2d5d3727b28f833f56a01b4d7637e084ae
Parents: 189d8cb
Author: Lyor Goldstein <lg...@vmware.com>
Authored: Sun Jun 21 15:51:25 2015 +0300
Committer: Lyor Goldstein <lg...@vmware.com>
Committed: Sun Jun 21 15:51:25 2015 +0300

----------------------------------------------------------------------
 .../java/org/apache/sshd/client/SshClient.java  |  39 ++-
 .../org/apache/sshd/common/BaseBuilder.java     |   8 +-
 .../config/keys/FilePasswordProvider.java       |  35 +++
 ...actClassLoadableResourceKeyPairProvider.java |  89 +++++++
 .../AbstractFileKeyPairProvider.java            |  94 +++++++
 .../AbstractResourceKeyPairProvider.java        | 199 ++++++++++++++
 .../common/keyprovider/FileKeyPairProvider.java | 156 -----------
 .../keyprovider/ResourceKeyPairProvider.java    | 206 --------------
 .../sshd/common/random/BouncyCastleRandom.java  | 103 -------
 .../apache/sshd/common/random/JceRandom.java    |  23 --
 .../sshd/common/random/JceRandomFactory.java    |  46 ++++
 .../sshd/common/random/RandomFactory.java       |  37 +++
 .../common/random/SingletonRandomFactory.java   |  12 +-
 .../apache/sshd/common/util/SecurityUtils.java  | 266 ++++++++++++++++++-
 .../apache/sshd/common/util/ValidateUtils.java  |   6 +
 .../org/apache/sshd/common/util/io/IoUtils.java |   7 +-
 .../common/util/io/ModifiableFileWatcher.java   |   2 +-
 .../java/org/apache/sshd/server/SshServer.java  |   7 +-
 .../AbstractGeneratorHostKeyProvider.java       | 136 +++++-----
 .../PEMGeneratorHostKeyProvider.java            |  79 ------
 .../SimpleGeneratorHostKeyProvider.java         |  32 ++-
 .../apache/sshd/server/sftp/SftpSubsystem.java  |   2 +-
 .../apache/sshd/SinglePublicKeyAuthTest.java    |   8 +-
 .../java/org/apache/sshd/client/ClientTest.java |   5 +-
 .../client/session/ClientSessionImplTest.java   |   4 +-
 .../apache/sshd/common/cipher/CipherTest.java   |   5 +-
 .../org/apache/sshd/common/mac/MacTest.java     |   5 +-
 .../apache/sshd/common/random/RandomTest.java   |  16 +-
 .../sshd/common/util/SecurityUtilsTest.java     | 173 ++++++++++++
 .../AbstractGeneratorHostKeyProviderTest.java   |   9 +-
 .../PEMGeneratorHostKeyProviderTest.java        |   6 +-
 .../SimpleGeneratorHostKeyProviderTest.java     |   2 +-
 .../org/apache/sshd/util/BaseTestSupport.java   |  35 ++-
 .../test/java/org/apache/sshd/util/Utils.java   |  40 ++-
 .../common/util/SecurityUtilsTest-DSA-KeyPair   |  12 +
 .../util/SecurityUtilsTest-DSA-KeyPair.pub      |   1 +
 .../util/SecurityUtilsTest-EC-256-KeyPair       |   5 +
 .../util/SecurityUtilsTest-EC-256-KeyPair.pub   |   1 +
 .../util/SecurityUtilsTest-EC-384-KeyPair       |   6 +
 .../util/SecurityUtilsTest-EC-384-KeyPair.pub   |   1 +
 .../util/SecurityUtilsTest-EC-521-KeyPair       |   7 +
 .../util/SecurityUtilsTest-EC-521-KeyPair.pub   |   1 +
 .../common/util/SecurityUtilsTest-RSA-KeyPair   |  27 ++
 .../util/SecurityUtilsTest-RSA-KeyPair.pub      |   1 +
 .../super-secret-passphrase-RSA-AES-128-key     |  30 +++
 .../super-secret-passphrase-RSA-AES-128-key.pub |   1 +
 .../super-secret-passphrase-RSA-AES-192-key     |  30 +++
 .../super-secret-passphrase-RSA-AES-192-key.pub |   1 +
 .../super-secret-passphrase-RSA-AES-256-key     |  30 +++
 .../super-secret-passphrase-RSA-AES-256-key.pub |   1 +
 .../super-secret-passphrase-RSA-DES-EDE3-key    |  30 +++
 ...super-secret-passphrase-RSA-DES-EDE3-key.pub |   1 +
 .../java/org/apache/sshd/git/util/Utils.java    |   8 +-
 53 files changed, 1344 insertions(+), 742 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/06d37a2d/sshd-core/src/main/java/org/apache/sshd/client/SshClient.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/SshClient.java b/sshd-core/src/main/java/org/apache/sshd/client/SshClient.java
index f223119..8bea7ed 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/SshClient.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/SshClient.java
@@ -32,7 +32,6 @@ import java.util.Date;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.concurrent.Callable;
 import java.util.logging.ConsoleHandler;
 import java.util.logging.Formatter;
 import java.util.logging.Handler;
@@ -58,10 +57,11 @@ import org.apache.sshd.common.NamedFactory;
 import org.apache.sshd.common.SshdSocketAddress;
 import org.apache.sshd.common.channel.Channel;
 import org.apache.sshd.common.config.SshConfigFileReader;
+import org.apache.sshd.common.config.keys.FilePasswordProvider;
 import org.apache.sshd.common.future.SshFutureListener;
 import org.apache.sshd.common.io.IoConnectFuture;
 import org.apache.sshd.common.io.IoConnector;
-import org.apache.sshd.common.keyprovider.FileKeyPairProvider;
+import org.apache.sshd.common.keyprovider.AbstractFileKeyPairProvider;
 import org.apache.sshd.common.keyprovider.KeyPairProvider;
 import org.apache.sshd.common.session.AbstractSession;
 import org.apache.sshd.common.util.GenericUtils;
@@ -69,7 +69,6 @@ import org.apache.sshd.common.util.SecurityUtils;
 import org.apache.sshd.common.util.ValidateUtils;
 import org.apache.sshd.common.util.io.NoCloseInputStream;
 import org.apache.sshd.common.util.io.NoCloseOutputStream;
-import org.bouncycastle.openssl.PasswordFinder;
 
 /**
  * Entry point for the client side of the SSH protocol.
@@ -437,43 +436,35 @@ public class SshClient extends AbstractFactoryManager implements ClientFactoryMa
         }
 
         KeyPairProvider provider = null;
-        final List<String> files = new ArrayList<String>();
+        final List<File> files = new ArrayList<File>();
         File f = new File(System.getProperty("user.home"), ".ssh/id_dsa");
         if (f.exists() && f.isFile() && f.canRead()) {
-            files.add(f.getAbsolutePath());
+            files.add(f);
         }
         f = new File(System.getProperty("user.home"), ".ssh/id_rsa");
         if (f.exists() && f.isFile() && f.canRead()) {
-            files.add(f.getAbsolutePath());
+            files.add(f);
         }
         f = new File(System.getProperty("user.home"), ".ssh/id_ecdsa");
         if (f.exists() && f.isFile() && f.canRead()) {
-            files.add(f.getAbsolutePath());
+            files.add(f);
         }
         if (files.size() > 0) {
             // SSHD-292: we need to use a different class to load the FileKeyPairProvider
             //  in order to break the link between SshClient and BouncyCastle
             try {
                 if (SecurityUtils.isBouncyCastleRegistered()) {
-                    class KeyPairProviderLoader implements Callable<KeyPairProvider> {
+                    AbstractFileKeyPairProvider filesProvider=SecurityUtils.createFileKeyPairProvider();
+                    filesProvider.setFiles(files);
+                    filesProvider.setPasswordFinder(new FilePasswordProvider() {
+                        private final BufferedReader r = new BufferedReader(new InputStreamReader(System.in));
                         @Override
-                        public KeyPairProvider call() throws Exception {
-                            return new FileKeyPairProvider(files.toArray(new String[files.size()]), new PasswordFinder() {
-                                @Override
-                                public char[] getPassword() {
-                                    try {
-                                        System.out.println("Enter password for private key: ");
-                                        BufferedReader r = new BufferedReader(new InputStreamReader(System.in));
-                                        String password = r.readLine();
-                                        return password.toCharArray();
-                                    } catch (IOException e) {
-                                        return null;
-                                    }
-                                }
-                            });
+                        public String getPassword(String file) throws IOException {
+                            System.out.print("Enter password for private key file=" + file + ": ");
+                            return r.readLine();
                         }
-                    }
-                    provider = new KeyPairProviderLoader().call();
+                    });
+                    provider = filesProvider;
                 }
             } catch (Throwable t) {
                 System.out.println("Error loading user keys: " + t.getMessage());

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/06d37a2d/sshd-core/src/main/java/org/apache/sshd/common/BaseBuilder.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/BaseBuilder.java b/sshd-core/src/main/java/org/apache/sshd/common/BaseBuilder.java
index ee0b2b1..09e62b3 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/BaseBuilder.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/BaseBuilder.java
@@ -37,8 +37,6 @@ import org.apache.sshd.common.kex.BuiltinDHFactories;
 import org.apache.sshd.common.kex.KeyExchange;
 import org.apache.sshd.common.mac.BuiltinMacs;
 import org.apache.sshd.common.mac.Mac;
-import org.apache.sshd.common.random.BouncyCastleRandom;
-import org.apache.sshd.common.random.JceRandom;
 import org.apache.sshd.common.random.Random;
 import org.apache.sshd.common.random.SingletonRandomFactory;
 import org.apache.sshd.common.session.ConnectionService;
@@ -76,11 +74,7 @@ public class BaseBuilder<T extends AbstractFactoryManager, S extends BaseBuilder
         }
 
         if (randomFactory == null) {
-            if (SecurityUtils.isBouncyCastleRegistered()) {
-                randomFactory = new SingletonRandomFactory(BouncyCastleRandom.BouncyCastleRandomFactory.INSTANCE);
-            } else {
-                randomFactory = new SingletonRandomFactory(JceRandom.JceRandomFactory.INSTANCE);
-            }
+            randomFactory = new SingletonRandomFactory(SecurityUtils.getRandomFactory());
         }
 
         if (cipherFactories == null) {

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/06d37a2d/sshd-core/src/main/java/org/apache/sshd/common/config/keys/FilePasswordProvider.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/FilePasswordProvider.java b/sshd-core/src/main/java/org/apache/sshd/common/config/keys/FilePasswordProvider.java
new file mode 100644
index 0000000..3a6f920
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/config/keys/FilePasswordProvider.java
@@ -0,0 +1,35 @@
+/*
+ * 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;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public interface FilePasswordProvider {
+    /**
+     * @param resourceKey The resource key representing the <U>private</U>
+     * file
+     * @return The password - if {@code null}/empty then no password is required
+     * @throws IOException if cannot resolve password
+     */
+    String getPassword(String resourceKey) throws IOException;
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/06d37a2d/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/AbstractClassLoadableResourceKeyPairProvider.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/AbstractClassLoadableResourceKeyPairProvider.java b/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/AbstractClassLoadableResourceKeyPairProvider.java
new file mode 100644
index 0000000..183bf06
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/AbstractClassLoadableResourceKeyPairProvider.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.keyprovider;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StreamCorruptedException;
+import java.security.KeyPair;
+import java.util.Collection;
+import java.util.Collections;
+
+import org.apache.sshd.common.util.threads.ThreadUtils;
+
+/**
+ * This provider loads private keys from the specified resources that
+ * are accessible via {@link ClassLoader#getResourceAsStream(String)}.
+ * If no loader configured via {@link #setResourceLoader(ClassLoader)}, then
+ * {@link ThreadUtils#resolveDefaultClassLoader(Class)} is used
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public abstract class AbstractClassLoadableResourceKeyPairProvider extends AbstractResourceKeyPairProvider<String> {
+    private ClassLoader classLoader;
+    private Collection<String>  resources;
+
+    protected AbstractClassLoadableResourceKeyPairProvider() {
+        classLoader = ThreadUtils.resolveDefaultClassLoader(getClass());
+    }
+
+    public Collection<String> getResources() {
+        return resources;
+    }
+
+    public void setResources(Collection<String> resources) {
+        this.resources = (resources == null) ? Collections.<String>emptyList() : resources;
+    }
+
+    public ClassLoader getResourceLoader() {
+        return classLoader;
+    }
+
+    public void setResourceLoader(ClassLoader classLoader) {
+        this.classLoader = classLoader;
+    }
+
+    @Override
+    public Iterable<KeyPair> loadKeys() {
+        return loadKeys(getResources());
+    }
+
+    @Override
+    protected InputStream openKeyPairResource(String resourceKey, String resource) throws IOException {
+        ClassLoader cl = resolveClassLoader();
+        if (cl == null) {
+            throw new StreamCorruptedException("No resource loader for " + resource);
+        }
+        
+        InputStream input = cl.getResourceAsStream(resource);
+        if (input == null) {
+            throw new FileNotFoundException("Cannot find resource " + resource);
+        }
+
+        return input;
+    }
+
+    protected ClassLoader resolveClassLoader() {
+        ClassLoader cl = getResourceLoader();
+        if (cl == null) {
+            cl = ThreadUtils.resolveDefaultClassLoader(getClass());
+        }
+        return cl;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/06d37a2d/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/AbstractFileKeyPairProvider.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/AbstractFileKeyPairProvider.java b/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/AbstractFileKeyPairProvider.java
new file mode 100644
index 0000000..13b4bf3
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/AbstractFileKeyPairProvider.java
@@ -0,0 +1,94 @@
+/*
+ * 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.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.security.GeneralSecurityException;
+import java.security.KeyPair;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.io.IoUtils;
+
+/**
+ * This host key provider loads private keys from the specified files. The
+ * loading is <U>lazy</U> - i.e., a file is not loaded until it is actually
+ * required. Once required though, its loaded {@link KeyPair} result is
+ * <U>cached</U> and not re-loaded.
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public abstract class AbstractFileKeyPairProvider extends AbstractResourceKeyPairProvider<Path> {
+    private Collection<? extends Path> files;
+
+    protected AbstractFileKeyPairProvider() {
+        super();
+    }
+
+    public Collection<? extends Path> getPaths() {
+        return files;
+    }
+
+    public void setFiles(Collection<File> files) {
+        if (GenericUtils.isEmpty(files)) {
+            setPaths(Collections.<Path>emptyList());
+        } else {
+            List<Path> paths = new ArrayList<Path>(files.size());
+            for (File f : files) {
+                paths.add(f.toPath());
+            }
+            setPaths(paths);
+        }
+    }
+
+    public void setPaths(Collection<? extends Path> paths) {
+        int numPaths = GenericUtils.size(paths);
+        Collection<Path> resolved = (numPaths <= 0) ? Collections.<Path>emptyList() : new ArrayList<Path>(paths.size());
+        // use absolute path in order to have unique cache keys
+        if (numPaths > 0) {
+            for (Path p : paths) {
+                resolved.add(p.toAbsolutePath());
+            }
+        }
+
+        resetCacheMap(resolved);
+        files = resolved;
+    }
+
+    @Override
+    public Iterable<KeyPair> loadKeys() {
+        return loadKeys(getPaths());
+    }
+
+    @Override
+    protected KeyPair doLoadKey(Path resource) throws IOException, GeneralSecurityException {
+        return super.doLoadKey((resource == null) ? null : resource.toAbsolutePath());
+    }
+
+    @Override
+    protected InputStream openKeyPairResource(String resourceKey, Path resource) throws IOException {
+        return Files.newInputStream(resource, IoUtils.EMPTY_OPEN_OPTIONS);
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/06d37a2d/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/AbstractResourceKeyPairProvider.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/AbstractResourceKeyPairProvider.java b/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/AbstractResourceKeyPairProvider.java
new file mode 100644
index 0000000..79c4ab9
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/AbstractResourceKeyPairProvider.java
@@ -0,0 +1,199 @@
+/*
+ * 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.io.IOException;
+import java.io.InputStream;
+import java.security.GeneralSecurityException;
+import java.security.KeyPair;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+import org.apache.sshd.common.config.keys.FilePasswordProvider;
+import org.apache.sshd.common.util.GenericUtils;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public abstract class AbstractResourceKeyPairProvider<R> extends AbstractKeyPairProvider {
+    private FilePasswordProvider passwordFinder;
+    /* 
+     * NOTE: the map is case insensitive even for Linux, as it is (very) bad
+     * practice to have 2 key files that differ from one another only in their
+     * case... 
+     */
+    private final Map<String,KeyPair>   cacheMap=new TreeMap<String, KeyPair>(String.CASE_INSENSITIVE_ORDER);
+
+    protected AbstractResourceKeyPairProvider() {
+        super();
+    }
+
+    public FilePasswordProvider getPasswordFinder() {
+        return passwordFinder;
+    }
+
+    public void setPasswordFinder(FilePasswordProvider passwordFinder) {
+        this.passwordFinder = passwordFinder;
+    }
+
+    protected void resetCacheMap(Collection<?> resources) {
+        // if have any cached pairs then see what we can keep from previous load
+        Collection<String>  toDelete=Collections.<String>emptySet();
+        synchronized(cacheMap) {
+            if (cacheMap.size() <= 0) {
+                return; // already empty - nothing to keep
+            }
+
+            if (GenericUtils.isEmpty(resources)) {
+                cacheMap.clear();
+                return;
+            }
+
+            for (Object r : resources) {
+                String resourceKey = Objects.toString(r);
+                if (cacheMap.containsKey(resourceKey)) {
+                    continue;
+                }
+                
+                if (toDelete.isEmpty()) {
+                    toDelete = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
+                }
+                
+                if (!toDelete.add(resourceKey)) {
+                    continue;   // debug breakpoint
+                }
+            }
+
+            if (GenericUtils.size(toDelete) > 0) {
+                for (String f : toDelete) {
+                    cacheMap.remove(f);
+                }
+            }
+        }
+        
+        if (log.isDebugEnabled()) {
+            log.debug("resetCacheMap(" + resources + ") removed previous cached keys for " + toDelete);
+        }
+    }
+    
+    protected Iterable<KeyPair> loadKeys(final Collection<? extends R> resources) {
+        if (GenericUtils.isEmpty(resources)) {
+            return Collections.emptyList();
+        } else {
+            return new Iterable<KeyPair>() {
+                @Override
+                public Iterator<KeyPair> iterator() {
+                    return new Iterator<KeyPair>() {
+                        private final Iterator<? extends R> iterator = resources.iterator();
+                        private KeyPair nextKeyPair;
+                        private boolean nextKeyPairSet = false;
+    
+                        @Override
+                        public boolean hasNext() {
+                            return nextKeyPairSet || setNextObject();
+                        }
+    
+                        @Override
+                        public KeyPair next() {
+                            if (!nextKeyPairSet) {
+                                if (!setNextObject()) {
+                                    throw new NoSuchElementException("Out of files to try");
+                                }
+                            }
+                            nextKeyPairSet = false;
+                            return nextKeyPair;
+                        }
+    
+                        @Override
+                        public void remove() {
+                            throw new UnsupportedOperationException("loadKeys(files) Iterator#remove() N/A");
+                        }
+    
+                        @SuppressWarnings("synthetic-access")
+                        private boolean setNextObject() {
+                            while (iterator.hasNext()) {
+                                R r = iterator.next();
+                                try {
+                                    nextKeyPair = doLoadKey(r);
+                                } catch(Exception e) {
+                                    log.warn("Failed (" + e.getClass().getSimpleName() + ")"
+                                            + " to load key resource=" + r + ": " + e.getMessage());
+                                    nextKeyPair = null;
+                                    continue;
+                                }
+    
+                                if (nextKeyPair != null) {
+                                    nextKeyPairSet = true;
+                                    return true;
+                                }
+                            }
+    
+                            return false;
+                        }
+                    };
+                }
+            };
+        }
+    }
+
+    protected KeyPair doLoadKey(R resource) throws IOException, GeneralSecurityException {
+        String resourceKey = Objects.toString(resource);
+        KeyPair kp;
+        synchronized(cacheMap) {
+            // check if lucky enough to have already loaded this file
+            if ((kp=cacheMap.get(resourceKey)) != null) {
+                return kp;
+            }
+        }
+
+        if ((kp=doLoadKey(resourceKey, resource, getPasswordFinder())) != null) {
+            synchronized(cacheMap) {
+                // if somebody else beat us to it, use the cached key
+                if (cacheMap.containsKey(resourceKey)) {
+                    kp = cacheMap.get(resourceKey);
+                } else {
+                    cacheMap.put(resourceKey, kp);
+                }
+            }
+            
+            if (log.isDebugEnabled()) {
+                log.debug("doLoadKey(" + resourceKey + ") loaded " + kp.getPublic() + " / " + kp.getPrivate());
+            }
+        }
+        
+        return kp;
+    }
+
+    protected KeyPair doLoadKey(String resourceKey, R resource, FilePasswordProvider provider) throws IOException, GeneralSecurityException {
+        try(InputStream inputStream = openKeyPairResource(resourceKey, resource)) {
+            return doLoadKey(resourceKey, inputStream, provider);
+        }
+    }
+    
+    protected abstract InputStream openKeyPairResource(String resourceKey, R resource) throws IOException;
+    
+    protected abstract KeyPair doLoadKey(String resourceKey, InputStream inputStream, FilePasswordProvider provider) throws IOException, GeneralSecurityException;
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/06d37a2d/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/FileKeyPairProvider.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/FileKeyPairProvider.java b/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/FileKeyPairProvider.java
deleted file mode 100644
index 01d6df9..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/FileKeyPairProvider.java
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * 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.io.FileInputStream;
-import java.io.InputStreamReader;
-import java.security.KeyPair;
-import java.util.Arrays;
-import java.util.Iterator;
-import java.util.NoSuchElementException;
-
-import org.apache.sshd.common.util.SecurityUtils;
-import org.bouncycastle.openssl.PEMDecryptorProvider;
-import org.bouncycastle.openssl.PEMEncryptedKeyPair;
-import org.bouncycastle.openssl.PEMKeyPair;
-import org.bouncycastle.openssl.PEMParser;
-import org.bouncycastle.openssl.PasswordFinder;
-import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
-import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder;
-
-/**
- * This host key provider loads private keys from the specified files.
- * 
- * Note that this class has a direct dependency on BouncyCastle and won't work
- * unless it has been correctly registered as a security provider.
- *
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class FileKeyPairProvider extends AbstractKeyPairProvider {
-
-    private String[] files;
-    private PasswordFinder passwordFinder;
-
-    public FileKeyPairProvider() {
-        super();
-    }
-
-    public FileKeyPairProvider(String ... files) {
-        this(files, null);
-    }
-
-    public FileKeyPairProvider(String[] files, PasswordFinder passwordFinder) {
-        this.files = files;
-        this.passwordFinder = passwordFinder;
-    }
-
-    public String[] getFiles() {
-        return files;
-    }
-
-    public void setFiles(String[] files) {
-        this.files = files;
-    }
-
-    public PasswordFinder getPasswordFinder() {
-        return passwordFinder;
-    }
-
-    public void setPasswordFinder(PasswordFinder passwordFinder) {
-        this.passwordFinder = passwordFinder;
-    }
-
-    @Override
-    public Iterable<KeyPair> loadKeys() {
-        if (!SecurityUtils.isBouncyCastleRegistered()) {
-            throw new IllegalStateException("BouncyCastle must be registered as a JCE provider");
-        }
-        return new Iterable<KeyPair>() {
-            @Override
-            public Iterator<KeyPair> iterator() {
-                return new Iterator<KeyPair>() {
-                    @SuppressWarnings("synthetic-access")
-                    private final Iterator<String> iterator = Arrays.asList(files).iterator();
-                    private KeyPair nextKeyPair;
-                    private boolean nextKeyPairSet = false;
-                    @Override
-                    public boolean hasNext() {
-                        return nextKeyPairSet || setNextObject();
-                    }
-                    @Override
-                    public KeyPair next() {
-                        if (!nextKeyPairSet) {
-                            if (!setNextObject()) {
-                                throw new NoSuchElementException();
-                            }
-                        }
-                        nextKeyPairSet = false;
-                        return nextKeyPair;
-                    }
-                    @Override
-                    public void remove() {
-                        throw new UnsupportedOperationException("loadKeys(files) Iterator#remove() N/A");
-                    }
-                    private boolean setNextObject() {
-                        while (iterator.hasNext()) {
-                            String file = iterator.next();
-                            nextKeyPair = doLoadKey(file);
-                            if (nextKeyPair != null) {
-                                nextKeyPairSet = true;
-                                return true;
-                            }
-                        }
-                        return false;
-                    }
-
-                };
-            }
-        };
-    }
-
-    protected KeyPair doLoadKey(String file) {
-        try {
-            PEMParser r = new PEMParser(new InputStreamReader(new FileInputStream(file)));
-            try {
-                Object o = r.readObject();
-
-                JcaPEMKeyConverter pemConverter = new JcaPEMKeyConverter();
-                pemConverter.setProvider("BC");
-                if (passwordFinder != null && o instanceof PEMEncryptedKeyPair) {
-                    JcePEMDecryptorProviderBuilder decryptorBuilder = new JcePEMDecryptorProviderBuilder();
-                    PEMDecryptorProvider pemDecryptor = decryptorBuilder.build(passwordFinder.getPassword());
-                    o = pemConverter.getKeyPair(((PEMEncryptedKeyPair) o).decryptKeyPair(pemDecryptor));
-                }
-
-                if (o instanceof PEMKeyPair) {
-                    o = pemConverter.getKeyPair((PEMKeyPair)o);
-                    return (KeyPair) o;
-                } else if (o instanceof KeyPair) {
-                    return (KeyPair) o;
-                }
-            } finally {
-                r.close();
-            }
-        } catch (Exception e) {
-            log.warn("Unable to read key " + file, e);
-        }
-        return null;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/06d37a2d/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/ResourceKeyPairProvider.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/ResourceKeyPairProvider.java b/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/ResourceKeyPairProvider.java
deleted file mode 100644
index 134416e..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/ResourceKeyPairProvider.java
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * 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.io.InputStream;
-import java.io.InputStreamReader;
-import java.security.KeyPair;
-import java.util.Arrays;
-import java.util.Iterator;
-import java.util.NoSuchElementException;
-
-import org.apache.sshd.common.util.GenericUtils;
-import org.apache.sshd.common.util.SecurityUtils;
-import org.bouncycastle.openssl.PEMDecryptorProvider;
-import org.bouncycastle.openssl.PEMEncryptedKeyPair;
-import org.bouncycastle.openssl.PEMKeyPair;
-import org.bouncycastle.openssl.PEMParser;
-import org.bouncycastle.openssl.PasswordFinder;
-import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
-import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder;
-
-/**
- * <p>This host key provider loads private keys from the specified resources.</p>
- *
- * <p>Note that this class has a direct dependency on BouncyCastle and won't work
- * unless it has been correctly registered as a security provider.</p>
- *
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class ResourceKeyPairProvider extends AbstractKeyPairProvider {
-    // --- Properties ---
-
-    /**
-     * Class loader
-     */
-    protected final ClassLoader cloader;
-
-    /**
-     * Key resources
-     */
-    private String[] resources;
-
-    /**
-     * Password finder
-     */
-    private PasswordFinder passwordFinder;
-
-    // ---
-
-    /**
-     * No-arg constructor.
-     */
-    public ResourceKeyPairProvider() {
-        this(GenericUtils.EMPTY_STRING_ARRAY);
-    } // end of <init>
-
-    /**
-     * Bulk constructor 1.
-     */
-    public ResourceKeyPairProvider(String ... resources) {
-        this(resources, null);
-    } // end of <init>
-
-    /**
-     * Bulk constructor 2.
-     */
-    public ResourceKeyPairProvider(String[] resources, PasswordFinder passwordFinder) {
-        this(resources, passwordFinder, null);
-    } // end of <init>
-
-    /**
-     * Bulk constructor 3.
-     */
-    public ResourceKeyPairProvider(String[] resources, PasswordFinder passwordFinder, ClassLoader cloader) {
-
-        this.cloader = (cloader == null) ? this.getClass().getClassLoader() : cloader;
-        this.resources = resources;
-        this.passwordFinder = passwordFinder;
-    } // end of <init>
-
-    // --- Properties accessors ---
-
-    /**
-     * {@inheritDoc}
-     */
-    public String[] getResources() {
-        return this.resources;
-    } // end of getResources
-
-    /**
-     * {@inheritDoc}
-     */
-    public void setResources(String[] resources) {
-        this.resources = resources;
-    } // end of setResources
-
-    /**
-     * {@inheritDoc}
-     */
-    public PasswordFinder getPasswordFinder() {
-        return this.passwordFinder;
-    } // end of getPasswordFinder
-
-    /**
-     * {@inheritDoc}
-     */
-    public void setPasswordFinder(PasswordFinder passwordFinder) {
-        this.passwordFinder = passwordFinder;
-    } // end of setPasswordFinder
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public Iterable<KeyPair> loadKeys() {
-        if (!SecurityUtils.isBouncyCastleRegistered()) {
-            throw new IllegalStateException("BouncyCastle must be registered as a JCE provider");
-        } // end of if
-        return new Iterable<KeyPair>() {
-            @Override
-            public Iterator<KeyPair> iterator() {
-                return new Iterator<KeyPair>() {
-                    @SuppressWarnings("synthetic-access")
-                    private final Iterator<String> iterator = Arrays.asList(resources).iterator();
-                    private KeyPair nextKeyPair;
-                    private boolean nextKeyPairSet = false;
-                    @Override
-                    public boolean hasNext() {
-                        return nextKeyPairSet || setNextObject();
-                    }
-                    @Override
-                    public KeyPair next() {
-                        if (!nextKeyPairSet) {
-                            if (!setNextObject()) {
-                                throw new NoSuchElementException("No next element in iterator");
-                            }
-                        }
-                        nextKeyPairSet = false;
-                        return nextKeyPair;
-                    }
-                    @Override
-                    public void remove() {
-                        throw new UnsupportedOperationException("Not allowed to remove items");
-                    }
-                    private boolean setNextObject() {
-                        while (iterator.hasNext()) {
-                            String file = iterator.next();
-                            nextKeyPair = doLoadKey(file);
-                            if (nextKeyPair != null) {
-                                nextKeyPairSet = true;
-                                return true;
-                            }
-                        }
-                        return false;
-                    }
-
-                };
-            }
-        };
-    }
-
-    protected KeyPair doLoadKey(String resource) {
-        try(InputStream is = this.cloader.getResourceAsStream(resource);
-            InputStreamReader isr = new InputStreamReader(is);
-            PEMParser r = new PEMParser(isr)) {
-
-            Object o = r.readObject();
-
-            JcaPEMKeyConverter pemConverter = new JcaPEMKeyConverter();
-            pemConverter.setProvider("BC");
-            if ((passwordFinder != null) && (o instanceof PEMEncryptedKeyPair)) {
-                JcePEMDecryptorProviderBuilder decryptorBuilder = new JcePEMDecryptorProviderBuilder();
-                PEMDecryptorProvider pemDecryptor = decryptorBuilder.build(passwordFinder.getPassword());
-                o = pemConverter.getKeyPair(((PEMEncryptedKeyPair) o).decryptKeyPair(pemDecryptor));
-            }
-
-            if (o instanceof PEMKeyPair) {
-                o = pemConverter.getKeyPair((PEMKeyPair)o);
-                return (KeyPair) o;
-            } else if (o instanceof KeyPair) {
-                return (KeyPair) o;
-            } // end of if
-        } catch (Exception e) {
-            log.warn("Unable to read key " + resource, e);
-        }
-
-        return null;
-    } // end of doLoadKey
-
-} // end of class ResourceKeyPairProvider

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/06d37a2d/sshd-core/src/main/java/org/apache/sshd/common/random/BouncyCastleRandom.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/random/BouncyCastleRandom.java b/sshd-core/src/main/java/org/apache/sshd/common/random/BouncyCastleRandom.java
deleted file mode 100644
index acf69d5..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/common/random/BouncyCastleRandom.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * 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.security.SecureRandom;
-
-import org.apache.sshd.common.NamedFactory;
-import org.bouncycastle.crypto.prng.RandomGenerator;
-import org.bouncycastle.crypto.prng.VMPCRandomGenerator;
-
-/**
- * BouncyCastle <code>Random</code>.
- * This pseudo random number generator uses the a very fast PRNG from BouncyCastle.
- * The JRE random will be used when creating a new generator to add some random
- * data to the seed.
- *
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class BouncyCastleRandom implements Random {
-
-    /**
-     * Named factory for the BouncyCastle <code>Random</code>
-     */
-    public static class BouncyCastleRandomFactory implements NamedFactory<Random> {
-        public static final BouncyCastleRandomFactory INSTANCE = new BouncyCastleRandomFactory();
-
-        public BouncyCastleRandomFactory() {
-            super();
-        }
-
-        @Override
-        public String getName() {
-            return "bouncycastle";
-        }
-
-        @Override
-        public Random create() {
-            return new BouncyCastleRandom();
-        }
-
-    }
-
-    private final RandomGenerator random;
-
-    public BouncyCastleRandom() {
-        this.random = new VMPCRandomGenerator();
-        byte[] seed = new SecureRandom().generateSeed(8);
-        this.random.addSeedMaterial(seed);
-    }
-
-    @Override
-    public void fill(byte[] bytes, int start, int len) {
-        this.random.nextBytes(bytes, start, len);
-    }
-
-    /**
-     * Returns a pseudo-random uniformly distributed {@code int}
-     * in the half-open range [0, n).
-     */
-    @Override
-    public int random(int n) {
-        if (n > 0) {
-            if ((n & -n) == n) {
-                return (int)((n * (long) next(31)) >> 31);
-            }
-            int bits, val;
-            do {
-                bits = next(31);
-                val = bits % n;
-            } while (bits - val + (n-1) < 0);
-            return val;
-        }
-        throw new IllegalArgumentException("Limit must be positive: " + n);
-    }
-
-    final protected int next(int numBits) {
-        int bytes = (numBits+7)/8;
-        byte next[] = new byte[bytes];
-        int ret = 0;
-        random.nextBytes(next);
-        for (int i = 0; i < bytes; i++) {
-            ret = (next[i] & 0xFF) | (ret << 8);
-        }
-        return ret >>> (bytes*8 - numBits);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/06d37a2d/sshd-core/src/main/java/org/apache/sshd/common/random/JceRandom.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/random/JceRandom.java b/sshd-core/src/main/java/org/apache/sshd/common/random/JceRandom.java
index 4657abe..6aaec25 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/random/JceRandom.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/random/JceRandom.java
@@ -20,8 +20,6 @@ package org.apache.sshd.common.random;
 
 import java.security.SecureRandom;
 
-import org.apache.sshd.common.NamedFactory;
-
 /**
  * A <code>Random</code> implementation using the built-in {@link SecureRandom} PRNG. 
  *
@@ -29,27 +27,6 @@ import org.apache.sshd.common.NamedFactory;
  */
 public class JceRandom implements Random {
 
-    /**
-     * Named factory for the BouncyCastle <code>Random</code>
-     */
-    public static class JceRandomFactory implements NamedFactory<Random> {
-        public static final JceRandomFactory INSTANCE = new JceRandomFactory();
-
-        public JceRandomFactory () {
-            super();
-        }
-
-        @Override
-        public String getName() {
-            return "default";
-        }
-
-        @Override
-        public Random create() {
-            return new JceRandom();
-        }
-    }
-
     private byte[] tmp = new byte[16];
     private final SecureRandom random = new SecureRandom();
 

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/06d37a2d/sshd-core/src/main/java/org/apache/sshd/common/random/JceRandomFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/random/JceRandomFactory.java b/sshd-core/src/main/java/org/apache/sshd/common/random/JceRandomFactory.java
new file mode 100644
index 0000000..1350814
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/random/JceRandomFactory.java
@@ -0,0 +1,46 @@
+/*
+ * 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;
+
+/**
+ * Named factory for the BouncyCastle <code>Random</code>
+ */
+public class JceRandomFactory implements RandomFactory {
+    public static final JceRandomFactory INSTANCE = new JceRandomFactory();
+
+    public JceRandomFactory () {
+        super();
+    }
+
+    @Override
+    public String getName() {
+        return "default";
+    }
+
+    @Override
+    public boolean isSupported() {
+        return true;
+    }
+
+    @Override
+    public Random create() {
+        return new JceRandom();
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/06d37a2d/sshd-core/src/main/java/org/apache/sshd/common/random/RandomFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/random/RandomFactory.java b/sshd-core/src/main/java/org/apache/sshd/common/random/RandomFactory.java
new file mode 100644
index 0000000..78d348c
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/random/RandomFactory.java
@@ -0,0 +1,37 @@
+/*
+ * 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 org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.OptionalFeature;
+import org.apache.sshd.common.util.Transformer;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public interface RandomFactory extends NamedFactory<Random>, OptionalFeature {
+    // required because of generics issues
+    Transformer<RandomFactory,NamedFactory<Random>> FAC2NAMED=new Transformer<RandomFactory,NamedFactory<Random>>() {
+        @Override
+        public NamedFactory<Random> transform(RandomFactory input) {
+            return input;
+        }
+    };
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/06d37a2d/sshd-core/src/main/java/org/apache/sshd/common/random/SingletonRandomFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/random/SingletonRandomFactory.java b/sshd-core/src/main/java/org/apache/sshd/common/random/SingletonRandomFactory.java
index 54b9575..8fc7d48 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/random/SingletonRandomFactory.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/random/SingletonRandomFactory.java
@@ -19,6 +19,7 @@
 package org.apache.sshd.common.random;
 
 import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.OptionalFeature;
 
 /**
  * A random factory wrapper that uses a single random instance.
@@ -26,7 +27,7 @@ import org.apache.sshd.common.NamedFactory;
  *
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
-public class SingletonRandomFactory implements Random, NamedFactory<Random> {
+public class SingletonRandomFactory implements Random, RandomFactory {
 
     private final NamedFactory<Random> factory;
     private final Random random;
@@ -37,6 +38,15 @@ public class SingletonRandomFactory implements Random, NamedFactory<Random> {
     }
 
     @Override
+    public boolean isSupported() {
+        if (factory instanceof OptionalFeature) {
+            return ((OptionalFeature) factory).isSupported();
+        } else {
+            return true;
+        }
+    }
+
+    @Override
     public void fill(byte[] bytes, int start, int len) {
         random.fill(bytes, start, len);
     }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/06d37a2d/sshd-core/src/main/java/org/apache/sshd/common/util/SecurityUtils.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/SecurityUtils.java b/sshd-core/src/main/java/org/apache/sshd/common/util/SecurityUtils.java
index f23029d..134c9d6 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/util/SecurityUtils.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/SecurityUtils.java
@@ -18,10 +18,19 @@
  */
 package org.apache.sshd.common.util;
 
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Path;
 import java.security.GeneralSecurityException;
 import java.security.KeyFactory;
+import java.security.KeyPair;
 import java.security.KeyPairGenerator;
 import java.security.MessageDigest;
+import java.security.SecureRandom;
 import java.security.Signature;
 import java.util.concurrent.Callable;
 
@@ -29,7 +38,22 @@ import javax.crypto.Cipher;
 import javax.crypto.KeyAgreement;
 import javax.crypto.Mac;
 
+import org.apache.sshd.common.config.keys.FilePasswordProvider;
+import org.apache.sshd.common.keyprovider.AbstractClassLoadableResourceKeyPairProvider;
+import org.apache.sshd.common.keyprovider.AbstractFileKeyPairProvider;
+import org.apache.sshd.common.random.JceRandomFactory;
+import org.apache.sshd.common.random.Random;
+import org.apache.sshd.common.random.RandomFactory;
+import org.apache.sshd.server.keyprovider.AbstractGeneratorHostKeyProvider;
+import org.bouncycastle.crypto.prng.RandomGenerator;
+import org.bouncycastle.crypto.prng.VMPCRandomGenerator;
 import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.openssl.PEMDecryptorProvider;
+import org.bouncycastle.openssl.PEMEncryptedKeyPair;
+import org.bouncycastle.openssl.PEMKeyPair;
+import org.bouncycastle.openssl.PEMParser;
+import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
+import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -110,6 +134,8 @@ public class SecurityUtils {
         }
     }
 
+    ///////////////// Bouncycastle specific implementations //////////////////
+
     private static class BouncyCastleRegistration implements Callable<Void> {
         @SuppressWarnings("synthetic-access")
         @Override
@@ -128,66 +154,278 @@ public class SecurityUtils {
         }
     }
 
+    /* -------------------------------------------------------------------- */
+    
+    // TODO in JDK-8 make this an interface...
+    private static class BouncyCastleInputStreamLoader {
+        public static KeyPair loadKeyPair(String resourceKey, InputStream inputStream, FilePasswordProvider provider)
+                throws IOException, GeneralSecurityException {
+            try(PEMParser r = new PEMParser(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
+                Object o = r.readObject();
+
+                JcaPEMKeyConverter pemConverter = new JcaPEMKeyConverter();
+                pemConverter.setProvider(SecurityUtils.BOUNCY_CASTLE);
+                if (o instanceof PEMEncryptedKeyPair) {
+                    ValidateUtils.checkNotNull(provider, "No password provider for resource=%s", resourceKey);
+
+                    String  password = ValidateUtils.checkNotNullAndNotEmpty(provider.getPassword(resourceKey), "No password provided for resource=%s", resourceKey);
+                    JcePEMDecryptorProviderBuilder decryptorBuilder = new JcePEMDecryptorProviderBuilder();
+                    PEMDecryptorProvider pemDecryptor = decryptorBuilder.build(password.toCharArray());
+                    o = ((PEMEncryptedKeyPair) o).decryptKeyPair(pemDecryptor);
+                }
+
+                if (o instanceof PEMKeyPair) {
+                    return pemConverter.getKeyPair((PEMKeyPair)o);
+                } else if (o instanceof KeyPair) {
+                    return (KeyPair) o;
+                } else {
+                    throw new IOException("Failed to read " + resourceKey + " - unknown result object: " + o);
+                }
+            }
+        }
+    }
+
+    /* -------------------------------------------------------------------- */
+
+    // use a separate class in order to avoid direct dependency
+    private static class BouncyCastleFileKeyPairProvider extends AbstractFileKeyPairProvider {
+        private BouncyCastleFileKeyPairProvider() {
+            ValidateUtils.checkTrue(isBouncyCastleRegistered(), "BouncyCastle not registered", GenericUtils.EMPTY_OBJECT_ARRAY);
+        }
+        
+        @Override
+        protected KeyPair doLoadKey(String resourceKey, InputStream inputStream, FilePasswordProvider provider)
+                throws IOException, GeneralSecurityException {
+            return BouncyCastleInputStreamLoader.loadKeyPair(resourceKey, inputStream, provider);
+        }
+    }
+
+    @SuppressWarnings("synthetic-access")
+    public static AbstractFileKeyPairProvider createFileKeyPairProvider() {
+        return new BouncyCastleFileKeyPairProvider();
+    }
+
+    /* -------------------------------------------------------------------- */
+
+    private static class BouncyCastleClassLoadableResourceKeyPairProvider extends AbstractClassLoadableResourceKeyPairProvider {
+        private BouncyCastleClassLoadableResourceKeyPairProvider() {
+            ValidateUtils.checkTrue(isBouncyCastleRegistered(), "BouncyCastle not registered", GenericUtils.EMPTY_OBJECT_ARRAY);
+        }
+
+        @Override
+        protected KeyPair doLoadKey(String resourceKey, InputStream inputStream, FilePasswordProvider provider)
+                throws IOException, GeneralSecurityException {
+            return BouncyCastleInputStreamLoader.loadKeyPair(resourceKey, inputStream, provider);
+        }
+    }
+
+    @SuppressWarnings("synthetic-access")
+    public static AbstractClassLoadableResourceKeyPairProvider createClassLoadableResourceKeyPairProvider() {
+        return new BouncyCastleClassLoadableResourceKeyPairProvider();
+    }
+
+    /* -------------------------------------------------------------------- */
+
+    private static class BouncyCastleGeneratorHostKeyProvider extends AbstractGeneratorHostKeyProvider {
+        private BouncyCastleGeneratorHostKeyProvider(Path path) {
+            ValidateUtils.checkTrue(isBouncyCastleRegistered(), "BouncyCastle not registered", GenericUtils.EMPTY_OBJECT_ARRAY);
+            setPath(path);
+        }
+
+        @Override
+        protected KeyPair doReadKeyPair(String resourceKey, InputStream inputStream) throws IOException, GeneralSecurityException {
+            return BouncyCastleInputStreamLoader.loadKeyPair(resourceKey, inputStream, null);
+        }
+
+        @SuppressWarnings("deprecation")
+        @Override
+        protected void doWriteKeyPair(String resourceKey, KeyPair kp, OutputStream outputStream) throws IOException, GeneralSecurityException {
+            try(org.bouncycastle.openssl.PEMWriter w =
+                    new org.bouncycastle.openssl.PEMWriter(new OutputStreamWriter(outputStream, StandardCharsets.UTF_8))) {
+                w.writeObject(kp);
+                w.flush();
+            }
+        }
+    }
+    
+    @SuppressWarnings("synthetic-access")
+    public static AbstractGeneratorHostKeyProvider createGeneratorHostKeyProvider(Path path) {
+        return new BouncyCastleGeneratorHostKeyProvider(path );
+    }
+
+    /* -------------------------------------------------------------------- */
+    
+    /**
+     * Named factory for the BouncyCastle <code>Random</code>
+     */
+    private static class BouncyCastleRandomFactory implements RandomFactory {
+        private static final BouncyCastleRandomFactory INSTANCE = new BouncyCastleRandomFactory();
+
+        private BouncyCastleRandomFactory() {
+            super();
+        }
+
+        @Override
+        public boolean isSupported() {
+            return isBouncyCastleRegistered();
+        }
+
+        @Override
+        public String getName() {
+            return "bouncycastle";
+        }
+
+        @Override
+        public Random create() {
+            return new BouncyCastleRandom();
+        }
+    }
+
+    /**
+     * BouncyCastle <code>Random</code>.
+     * This pseudo random number generator uses the a very fast PRNG from BouncyCastle.
+     * The JRE random will be used when creating a new generator to add some random
+     * data to the seed.
+     *
+     * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+     */
+    private static class BouncyCastleRandom implements Random {
+
+        private final RandomGenerator random;
+
+        public BouncyCastleRandom() {
+            ValidateUtils.checkTrue(isBouncyCastleRegistered(), "BouncyCastle not registered", GenericUtils.EMPTY_OBJECT_ARRAY);
+            this.random = new VMPCRandomGenerator();
+            byte[] seed = new SecureRandom().generateSeed(8);
+            this.random.addSeedMaterial(seed);
+        }
+
+        @Override
+        public void fill(byte[] bytes, int start, int len) {
+            this.random.nextBytes(bytes, start, len);
+        }
+
+        /**
+         * Returns a pseudo-random uniformly distributed {@code int}
+         * in the half-open range [0, n).
+         */
+        @Override
+        public int random(int n) {
+            if (n > 0) {
+                if ((n & -n) == n) {
+                    return (int)((n * (long) next(31)) >> 31);
+                }
+                int bits, val;
+                do {
+                    bits = next(31);
+                    val = bits % n;
+                } while (bits - val + (n-1) < 0);
+                return val;
+            }
+            throw new IllegalArgumentException("Limit must be positive: " + n);
+        }
+
+        final protected int next(int numBits) {
+            int bytes = (numBits+7)/8;
+            byte next[] = new byte[bytes];
+            int ret = 0;
+            random.nextBytes(next);
+            for (int i = 0; i < bytes; i++) {
+                ret = (next[i] & 0xFF) | (ret << 8);
+            }
+            return ret >>> (bytes*8 - numBits);
+        }
+    }
+
+    /**
+     * @return If {@link #isBouncyCastleRegistered()} then a {@link BouncyCastleRandomFactory}
+     * instance, otherwise a {@link JceRandomFactory} one
+     */
+    @SuppressWarnings("synthetic-access")
+    public static RandomFactory getRandomFactory() {
+        if (isBouncyCastleRegistered()) {
+            return BouncyCastleRandomFactory.INSTANCE;
+        } else {
+            return JceRandomFactory.INSTANCE;
+        }
+    }
+
+    //////////////////////////////////////////////////////////////////////////
+
     public static synchronized KeyFactory getKeyFactory(String algorithm) throws GeneralSecurityException {
         register();
-        if (getSecurityProvider() == null) {
+
+        String providerName = getSecurityProvider();
+        if (GenericUtils.isEmpty(providerName)) {
             return KeyFactory.getInstance(algorithm);
         } else {
-            return KeyFactory.getInstance(algorithm, getSecurityProvider());
+            return KeyFactory.getInstance(algorithm, providerName);
         }
     }
 
     public static synchronized Cipher getCipher(String transformation) throws GeneralSecurityException {
         register();
-        if (getSecurityProvider() == null) {
+
+        String providerName = getSecurityProvider();
+        if (GenericUtils.isEmpty(providerName)) {
             return Cipher.getInstance(transformation);
         } else {
-            return Cipher.getInstance(transformation, getSecurityProvider());
+            return Cipher.getInstance(transformation, providerName);
         }
     }
 
     public static synchronized MessageDigest getMessageDigest(String algorithm) throws GeneralSecurityException {
         register();
-        if (getSecurityProvider() == null) {
+        
+        String providerName = getSecurityProvider();
+        if (GenericUtils.isEmpty(providerName)) {
             return MessageDigest.getInstance(algorithm);
         } else {
-            return MessageDigest.getInstance(algorithm, getSecurityProvider());
+            return MessageDigest.getInstance(algorithm, providerName);
         }
     }
 
     public static synchronized KeyPairGenerator getKeyPairGenerator(String algorithm) throws GeneralSecurityException {
         register();
-        if (getSecurityProvider() == null) {
+
+        String providerName = getSecurityProvider();
+        if (GenericUtils.isEmpty(providerName)) {
             return KeyPairGenerator.getInstance(algorithm);
         } else {
-            return KeyPairGenerator.getInstance(algorithm, getSecurityProvider());
+            return KeyPairGenerator.getInstance(algorithm, providerName);
         }
     }
 
     public static synchronized KeyAgreement getKeyAgreement(String algorithm) throws GeneralSecurityException {
         register();
-        if (getSecurityProvider() == null) {
+
+        String providerName = getSecurityProvider();
+        if (GenericUtils.isEmpty(providerName)) {
             return KeyAgreement.getInstance(algorithm);
         } else {
-            return KeyAgreement.getInstance(algorithm, getSecurityProvider());
+            return KeyAgreement.getInstance(algorithm, providerName);
         }
     }
 
     public static synchronized Mac getMac(String algorithm) throws GeneralSecurityException {
         register();
-        if (getSecurityProvider() == null) {
+
+        String providerName = getSecurityProvider();
+        if (GenericUtils.isEmpty(providerName)) {
             return Mac.getInstance(algorithm);
         } else {
-            return Mac.getInstance(algorithm, getSecurityProvider());
+            return Mac.getInstance(algorithm, providerName);
         }
     }
 
     public static synchronized Signature getSignature(String algorithm) throws GeneralSecurityException {
         register();
-        if (getSecurityProvider() == null) {
+
+        String providerName = getSecurityProvider();
+        if (GenericUtils.isEmpty(providerName)) {
             return Signature.getInstance(algorithm);
         } else {
-            return Signature.getInstance(algorithm, getSecurityProvider());
+            return Signature.getInstance(algorithm, providerName);
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/06d37a2d/sshd-core/src/main/java/org/apache/sshd/common/util/ValidateUtils.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/ValidateUtils.java b/sshd-core/src/main/java/org/apache/sshd/common/util/ValidateUtils.java
index 1051a69..0009a14 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/util/ValidateUtils.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/ValidateUtils.java
@@ -43,6 +43,12 @@ public final class ValidateUtils {
         return t;
     }
 
+    public static final String checkNotNullAndNotEmpty(String t, String message, Object arg) {
+        t = checkNotNull(t, message, arg).trim();
+        checkTrue(GenericUtils.length(t) > 0, message, arg);
+        return t;
+    }
+
     public static final String checkNotNullAndNotEmpty(String t, String message, Object ... args) {
         t = checkNotNull(t, message, args).trim();
         checkTrue(GenericUtils.length(t) > 0, message, args);

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/06d37a2d/sshd-core/src/main/java/org/apache/sshd/common/util/io/IoUtils.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/io/IoUtils.java b/sshd-core/src/main/java/org/apache/sshd/common/util/io/IoUtils.java
index 9bae57e..73f7b59 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/util/io/IoUtils.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/io/IoUtils.java
@@ -27,6 +27,7 @@ import java.io.OutputStream;
 import java.nio.file.FileSystem;
 import java.nio.file.Files;
 import java.nio.file.LinkOption;
+import java.nio.file.OpenOption;
 import java.nio.file.Path;
 import java.nio.file.attribute.PosixFilePermission;
 import java.util.Arrays;
@@ -44,13 +45,13 @@ import org.apache.sshd.common.util.OsUtils;
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
 public class IoUtils {
-
-    public static final LinkOption[] EMPTY_OPTIONS = new LinkOption[0];
+    public static final OpenOption[] EMPTY_OPEN_OPTIONS = new OpenOption[0];
+    public static final LinkOption[] EMPTY_LINK_OPTIONS = new LinkOption[0];
     private static final LinkOption[] NO_FOLLOW_OPTIONS = new LinkOption[] { LinkOption.NOFOLLOW_LINKS };
 
     public static LinkOption[] getLinkOptions(boolean followLinks) {
         if (followLinks) {
-            return EMPTY_OPTIONS;
+            return EMPTY_LINK_OPTIONS;
         } else {    // return a clone that modifications to the array will not affect others
             return NO_FOLLOW_OPTIONS.clone();
         }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/06d37a2d/sshd-core/src/main/java/org/apache/sshd/common/util/io/ModifiableFileWatcher.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/io/ModifiableFileWatcher.java b/sshd-core/src/main/java/org/apache/sshd/common/util/io/ModifiableFileWatcher.java
index ddf0efb..c44cee0 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/util/io/ModifiableFileWatcher.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/io/ModifiableFileWatcher.java
@@ -56,7 +56,7 @@ public class ModifiableFileWatcher extends AbstractLoggingBean {
     public ModifiableFileWatcher(Path file, LinkOption ... options) {
         this.file = ValidateUtils.checkNotNull(file, "No path to watch", GenericUtils.EMPTY_OBJECT_ARRAY);
         // use a clone to avoid being sensitive to changes in the passed array
-        this.options = (options == null) ? IoUtils.EMPTY_OPTIONS : options.clone();
+        this.options = (options == null) ? IoUtils.EMPTY_LINK_OPTIONS : options.clone();
     }
     
     /**

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/06d37a2d/sshd-core/src/main/java/org/apache/sshd/server/SshServer.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/SshServer.java b/sshd-core/src/main/java/org/apache/sshd/server/SshServer.java
index 3281b28..135ac0d 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/SshServer.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/SshServer.java
@@ -18,6 +18,7 @@
  */
 package org.apache.sshd.server;
 
+import java.io.File;
 import java.io.IOException;
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
@@ -50,7 +51,6 @@ import org.apache.sshd.server.auth.gss.GSSAuthenticator;
 import org.apache.sshd.server.auth.gss.UserAuthGSS;
 import org.apache.sshd.server.command.ScpCommandFactory;
 import org.apache.sshd.server.forward.ForwardingFilter;
-import org.apache.sshd.server.keyprovider.PEMGeneratorHostKeyProvider;
 import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
 import org.apache.sshd.server.session.ServerConnectionService;
 import org.apache.sshd.server.session.ServerSession;
@@ -428,10 +428,11 @@ public class SshServer extends AbstractFactoryManager implements ServerFactoryMa
         sshd.setPort(port);
 
         if (SecurityUtils.isBouncyCastleRegistered()) {
-            sshd.setKeyPairProvider(new PEMGeneratorHostKeyProvider("key.pem"));
+            sshd.setKeyPairProvider(SecurityUtils.createGeneratorHostKeyProvider(new File("key.pem").toPath()));
         } else {
-            sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider("key.ser"));
+            sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider(new File("key.ser")));
         }
+
         if (OsUtils.isUNIX()) {
             sshd.setShellFactory(new ProcessShellFactory(new String[] { "/bin/sh", "-i", "-l" },
                                  EnumSet.of(ProcessShellFactory.TtyOptions.ONlCr)));

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/06d37a2d/sshd-core/src/main/java/org/apache/sshd/server/keyprovider/AbstractGeneratorHostKeyProvider.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/keyprovider/AbstractGeneratorHostKeyProvider.java b/sshd-core/src/main/java/org/apache/sshd/server/keyprovider/AbstractGeneratorHostKeyProvider.java
index c6bafd3..87bc88b 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/keyprovider/AbstractGeneratorHostKeyProvider.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/keyprovider/AbstractGeneratorHostKeyProvider.java
@@ -19,57 +19,55 @@
 package org.apache.sshd.server.keyprovider;
 
 import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
+import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.LinkOption;
+import java.nio.file.OpenOption;
+import java.nio.file.Path;
+import java.security.GeneralSecurityException;
 import java.security.KeyPair;
 import java.security.KeyPairGenerator;
 import java.security.spec.AlgorithmParameterSpec;
 import java.util.Collections;
 
 import org.apache.sshd.common.keyprovider.AbstractKeyPairProvider;
-import org.apache.sshd.common.util.GenericUtils;
 import org.apache.sshd.common.util.SecurityUtils;
+import org.apache.sshd.common.util.io.IoUtils;
 
 /**
- * TODO Add javadoc
- *
+ * Holds a <U>single</U> {@link KeyPair} which is generated the 1st time
+ * {@link #loadKeys()} is called. If there is a file backing it up and the
+ * file exists, the key is loaded from it. Otherwise a new key pair is
+ * generated and saved (provided a path is configured and {@link #isOverwriteAllowed()}
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
 public abstract class AbstractGeneratorHostKeyProvider extends AbstractKeyPairProvider {
+    public static final String DEFAULT_ALGORITHM = "DSA";
+    public static final boolean DEFAULT_ALLOWED_TO_OVERWRITE = true;
 
-    private String path;
-    private String algorithm;
+    private Path path;
+    private String algorithm = DEFAULT_ALGORITHM;
     private int keySize;
     private AlgorithmParameterSpec keySpec;
     private KeyPair keyPair;
-    private boolean overwriteAllowed = true;
+    private boolean overwriteAllowed = DEFAULT_ALLOWED_TO_OVERWRITE;
 
     protected AbstractGeneratorHostKeyProvider() {
-        this(null);
-    }
-
-    protected AbstractGeneratorHostKeyProvider(String path) {
-        this(path, "DSA");
-    }
-
-    protected AbstractGeneratorHostKeyProvider(String path, String algorithm) {
-        this(path, algorithm, 0);
+        super();
     }
 
-    protected AbstractGeneratorHostKeyProvider(String path, String algorithm, int keySize) {
-        this.path = path;
-        this.algorithm = algorithm;
-        this.keySize = keySize;
+    public Path getPath() {
+        return path;
     }
 
-    public String getPath() {
-        return path;
+    public void setFile(File file) {
+        setPath((file == null) ? null : file.toPath());
     }
 
-    public void setPath(String path) {
-        this.path = path;
+    public void setPath(Path path) {
+        this.path = (path == null) ? null : path.toAbsolutePath();
     }
 
     public String getAlgorithm() {
@@ -104,25 +102,45 @@ public abstract class AbstractGeneratorHostKeyProvider extends AbstractKeyPairPr
         this.overwriteAllowed = overwriteAllowed;
     }
 
-    protected abstract KeyPair doReadKeyPair(InputStream is) throws Exception;
-
-    protected abstract void doWriteKeyPair(KeyPair kp, OutputStream os) throws Exception;
-
     @Override
     public synchronized Iterable<KeyPair> loadKeys() {
+        Path keyPath = getPath();
+
         if (keyPair == null) {
-            if (!GenericUtils.isEmpty(path)) {
-                File f = new File(path);
-                if (f.exists() && f.isFile()) {
-                    keyPair = readKeyPair(f);
+            if (keyPath != null) {
+                LinkOption[]    options = IoUtils.getLinkOptions(false);
+                if (Files.exists(keyPath, options) && Files.isRegularFile(keyPath, options)) {
+                    try {
+                        keyPair = readKeyPair(keyPath, IoUtils.EMPTY_OPEN_OPTIONS);
+                    } catch(Exception e) {
+                        log.warn("Failed (" + e.getClass().getSimpleName() + ")"
+                                + " to load from " + keyPath
+                                + ": " + e.getMessage(),
+                                e);
+                    }
                 }
             }
         }
 
         if (keyPair == null) {
-            keyPair = generateKeyPair(getAlgorithm());
-            if ((keyPair != null) && (!GenericUtils.isEmpty(path))) {
-                writeKeyPair(keyPair, new File(path));
+            String alg = getAlgorithm();
+            try {
+                keyPair = generateKeyPair(alg);
+            } catch(Exception e) {
+                log.warn("Failed (" + e.getClass().getSimpleName() + ")"
+                       + " to generate " + alg + " keys: " + e.getMessage(),
+                         e);
+            }
+
+            if ((keyPair != null) && (keyPath != null)) {
+                try {
+                    writeKeyPair(keyPair, keyPath);
+                } catch(Exception e) {
+                    log.warn("Failed (" + e.getClass().getSimpleName() + ")"
+                            + " to write to " + keyPath
+                            + ": " + e.getMessage(),
+                            e);
+                }
             }
         }
 
@@ -133,41 +151,37 @@ public abstract class AbstractGeneratorHostKeyProvider extends AbstractKeyPairPr
         }
     }
 
-    private KeyPair readKeyPair(File f) {
-        try(InputStream is = new FileInputStream(f)) {
-            return doReadKeyPair(is);
-        } catch (Exception e) {
-            log.warn("Unable to read key {}: {}", f.getAbsolutePath(), e);
-            return null;
+    protected KeyPair readKeyPair(Path keyPath, OpenOption ... options) throws IOException, GeneralSecurityException {
+        try(InputStream inputStream = Files.newInputStream(keyPath, options)) {
+            return doReadKeyPair(keyPath.toString(), inputStream);
         }
     }
+    protected abstract KeyPair doReadKeyPair(String resourceKey, InputStream inputStream) throws IOException, GeneralSecurityException;
 
-    private void writeKeyPair(KeyPair kp, File f) {
-        if ((!f.exists()) || isOverwriteAllowed()) {
-            try(OutputStream os = new FileOutputStream(f)) {
-                doWriteKeyPair(kp, os);
+    protected void writeKeyPair(KeyPair kp, Path keyPath, OpenOption ... options) throws IOException, GeneralSecurityException {
+        if ((!Files.exists(keyPath)) || isOverwriteAllowed()) {
+            try(OutputStream os = Files.newOutputStream(keyPath, options)) {
+                doWriteKeyPair(keyPath.toString(), kp, os);
             } catch (Exception e) {
                 log.warn("Unable to write key {}: {}", path, e);
             }
         } else {
-            log.error("Overwriting key ({}) is disabled: using throwaway {}", f.getAbsolutePath(), kp);
+            log.error("Overwriting key ({}) is disabled: using throwaway {}", keyPath, kp);
         }
     }
+    protected abstract void doWriteKeyPair(String resourceKey, KeyPair kp, OutputStream outputStream) throws IOException, GeneralSecurityException;
 
-    private KeyPair generateKeyPair(String algorithm) {
-        try {
-            KeyPairGenerator generator = SecurityUtils.getKeyPairGenerator(algorithm);
-            if (keySpec != null) {
-                generator.initialize(keySpec);
-            } else if (keySize != 0) {
-                generator.initialize(keySize);
-            }
-            log.info("generateKeyPair(" + algorithm + ") generating host key...");
-            KeyPair kp = generator.generateKeyPair();
-            return kp;
-        } catch (Exception e) {
-            log.warn("generateKeyPair(" + algorithm + ") Unable to generate keypair", e);
-            return null;
+
+    protected KeyPair generateKeyPair(String algorithm) throws GeneralSecurityException {
+        KeyPairGenerator generator = SecurityUtils.getKeyPairGenerator(algorithm);
+        if (keySpec != null) {
+            generator.initialize(keySpec);
+            log.info("generateKeyPair(" + algorithm + ") generating host key - spec=" + keySpec.getClass().getSimpleName());
+        } else if (keySize != 0) {
+            generator.initialize(keySize);
+            log.info("generateKeyPair(" + algorithm + ") generating host key - size=" + keySize);
         }
+
+        return generator.generateKeyPair();
     }
 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/06d37a2d/sshd-core/src/main/java/org/apache/sshd/server/keyprovider/PEMGeneratorHostKeyProvider.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/keyprovider/PEMGeneratorHostKeyProvider.java b/sshd-core/src/main/java/org/apache/sshd/server/keyprovider/PEMGeneratorHostKeyProvider.java
deleted file mode 100644
index 47c884e..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/server/keyprovider/PEMGeneratorHostKeyProvider.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.sshd.server.keyprovider;
-
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.security.KeyPair;
-
-import org.bouncycastle.openssl.PEMKeyPair;
-import org.bouncycastle.openssl.PEMParser;
-import org.bouncycastle.openssl.PEMWriter;
-import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
-
-/**
- * TODO Add javadoc
- *
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class PEMGeneratorHostKeyProvider extends AbstractGeneratorHostKeyProvider {
-
-    public PEMGeneratorHostKeyProvider() {
-        super();
-    }
-
-    public PEMGeneratorHostKeyProvider(String path) {
-        super(path);
-    }
-
-    public PEMGeneratorHostKeyProvider(String path, String algorithm) {
-        super(path, algorithm);
-    }
-
-    public PEMGeneratorHostKeyProvider(String path, String algorithm, int keySize) {
-        super(path, algorithm, keySize);
-    }
-
-    @Override
-    protected KeyPair doReadKeyPair(InputStream is) throws Exception {
-        try(PEMParser r = new PEMParser(new InputStreamReader(is))) {
-            Object o = r.readObject();
-            JcaPEMKeyConverter pemConverter = new JcaPEMKeyConverter();
-            pemConverter.setProvider("BC");
-            if (o instanceof PEMKeyPair) {
-                o = pemConverter.getKeyPair((PEMKeyPair)o);
-                return (KeyPair) o;
-            } else if (o instanceof KeyPair) {
-                return (KeyPair) o;
-            }
-            return null;
-        }
-    }
-
-    @Override
-    protected void doWriteKeyPair(KeyPair kp, OutputStream os) throws Exception {
-        try(PEMWriter w = new PEMWriter(new OutputStreamWriter(os))) {
-            w.writeObject(kp);
-            w.flush();
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/06d37a2d/sshd-core/src/main/java/org/apache/sshd/server/keyprovider/SimpleGeneratorHostKeyProvider.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/keyprovider/SimpleGeneratorHostKeyProvider.java b/sshd-core/src/main/java/org/apache/sshd/server/keyprovider/SimpleGeneratorHostKeyProvider.java
index 982d2e7..fff76a8 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/keyprovider/SimpleGeneratorHostKeyProvider.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/keyprovider/SimpleGeneratorHostKeyProvider.java
@@ -18,11 +18,16 @@
  */
 package org.apache.sshd.server.keyprovider;
 
+import java.io.File;
+import java.io.IOException;
 import java.io.InputStream;
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
 import java.io.OutputStream;
+import java.nio.file.Path;
+import java.security.GeneralSecurityException;
 import java.security.KeyPair;
+import java.security.spec.InvalidKeySpecException;
 
 /**
  * TODO Add javadoc
@@ -30,33 +35,32 @@ import java.security.KeyPair;
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
 public class SimpleGeneratorHostKeyProvider extends AbstractGeneratorHostKeyProvider {
-
     public SimpleGeneratorHostKeyProvider() {
         super();
     }
 
-    public SimpleGeneratorHostKeyProvider(String path) {
-        super(path);
-    }
-
-    public SimpleGeneratorHostKeyProvider(String path, String algorithm) {
-        super(path, algorithm);
+    public SimpleGeneratorHostKeyProvider(File file) {
+        this((file == null) ? null : file.toPath());
     }
 
-    public SimpleGeneratorHostKeyProvider(String path, String algorithm, int keySize) {
-        super(path, algorithm, keySize);
+    public SimpleGeneratorHostKeyProvider(Path path) {
+        setPath(path);
     }
 
     @Override
-    protected KeyPair doReadKeyPair(InputStream is) throws Exception {
-        try(ObjectInputStream r = new ObjectInputStream(is)) {
-            return (KeyPair) r.readObject();
+    protected KeyPair doReadKeyPair(String resourceKey, InputStream inputStream) throws IOException, GeneralSecurityException {
+        try(ObjectInputStream r = new ObjectInputStream(inputStream)) {
+            try {
+                return (KeyPair) r.readObject();
+            } catch (ClassNotFoundException e) {
+                throw new InvalidKeySpecException("Missing classes: " + e.getMessage(), e);
+            }
         }
     }
 
     @Override
-    protected void doWriteKeyPair(KeyPair kp, OutputStream os) throws Exception {
-        try(ObjectOutputStream w = new ObjectOutputStream(os)) {
+    protected void doWriteKeyPair(String resourceKey, KeyPair kp, OutputStream outputStream) throws IOException, GeneralSecurityException {
+        try(ObjectOutputStream w = new ObjectOutputStream(outputStream)) {
             w.writeObject(kp);
         }
     }