You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by gn...@apache.org on 2015/03/17 18:35:33 UTC

[3/4] mina-sshd git commit: [SSHD-430] Expose supported built-in ciphers as an Enum

[SSHD-430] Expose supported built-in ciphers as an Enum

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

Branch: refs/heads/master
Commit: eac1704e05d23a562512dc6d2bde387c3cea07e9
Parents: 043c7df
Author: Guillaume Nodet <gn...@apache.org>
Authored: Tue Mar 17 16:10:52 2015 +0100
Committer: Guillaume Nodet <gn...@apache.org>
Committed: Tue Mar 17 18:06:11 2015 +0100

----------------------------------------------------------------------
 .../main/java/org/apache/sshd/SshBuilder.java   |  85 ++++---
 .../org/apache/sshd/common/NamedFactory.java    |  27 ++-
 .../apache/sshd/common/cipher/AES128CBC.java    |   9 +-
 .../apache/sshd/common/cipher/AES128CTR.java    |   9 +-
 .../apache/sshd/common/cipher/AES192CBC.java    |   9 +-
 .../apache/sshd/common/cipher/AES192CTR.java    |   9 +-
 .../apache/sshd/common/cipher/AES256CBC.java    |   9 +-
 .../apache/sshd/common/cipher/AES256CTR.java    |   9 +-
 .../apache/sshd/common/cipher/ARCFOUR128.java   |   9 +-
 .../apache/sshd/common/cipher/ARCFOUR256.java   |   9 +-
 .../apache/sshd/common/cipher/BlowfishCBC.java  |   9 +-
 .../sshd/common/cipher/BuiltinCiphers.java      | 234 +++++++++++++++++++
 .../apache/sshd/common/cipher/CipherNone.java   |  12 +-
 .../apache/sshd/common/cipher/CipherUtils.java  |  58 +++++
 .../apache/sshd/common/cipher/TripleDESCBC.java |   9 +-
 .../apache/sshd/common/util/GenericUtils.java   |  92 ++++++++
 .../java/org/apache/sshd/SshBuilderTest.java    |  81 +++++++
 .../sshd/common/cipher/BuiltinCiphersTest.java  |  94 ++++++++
 .../java/org/apache/sshd/util/BaseTest.java     |  39 +++-
 19 files changed, 748 insertions(+), 64 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/eac1704e/sshd-core/src/main/java/org/apache/sshd/SshBuilder.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/SshBuilder.java b/sshd-core/src/main/java/org/apache/sshd/SshBuilder.java
index b87d994..bac6163 100644
--- a/sshd-core/src/main/java/org/apache/sshd/SshBuilder.java
+++ b/sshd-core/src/main/java/org/apache/sshd/SshBuilder.java
@@ -18,10 +18,9 @@
  */
 package org.apache.sshd;
 
-import java.security.InvalidKeyException;
+import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Iterator;
-import java.util.LinkedList;
+import java.util.Collections;
 import java.util.List;
 
 import org.apache.sshd.client.ServerKeyVerifier;
@@ -38,16 +37,7 @@ import org.apache.sshd.common.Random;
 import org.apache.sshd.common.RequestHandler;
 import org.apache.sshd.common.Signature;
 import org.apache.sshd.common.TcpipForwarderFactory;
-import org.apache.sshd.common.cipher.AES128CBC;
-import org.apache.sshd.common.cipher.AES128CTR;
-import org.apache.sshd.common.cipher.AES192CBC;
-import org.apache.sshd.common.cipher.AES192CTR;
-import org.apache.sshd.common.cipher.AES256CBC;
-import org.apache.sshd.common.cipher.AES256CTR;
-import org.apache.sshd.common.cipher.ARCFOUR128;
-import org.apache.sshd.common.cipher.ARCFOUR256;
-import org.apache.sshd.common.cipher.BlowfishCBC;
-import org.apache.sshd.common.cipher.TripleDESCBC;
+import org.apache.sshd.common.cipher.BuiltinCiphers;
 import org.apache.sshd.common.compression.CompressionNone;
 import org.apache.sshd.common.file.FileSystemFactory;
 import org.apache.sshd.common.file.nativefs.NativeFileSystemFactory;
@@ -89,6 +79,9 @@ public class SshBuilder {
         return new ServerBuilder();
     }
 
