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 "target" 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);
}
}