+    /**
+     * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+     */
     protected static class BaseBuilder<T extends AbstractFactoryManager, S extends BaseBuilder<T, S>> implements ObjectBuilder<T> {
 
         protected Factory<T> factory = null;
@@ -142,7 +135,7 @@ public class SshBuilder {
             }
 
             if (cipherFactories == null) {
-                cipherFactories = setUpDefaultCiphers();
+                cipherFactories = setUpDefaultCiphers(false);
             }
 
             // Compression is not enabled by default
@@ -260,32 +253,48 @@ public class SshBuilder {
             return (S) this;
         }
 
-        protected static List<NamedFactory<Cipher>> setUpDefaultCiphers() {
-            List<NamedFactory<Cipher>> avail = new LinkedList<NamedFactory<Cipher>>();
-            avail.add(new AES128CTR.Factory());
-            avail.add(new AES192CTR.Factory());
-            avail.add(new AES256CTR.Factory());
-            avail.add(new ARCFOUR128.Factory());
-            avail.add(new ARCFOUR256.Factory());
-            avail.add(new AES128CBC.Factory());
-            avail.add(new TripleDESCBC.Factory());
-            avail.add(new BlowfishCBC.Factory());
-            avail.add(new AES192CBC.Factory());
-            avail.add(new AES256CBC.Factory());
-
-            for (Iterator<NamedFactory<Cipher>> i = avail.iterator(); i.hasNext(); ) {
-                final NamedFactory<Cipher> f = i.next();
-                try {
-                    final Cipher c = f.create();
-                    final byte[] key = new byte[c.getBlockSize()];
-                    final byte[] iv = new byte[c.getIVSize()];
-                    c.init(Cipher.Mode.Encrypt, key, iv);
-                } catch (InvalidKeyException e) {
-                    i.remove();
-                } catch (Exception e) {
-                    i.remove();
+        /**
+         * The default {@link BuiltinCiphers} setup in order of preference
+         * as specified by <A HREF="https://www.freebsd.org/cgi/man.cgi?query=ssh_config&sektion=5">
+         * ssh_config(5)</A> 
+         */
+        public static final List<BuiltinCiphers> DEFAULT_CIPHERS_PREFERENCE =
+                Collections.unmodifiableList(
+                        Arrays.asList(
+                                BuiltinCiphers.aes128ctr,
+                                BuiltinCiphers.aes192ctr,
+                                BuiltinCiphers.aes256ctr,
+                                BuiltinCiphers.arcfour256,
+                                BuiltinCiphers.arcfour128,
+                                BuiltinCiphers.aes128cbc,
+                                BuiltinCiphers.tripledescbc,
+                                BuiltinCiphers.blowfishcbc,
+                                // TODO add support for cast128-cbc cipher
+                                BuiltinCiphers.aes192cbc,
+                                BuiltinCiphers.aes256cbc
+                                // TODO add support for arcfour cipher
+                        ));
+        
+        /**
+         * @param ignoreUnsupported If {@code true} then all the default
+         * ciphers are included, regardless of whether they are currently
+         * supported by the JCE. Otherwise, only the supported ones out of the
+         * list are included
+         * @return A {@link List} of the default {@link NamedFactory}
+         * instances of the {@link Cipher}s according to the preference
+         * order defined by {@link #DEFAULT_CIPHERS_PREFERENCE}.
+         * <B>Note:</B> the list may be filtered to exclude unsupported JCE
+         * ciphers according to the <tt>ignoreUnsupported</tt> parameter
+         * @see BuiltinCiphers#isSupported()
+         */
+        protected static List<NamedFactory<Cipher>> setUpDefaultCiphers(boolean ignoreUnsupported) {
+            List<NamedFactory<Cipher>> avail = new ArrayList<NamedFactory<Cipher>>(DEFAULT_CIPHERS_PREFERENCE.size());
+            for (BuiltinCiphers c : DEFAULT_CIPHERS_PREFERENCE) {
+                if (ignoreUnsupported || c.isSupported()) {
+                    avail.add(c.create());
                 }
             }
+
             return avail;
         }
     }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/eac1704e/sshd-core/src/main/java/org/apache/sshd/common/NamedFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/NamedFactory.java b/sshd-core/src/main/java/org/apache/sshd/common/NamedFactory.java
index 47347b4..ba8d60f 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/NamedFactory.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/NamedFactory.java
@@ -23,6 +23,8 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 
+import org.apache.sshd.common.util.GenericUtils;
+
 /**
  * A named factory is a factory identified by a name.
  * Such names are used mainly in the algorithm negotiation at the beginning of the SSH connection.
@@ -48,18 +50,19 @@ public interface NamedFactory<T> extends Factory<T> {
     	 * @return A {@link List} of all the factories names - in same order
     	 * as they appear in the input collection
     	 */
-    	public static <T> List<String> getNameList(Collection<NamedFactory<T>> factories) {
-    		if ((factories == null) || factories.isEmpty()) {
-    			return Collections.emptyList();
-    		}
-    		
-    		List<String>	names=new ArrayList<String>(factories.size());
-    		for (NamedFactory<T> f : factories) {
-    			names.add(f.getName());
-    		}
-    		
-    		return names;
-    	}
+        public static List<String> getNameList(Collection<? extends NamedFactory<?>> factories) {
+            if (GenericUtils.isEmpty(factories)) {
+                return Collections.emptyList();
+            }
+
+            List<String> names = new ArrayList<String>(factories.size());
+            for (NamedFactory<?> f : factories) {
+                names.add(f.getName());
+            }
+
+            return names;
+        }
+
         /**
          * Create an instance of the specified name by looking up the needed factory
          * in the list.

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/eac1704e/sshd-core/src/main/java/org/apache/sshd/common/cipher/AES128CBC.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/cipher/AES128CBC.java b/sshd-core/src/main/java/org/apache/sshd/common/cipher/AES128CBC.java
index 3ea3870..39a1a08 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/cipher/AES128CBC.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/cipher/AES128CBC.java
@@ -32,9 +32,16 @@ public class AES128CBC extends BaseCipher {
      * Named factory for AES128CBC Cipher
      */
     public static class Factory implements NamedFactory<Cipher> {
+        public static final String NAME = "aes128-cbc";
+
+        public Factory() {
+            super();
+        }
+
         public String getName() {
-            return "aes128-cbc";
+            return NAME;
         }
+
         public Cipher create() {
             return new AES128CBC();
         }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/eac1704e/sshd-core/src/main/java/org/apache/sshd/common/cipher/AES128CTR.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/cipher/AES128CTR.java b/sshd-core/src/main/java/org/apache/sshd/common/cipher/AES128CTR.java
index 2a7dc3a..2cbfb21 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/cipher/AES128CTR.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/cipher/AES128CTR.java
@@ -32,9 +32,16 @@ public class AES128CTR extends BaseCipher {
      * Named factory for AES128CTR Cipher
      */
     public static class Factory implements NamedFactory<Cipher> {
+        public static final String NAME = "aes128-ctr";
+
+        public Factory() {
+            super();
+        }
+
         public String getName() {
-            return "aes128-ctr";
+            return NAME;
         }
+
         public Cipher create() {
             return new AES128CTR();
         }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/eac1704e/sshd-core/src/main/java/org/apache/sshd/common/cipher/AES192CBC.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/cipher/AES192CBC.java b/sshd-core/src/main/java/org/apache/sshd/common/cipher/AES192CBC.java
index 87ffdeb..3d26f76 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/cipher/AES192CBC.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/cipher/AES192CBC.java
@@ -32,9 +32,16 @@ public class AES192CBC extends BaseCipher {
      * Named factory for AES192CBC Cipher
      */
     public static class Factory implements NamedFactory<Cipher> {
+        public static final String NAME = "aes192-cbc";
+
+        public Factory() {
+            super();
+        }
+
         public String getName() {
-            return "aes192-cbc";
+            return NAME;
         }
+
         public Cipher create() {
             return new AES192CBC();
         }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/eac1704e/sshd-core/src/main/java/org/apache/sshd/common/cipher/AES192CTR.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/cipher/AES192CTR.java b/sshd-core/src/main/java/org/apache/sshd/common/cipher/AES192CTR.java
index d44c06c..cf13b9f 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/cipher/AES192CTR.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/cipher/AES192CTR.java
@@ -32,9 +32,16 @@ public class AES192CTR extends BaseCipher {
      * Named factory for AES192CBC Cipher
      */
     public static class Factory implements NamedFactory<Cipher> {
+        public static final String NAME = "aes192-ctr";
+
+        public Factory() {
+            super();
+        }
+
         public String getName() {
-            return "aes192-ctr";
+            return NAME;
         }
+
         public Cipher create() {
             return new AES192CTR();
         }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/eac1704e/sshd-core/src/main/java/org/apache/sshd/common/cipher/AES256CBC.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/cipher/AES256CBC.java b/sshd-core/src/main/java/org/apache/sshd/common/cipher/AES256CBC.java
index 736e594..38122d8 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/cipher/AES256CBC.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/cipher/AES256CBC.java
@@ -32,9 +32,16 @@ public class AES256CBC extends BaseCipher {
      * Named factory for AES256CBC Cipher
      */
     public static class Factory implements NamedFactory<Cipher> {
+        public static final String NAME = "aes256-cbc";
+
+        public Factory() {
+            super();
+        }
+
         public String getName() {
-            return "aes256-cbc";
+            return NAME;
         }
+
         public Cipher create() {
             return new AES256CBC();
         }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/eac1704e/sshd-core/src/main/java/org/apache/sshd/common/cipher/AES256CTR.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/cipher/AES256CTR.java b/sshd-core/src/main/java/org/apache/sshd/common/cipher/AES256CTR.java
index 608fc43..718017f 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/cipher/AES256CTR.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/cipher/AES256CTR.java
@@ -32,9 +32,16 @@ public class AES256CTR extends BaseCipher {
      * Named factory for AES256CTR Cipher
      */
     public static class Factory implements NamedFactory<Cipher> {
+        public static final String NAME = "aes256-ctr";
+
+        public Factory() {
+            super();
+        }
+
         public String getName() {
-            return "aes256-ctr";
+            return NAME;
         }
+
         public Cipher create() {
             return new AES256CTR();
         }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/eac1704e/sshd-core/src/main/java/org/apache/sshd/common/cipher/ARCFOUR128.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/cipher/ARCFOUR128.java b/sshd-core/src/main/java/org/apache/sshd/common/cipher/ARCFOUR128.java
index 4ff5f1d..33d6a6e 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/cipher/ARCFOUR128.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/cipher/ARCFOUR128.java
@@ -32,9 +32,16 @@ public class ARCFOUR128 extends BaseRC4Cipher {
      * Named factory for ARCFOUR128 Cipher
      */
     public static class Factory implements NamedFactory<Cipher> {
+        public static final String NAME = "arcfour128";
+
+        public Factory() {
+            super();
+        }
+
         public String getName() {
-            return "arcfour128";
+            return NAME;
         }
+
         public Cipher create() {
             return new ARCFOUR128();
         }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/eac1704e/sshd-core/src/main/java/org/apache/sshd/common/cipher/ARCFOUR256.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/cipher/ARCFOUR256.java b/sshd-core/src/main/java/org/apache/sshd/common/cipher/ARCFOUR256.java
index fed8176..500c1b7 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/cipher/ARCFOUR256.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/cipher/ARCFOUR256.java
@@ -32,9 +32,16 @@ public class ARCFOUR256 extends BaseRC4Cipher {
      * Named factory for AES128CTR Cipher
      */
     public static class Factory implements NamedFactory<Cipher> {
+        public static final String NAME = "arcfour256";
+
+        public Factory() {
+            super();
+        }
+
         public String getName() {
-            return "arcfour256";
+            return NAME;
         }
+
         public Cipher create() {
             return new ARCFOUR256();
         }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/eac1704e/sshd-core/src/main/java/org/apache/sshd/common/cipher/BlowfishCBC.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/cipher/BlowfishCBC.java b/sshd-core/src/main/java/org/apache/sshd/common/cipher/BlowfishCBC.java
index 6a76ad1..b2c6135 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/cipher/BlowfishCBC.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/cipher/BlowfishCBC.java
@@ -32,9 +32,16 @@ public class BlowfishCBC extends BaseCipher {
      * Named factory for BlowfishCBC Cipher
      */
     public static class Factory implements NamedFactory<Cipher> {
+        public static final String NAME = "blowfish-cbc";
+
+        public Factory() {
+            super();
+        }
+
         public String getName() {
-            return "blowfish-cbc";
+            return NAME;
         }
+
         public Cipher create() {
             return new BlowfishCBC();
         }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/eac1704e/sshd-core/src/main/java/org/apache/sshd/common/cipher/BuiltinCiphers.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/cipher/BuiltinCiphers.java b/sshd-core/src/main/java/org/apache/sshd/common/cipher/BuiltinCiphers.java
new file mode 100644
index 0000000..74c45f1
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/cipher/BuiltinCiphers.java
@@ -0,0 +1,234 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sshd.common.cipher;
+
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.apache.sshd.common.Cipher;
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.util.GenericUtils;
+
+/**
+ * Provides easy access to the currently implemented ciphers
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public enum BuiltinCiphers implements NamedFactory<NamedFactory<Cipher>> {
+    none(CipherNone.Factory.NAME, CipherNone.class) {
+        @Override
+        public NamedFactory<Cipher> create() {
+            return new CipherNone.Factory();
+        }
+    },
+    aes128cbc(AES128CBC.Factory.NAME, AES128CBC.class) {
+        @Override
+        public NamedFactory<Cipher> create() {
+            return new AES128CBC.Factory();
+        }
+    },
+    aes128ctr(AES128CTR.Factory.NAME, AES128CTR.class) {
+        @Override
+        public NamedFactory<Cipher> create() {
+            return new AES128CTR.Factory();
+        }
+    },
+    aes192cbc(AES192CBC.Factory.NAME, AES192CBC.class) {
+        @Override
+        public NamedFactory<Cipher> create() {
+            return new AES192CBC.Factory();
+        }
+    },
+    aes192ctr(AES192CTR.Factory.NAME, AES192CTR.class) {
+        @Override
+        public NamedFactory<Cipher> create() {
+            return new AES192CTR.Factory();
+        }
+    },
+    aes256cbc(AES256CBC.Factory.NAME, AES256CBC.class) {
+        @Override
+        public NamedFactory<Cipher> create() {
+            return new AES256CBC.Factory();
+        }
+    },
+    aes256ctr(AES256CTR.Factory.NAME, AES256CTR.class) {
+        @Override
+        public NamedFactory<Cipher> create() {
+            return new AES256CTR.Factory();
+        }
+    },
+    arcfour128(ARCFOUR128.Factory.NAME, ARCFOUR128.class) {
+        @Override
+        public NamedFactory<Cipher> create() {
+            return new ARCFOUR128.Factory();
+        }
+    },
+    arcfour256(ARCFOUR256.Factory.NAME, ARCFOUR256.class) {
+        @Override
+        public NamedFactory<Cipher> create() {
+            return new ARCFOUR256.Factory();
+        }
+    },
+    blowfishcbc(BlowfishCBC.Factory.NAME, BlowfishCBC.class) {
+        @Override
+        public NamedFactory<Cipher> create() {
+            return new BlowfishCBC.Factory();
+        }
+    },
+    tripledescbc(TripleDESCBC.Factory.NAME, TripleDESCBC.class) {
+        @Override
+        public NamedFactory<Cipher> create() {
+            return new TripleDESCBC.Factory();
+        }
+    };
+
+    private final String factoryName;
+    private Class<? extends Cipher> cipherType;
+
+    @Override
+    public final String getName() {
+        return factoryName;
+    }
+
+    public final Class<? extends Cipher> getCipherType() {
+        return cipherType;
+    }
+
+    BuiltinCiphers(String facName, Class<? extends Cipher> cipherClass) {
+        factoryName = facName;
+        cipherType = cipherClass;
+    }
+
+    private final AtomicReference<Boolean> _supported = new AtomicReference<>(null);
+
+    /**
+     * @return {@code true} if the current JVM configuration supports this
+     * cipher - e.g., AES-256 requires the <A HREF="http://www.oracle.com/technetwork/java/javase/downloads/">
+     * Java Cryptography Extension (JCE)</A>
+     */
+    public boolean isSupported() {
+        Boolean value;
+        synchronized (_supported) {
+            if ((value = _supported.get()) == null) {
+                // see BaseBuilder#fillWithDefaultValues
+                try {
+                    Exception t = CipherUtils.checkSupported(create());
+                    value = t == null;
+                } catch (Exception e) {
+                    value = Boolean.FALSE;
+                }
+
+                _supported.set(value);
+            }
+        }
+
+        return value;
+    }
+
+    public static final Set<BuiltinCiphers> VALUES =
+            Collections.unmodifiableSet(EnumSet.allOf(BuiltinCiphers.class));
+
+    /**
+     * @param s The {@link Enum}'s name - ignored if {@code null}/empty
+     * @return The matching {@link BuiltinCiphers} whose {@link Enum#name()} matches
+     * (case <U>insensitive</U>) the provided argument - {@code null} if no match
+     */
+    public static BuiltinCiphers fromString(String s) {
+        if (GenericUtils.isEmpty(s)) {
+            return null;
+        }
+
+        for (BuiltinCiphers c : VALUES) {
+            if (s.equalsIgnoreCase(c.name())) {
+                return c;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * @param factory The {@link NamedFactory} for the cipher - ignored if {@code null}
+     * @return The matching {@link BuiltinCiphers} whose factory name matches
+     * (case <U>insensitive</U>) the cipher factory name
+     * @see #fromFactoryName(String)
+     */
+    public static BuiltinCiphers fromFactory(NamedFactory<Cipher> factory) {
+        if (factory == null) {
+            return null;
+        } else {
+            return fromFactoryName(factory.getName());
+        }
+    }
+
+    /**
+     * @param n The factory name - ignored if {@code null}/empty
+     * @return The matching {@link BuiltinCiphers} whose factory name matches
+     * (case <U>insensitive</U>) the provided name - {@code null} if no match
+     */
+    public static BuiltinCiphers fromFactoryName(String n) {
+        if (GenericUtils.isEmpty(n)) {
+            return null;
+        }
+
+        for (BuiltinCiphers c : VALUES) {
+            if (n.equalsIgnoreCase(c.getName())) {
+                return c;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * @param c The {@link Cipher} instance - ignored if {@code null}
+     * @return The matching {@link BuiltinCiphers} - {@code null} if no match
+     * @see #fromCipherType(Class)
+     */
+    public static BuiltinCiphers fromCipher(Cipher c) {
+        if (c == null) {
+            return null;
+        } else {
+            return fromCipherType(c.getClass());
+        }
+    }
+
+    /**
+     * @param type The cipher type - ignored if {@code null} or not a
+     *             {@link Cipher} derived class
+     * @return The matching {@link BuiltinCiphers} - {@code null} if no match
+     */
+    public static BuiltinCiphers fromCipherType(Class<?> type) {
+        if ((type == null) || (!Cipher.class.isAssignableFrom(type))) {
+            return null;
+        }
+
+        for (BuiltinCiphers c : VALUES) {
+            Class<?> t = c.getCipherType();
+            if (t.isAssignableFrom(type)) {
+                return c;
+            }
+        }
+
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/eac1704e/sshd-core/src/main/java/org/apache/sshd/common/cipher/CipherNone.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/cipher/CipherNone.java b/sshd-core/src/main/java/org/apache/sshd/common/cipher/CipherNone.java
index 65c921b..95c82d9 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/cipher/CipherNone.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/cipher/CipherNone.java
@@ -35,9 +35,16 @@ public class CipherNone implements Cipher {
      * Named factory for the no-op Cipher
      */
     public static class Factory implements NamedFactory<Cipher> {
+        public static final String NAME = "none";
+
+        public Factory() {
+            super();
+        }
+
         public String getName() {
-            return "none";
+            return NAME;
         }
+
         public Cipher create() {
             return new CipherNone();
         }
@@ -52,9 +59,10 @@ public class CipherNone implements Cipher {
     }
 
     public void init(Mode mode, byte[] bytes, byte[] bytes1) throws Exception {
+        // ignored - always succeeds
     }
 
     public void update(byte[] input, int inputOffset, int inputLen) throws Exception {
+        // ignored - always succeeds
     }
-
 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/eac1704e/sshd-core/src/main/java/org/apache/sshd/common/cipher/CipherUtils.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/cipher/CipherUtils.java b/sshd-core/src/main/java/org/apache/sshd/common/cipher/CipherUtils.java
new file mode 100644
index 0000000..45070f6
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/cipher/CipherUtils.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sshd.common.cipher;
+
+import org.apache.sshd.common.Cipher;
+import org.apache.sshd.common.Factory;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class CipherUtils {
+    /**
+     * Checks if the provided cipher factory instance generates a cipher
+     * that is supported by the JCE
+     * @param f The cipher factory instance
+     * @return The {@link Exception} that the {@link Cipher#init(org.apache.sshd.common.Cipher.Mode, byte[], byte[])}
+     * call has thrown - {@code null} if successful (i.e., cipher supported)
+     * @see <A HREF="http://www.oracle.com/technetwork/java/javase/downloads/">Java Cryptography Extension (JCE)</A>
+     */
+    public static Exception checkSupported(Factory<? extends Cipher> f) {
+        return checkSupported(f.create());
+    }
+
+    /**
+     * Checks if the provided cipher is supported by the JCE
+     * @param c The {@link Cipher} to be checked
+     * @return The {@link Exception} that the {@link Cipher#init(org.apache.sshd.common.Cipher.Mode, byte[], byte[])}
+     * call has thrown - {@code null} if successful (i.e., cipher supported)
+     * @see <A HREF="http://www.oracle.com/technetwork/java/javase/downloads/">Java Cryptography Extension (JCE)</A>
+     */
+    public static Exception checkSupported(Cipher c) {
+        try {
+            byte[] key=new byte[c.getBlockSize()];
+            byte[] iv=new byte[c.getIVSize()];
+            c.init(Cipher.Mode.Encrypt, key, iv);
+            return null;
+        } catch(Exception e) {
+            return e;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/eac1704e/sshd-core/src/main/java/org/apache/sshd/common/cipher/TripleDESCBC.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/cipher/TripleDESCBC.java b/sshd-core/src/main/java/org/apache/sshd/common/cipher/TripleDESCBC.java
index bb194c3..5cdae9a 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/cipher/TripleDESCBC.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/cipher/TripleDESCBC.java
@@ -32,9 +32,16 @@ public class TripleDESCBC extends BaseCipher {
      * Named factory for TripleDESCBC Cipher
      */
     public static class Factory implements NamedFactory<Cipher> {
+        public static final String NAME = "3des-cbc";
+
+        public Factory() {
+            super();
+        }
+
         public String getName() {
-            return "3des-cbc";
+            return NAME;
         }
+
         public Cipher create() {
             return new TripleDESCBC();
         }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/eac1704e/sshd-core/src/main/java/org/apache/sshd/common/util/GenericUtils.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/GenericUtils.java b/sshd-core/src/main/java/org/apache/sshd/common/util/GenericUtils.java
new file mode 100644
index 0000000..b02c7ec
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/GenericUtils.java
@@ -0,0 +1,92 @@
+/*
+ * 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.util.Collection;
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class GenericUtils {
+    public static final int length(CharSequence cs) {
+        if (cs == null) {
+            return 0;
+        } else {
+            return cs.length();
+        }
+    }
+
+    public static final boolean isEmpty(CharSequence cs) {
+        if (length(cs) <= 0) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+    
+    public static final int size(Collection<?> c) {
+        if (c == null) {
+            return 0;
+        } else {
+            return c.size();
+        }
+    }
+
+    public static final boolean isEmpty(Collection<?> c) {
+        if (size(c) <= 0) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    public static final int size(Map<?,?> m) {
+        if (m == null) {
+            return 0;
+        } else {
+            return m.size();
+        }
+    }
+
+    public static final boolean isEmpty(Map<?,?> m) {
+        if (size(m) <= 0) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    public static final int length(Object ... a) {
+        if (a == null) {
+            return 0;
+        } else {
+            return a.length;
+        }
+    }
+
+    public static final boolean isEmpty(Object ... a) {
+        if (length(a) <= 0) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/eac1704e/sshd-core/src/test/java/org/apache/sshd/SshBuilderTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/SshBuilderTest.java b/sshd-core/src/test/java/org/apache/sshd/SshBuilderTest.java
new file mode 100644
index 0000000..a1d9a39
--- /dev/null
+++ b/sshd-core/src/test/java/org/apache/sshd/SshBuilderTest.java
@@ -0,0 +1,81 @@
+/*
+ * 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;
+
+import java.util.List;
+
+import org.apache.sshd.SshBuilder.BaseBuilder;
+import org.apache.sshd.common.Cipher;
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.cipher.BuiltinCiphers;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.util.BaseTest;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class SshBuilderTest extends BaseTest {
+    public SshBuilderTest() {
+        super();
+    }
+
+    /**
+     * Make sure that {@link BaseBuilder#setUpDefaultCiphers(boolean)} returns
+     * the correct result - i.e., according to the {@code ingoreUnsupported}
+     * parameter and in the defined preference order
+     */
+    @Test
+    public void testSetUpDefaultCiphers() {
+        for (boolean ignoreUnsupported : new boolean[] { true, false }) {
+            List<NamedFactory<Cipher>>  ciphers=BaseBuilder.setUpDefaultCiphers(ignoreUnsupported);
+            int                         numCiphers=GenericUtils.size(ciphers);
+            // make sure returned list size matches expected count
+            if (ignoreUnsupported) {
+                Assert.assertEquals("Incomplete full ciphers size", BaseBuilder.DEFAULT_CIPHERS_PREFERENCE.size(), numCiphers);
+            } else {
+                int expectedCount=0;
+                for (BuiltinCiphers c : BaseBuilder.DEFAULT_CIPHERS_PREFERENCE) {
+                    if (c.isSupported()) {
+                        expectedCount++;
+                    }
+                }
+                Assert.assertEquals("Incomplete supported ciphers size", expectedCount, numCiphers);
+            }
+            
+            // make sure order is according to the default preference list
+            List<String>    cipherNames=NamedFactory.Utils.getNameList(ciphers);
+            int             nameIndex=0;
+            for (BuiltinCiphers c : BaseBuilder.DEFAULT_CIPHERS_PREFERENCE) {
+                if ((!c.isSupported()) && (!ignoreUnsupported)) {
+                    continue;
+                }
+                
+                String  expectedName=c.getName();
+                Assert.assertTrue("Out of actual ciphers for expected=" + expectedName, nameIndex < numCiphers);
+                
+                String  actualName=cipherNames.get(nameIndex);
+                Assert.assertEquals("Mismatched cipher at position " + nameIndex + " for ignoreUnsupported=" + ignoreUnsupported, expectedName, actualName);
+                nameIndex++;
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/eac1704e/sshd-core/src/test/java/org/apache/sshd/common/cipher/BuiltinCiphersTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/common/cipher/BuiltinCiphersTest.java b/sshd-core/src/test/java/org/apache/sshd/common/cipher/BuiltinCiphersTest.java
new file mode 100644
index 0000000..f9e2f04
--- /dev/null
+++ b/sshd-core/src/test/java/org/apache/sshd/common/cipher/BuiltinCiphersTest.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.cipher;
+
+import org.apache.sshd.common.Cipher;
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.util.BaseTest;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class BuiltinCiphersTest extends BaseTest {
+    public BuiltinCiphersTest() {
+        super();
+    }
+
+    @Test
+    public void testFromEnumName() {
+        for (BuiltinCiphers expected : BuiltinCiphers.VALUES) {
+            String  name=expected.name();
+
+            for (int index=0; index < name.length(); index++) {
+                BuiltinCiphers  actual=BuiltinCiphers.fromString(name);
+                Assert.assertSame(name + " - mismatched enum values", expected, actual);
+                name = shuffleCase(name);   // prepare for next time
+            }
+        }
+    }
+
+    @Test
+    public void testFromFactoryName() {
+        for (BuiltinCiphers expected : BuiltinCiphers.VALUES) {
+            String  name=expected.getName();
+            
+            for (int index=0; index < name.length(); index++) {
+                BuiltinCiphers  actual=BuiltinCiphers.fromFactoryName(name);
+                Assert.assertSame(name + " - mismatched enum values", expected, actual);
+                name = shuffleCase(name);   // prepare for next time
+            }
+        }
+    }
+
+    @Test
+    public void testFromFactory() {
+        for (BuiltinCiphers expected : BuiltinCiphers.VALUES) {
+            if (!expected.isSupported()) {
+                System.out.append("Skip unsupported cipher: ").println(expected);
+                continue;
+            }
+            
+            NamedFactory<Cipher>    factory=expected.create();
+            Assert.assertEquals(expected.name() + " - mismatched factory names", expected.getName(), factory.getName());
+
+            BuiltinCiphers  actual=BuiltinCiphers.fromFactory(factory);
+            Assert.assertSame(expected.getName() + " - mismatched enum values", expected, actual);
+        }
+    }
+
+    @Test
+    public void testFromCipher() {
+        for (BuiltinCiphers expected : BuiltinCiphers.VALUES) {
+            if (!expected.isSupported()) {
+                System.out.append("Skip unsupported cipher: ").println(expected);
+                continue;
+            }
+            
+            NamedFactory<Cipher>    factory=expected.create();
+            Cipher                  cipher=factory.create();
+            assertObjectInstanceOf(expected.name() + " - mismatched cipher type", expected.getCipherType(), cipher);
+
+            BuiltinCiphers  actual=BuiltinCiphers.fromCipher(cipher);
+            Assert.assertSame(expected.getName() + " - mismatched enum values", expected, actual);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/eac1704e/sshd-core/src/test/java/org/apache/sshd/util/BaseTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/util/BaseTest.java b/sshd-core/src/test/java/org/apache/sshd/util/BaseTest.java
index 49b8f31..205c889 100644
--- a/sshd-core/src/test/java/org/apache/sshd/util/BaseTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/util/BaseTest.java
@@ -18,10 +18,13 @@
  */
 package org.apache.sshd.util;
 
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import java.io.File;
 
+import org.apache.sshd.common.util.GenericUtils;
 import org.junit.Rule;
 import org.junit.rules.TestName;
 import org.junit.rules.TestWatcher;
@@ -57,12 +60,44 @@ public abstract class BaseTest extends TestWatcher {
         System.out.println("\nFinished " + description.getClassName() + ":" + description.getMethodName() + " in " + duration + " ms\n");
     }
 
-    public static final File assertHierarchyTargetFolderExists(File folder) {
+    /* ------------------- Useful extra test helpers ---------------------- */
+
+    public static String shuffleCase(CharSequence cs) {
+        if (GenericUtils.isEmpty(cs)) {
+            return "";
+        }
+
+        StringBuilder sb = new StringBuilder(cs.length());
+        for (int index = 0; index < cs.length(); index++) {
+            char ch = cs.charAt(index);
+            double v = Math.random();
+            if (Double.compare(v, 0.3d) < 0) {
+                ch = Character.toUpperCase(ch);
+            } else if ((Double.compare(v, 0.3d) >= 0) && (Double.compare(v, 0.6d) < 0)) {
+                ch = Character.toLowerCase(ch);
+            }
+            sb.append(ch);
+        }
+
+        return sb.toString();
+    }
+
+    /* ----------------------- Useful extra assertions --------------------- */
+
+    public static File assertHierarchyTargetFolderExists(File folder) {
         if (!folder.exists()) {
             assertTrue("Failed to create hierarchy of " + folder.getAbsolutePath(), folder.mkdirs());
         }
         
         return folder;
     }
-
+    
+    public static void assertObjectInstanceOf(String message, Class<?> expected, Object obj) {
+        assertNotNull(message + " - no actual object", obj);
+        
+        Class<?>    actual=obj.getClass();
+        if (!expected.isAssignableFrom(actual)) {
+            fail(message + " - actual object type (" + actual.getName() + ") incompatible with expected (" + expected.getName() + ")");
+        }
+    }
 }