Repository: mina-sshd
Updated Branches:
  refs/heads/master 0f6976447 -> 4aef497ee


[SSHD-763] Add support for reading ECDSA PUTTY key files


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

Branch: refs/heads/master
Commit: 4aef497ee8a5d161735da419591338cef9adec62
Parents: 0f69764
Author: Goldstein Lyor <l...@c-b4.com>
Authored: Sun Sep 17 11:01:55 2017 +0300
Committer: Goldstein Lyor <l...@c-b4.com>
Committed: Sun Sep 17 12:26:42 2017 +0300

----------------------------------------------------------------------
 .../loader/putty/AbstractPuttyKeyDecoder.java   | 24 ++---
 .../keys/loader/putty/DSSPuttyKeyDecoder.java   |  6 +-
 .../keys/loader/putty/ECDSAPuttyKeyDecoder.java | 98 ++++++++++++++++++++
 .../putty/PuttyKeyPairResourceParser.java       | 11 +--
 .../keys/loader/putty/PuttyKeyReader.java       | 22 ++++-
 .../config/keys/loader/putty/PuttyKeyUtils.java | 22 +++--
 .../keys/loader/putty/RSAPuttyKeyDecoder.java   |  6 +-
 .../keys/loader/putty/PuttyKeyUtilsTest.java    | 16 +++-
 ...KeyUtilsTest-ecdsa-sha2-nistp256-KeyPair.ppk | 10 ++
 ...KeyUtilsTest-ecdsa-sha2-nistp384-KeyPair.ppk | 11 +++
 ...KeyUtilsTest-ecdsa-sha2-nistp521-KeyPair.ppk | 12 +++
 ...-AES-256-CBC-ecdsa-sha2-nistp256-KeyPair.ppk | 10 ++
 ...-AES-256-CBC-ecdsa-sha2-nistp384-KeyPair.ppk | 11 +++
 ...-AES-256-CBC-ecdsa-sha2-nistp521-KeyPair.ppk | 12 +++
 .../org/apache/sshd/common/cipher/ECCurves.java |  9 +-
 .../config/keys/IdentityResourceLoader.java     | 49 ++++++++++
 .../common/config/keys/KeyEntryResolver.java    | 22 +----
 .../impl/AbstractIdentityResourceLoader.java    | 62 +++++++++++++
 .../keys/impl/AbstractKeyEntryResolver.java     | 28 +-----
 .../keys/impl/ECDSAPublicKeyEntryDecoder.java   |  2 +-
 .../apache/sshd/common/util/GenericUtils.java   |  5 +-
 21 files changed, 353 insertions(+), 95 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/4aef497e/sshd-contrib/src/main/java/org/apache/sshd/common/config/keys/loader/putty/AbstractPuttyKeyDecoder.java
----------------------------------------------------------------------
diff --git 
a/sshd-contrib/src/main/java/org/apache/sshd/common/config/keys/loader/putty/AbstractPuttyKeyDecoder.java
 
b/sshd-contrib/src/main/java/org/apache/sshd/common/config/keys/loader/putty/AbstractPuttyKeyDecoder.java
index 5b29618..101119b 100644
--- 
a/sshd-contrib/src/main/java/org/apache/sshd/common/config/keys/loader/putty/AbstractPuttyKeyDecoder.java
+++ 
b/sshd-contrib/src/main/java/org/apache/sshd/common/config/keys/loader/putty/AbstractPuttyKeyDecoder.java
@@ -25,35 +25,30 @@ import java.io.InputStream;
 import java.io.StreamCorruptedException;
 import java.security.GeneralSecurityException;
 import java.security.KeyPair;
+import java.security.PrivateKey;
+import java.security.PublicKey;
 import java.util.Base64;
 import java.util.Base64.Decoder;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
-import java.util.Objects;
 
 import org.apache.sshd.common.config.keys.FilePasswordProvider;
+import org.apache.sshd.common.config.keys.impl.AbstractIdentityResourceLoader;
 import org.apache.sshd.common.config.keys.loader.KeyPairResourceParser;
 import org.apache.sshd.common.util.GenericUtils;
 import org.apache.sshd.common.util.ValidateUtils;
-import org.apache.sshd.common.util.logging.AbstractLoggingBean;
 
 /**
  * @author <a href="mailto:d...@mina.apache.org";>Apache MINA SSHD Project</a>
  */
-public abstract class AbstractPuttyKeyDecoder
-                extends AbstractLoggingBean
-                implements PuttyKeyPairResourceParser {
+public abstract class AbstractPuttyKeyDecoder<PUB extends PublicKey, PRV 
extends PrivateKey>
+                extends AbstractIdentityResourceLoader<PUB, PRV>
+                implements PuttyKeyPairResourceParser<PUB, PRV> {
     public static final String ENCRYPTION_HEADER = "Encryption";
 
-    private final String keyType;
-    protected AbstractPuttyKeyDecoder(String keyType) {
-        this.keyType = keyType;
-    }
-
-    @Override
-    public String getKeyType() {
-        return keyType;
+    protected AbstractPuttyKeyDecoder(Class<PUB> pubType, Class<PRV> prvType, 
Collection<String> names) {
+        super(pubType, prvType, names);
     }
 
     @Override
@@ -74,8 +69,9 @@ public abstract class AbstractPuttyKeyDecoder
                 return false;
             }
 
+            Collection<String> supported = getSupportedTypeNames();
             String typeValue = l.substring(pos + 1).trim();
-            return Objects.equals(getKeyType(), typeValue);
+            return supported.contains(typeValue);
         }
 
         return false;

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/4aef497e/sshd-contrib/src/main/java/org/apache/sshd/common/config/keys/loader/putty/DSSPuttyKeyDecoder.java
----------------------------------------------------------------------
diff --git 
a/sshd-contrib/src/main/java/org/apache/sshd/common/config/keys/loader/putty/DSSPuttyKeyDecoder.java
 
b/sshd-contrib/src/main/java/org/apache/sshd/common/config/keys/loader/putty/DSSPuttyKeyDecoder.java
index c03a9d5..366aead 100644
--- 
a/sshd-contrib/src/main/java/org/apache/sshd/common/config/keys/loader/putty/DSSPuttyKeyDecoder.java
+++ 
b/sshd-contrib/src/main/java/org/apache/sshd/common/config/keys/loader/putty/DSSPuttyKeyDecoder.java
@@ -26,6 +26,8 @@ import java.security.KeyFactory;
 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.spec.DSAPrivateKeySpec;
 import java.security.spec.DSAPublicKeySpec;
 import java.util.Collection;
@@ -38,11 +40,11 @@ import org.apache.sshd.common.util.security.SecurityUtils;
 /**
  * @author <a href="mailto:d...@mina.apache.org";>Apache MINA SSHD Project</a>
  */
-public class DSSPuttyKeyDecoder extends AbstractPuttyKeyDecoder {
+public class DSSPuttyKeyDecoder extends AbstractPuttyKeyDecoder<DSAPublicKey, 
DSAPrivateKey> {
     public static final DSSPuttyKeyDecoder INSTANCE = new DSSPuttyKeyDecoder();
 
     public DSSPuttyKeyDecoder() {
-        super(KeyPairProvider.SSH_DSS);
+        super(DSAPublicKey.class, DSAPrivateKey.class, 
Collections.singletonList(KeyPairProvider.SSH_DSS));
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/4aef497e/sshd-contrib/src/main/java/org/apache/sshd/common/config/keys/loader/putty/ECDSAPuttyKeyDecoder.java
----------------------------------------------------------------------
diff --git 
a/sshd-contrib/src/main/java/org/apache/sshd/common/config/keys/loader/putty/ECDSAPuttyKeyDecoder.java
 
b/sshd-contrib/src/main/java/org/apache/sshd/common/config/keys/loader/putty/ECDSAPuttyKeyDecoder.java
new file mode 100644
index 0000000..03bfa6c
--- /dev/null
+++ 
b/sshd-contrib/src/main/java/org/apache/sshd/common/config/keys/loader/putty/ECDSAPuttyKeyDecoder.java
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sshd.common.config.keys.loader.putty;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.ECPoint;
+import java.security.spec.ECPrivateKeySpec;
+import java.security.spec.ECPublicKeySpec;
+import java.security.spec.InvalidKeySpecException;
+import java.util.Collection;
+import java.util.Collections;
+
+import org.apache.sshd.common.cipher.ECCurves;
+import org.apache.sshd.common.config.keys.KeyUtils;
+import org.apache.sshd.common.util.buffer.BufferUtils;
+import org.apache.sshd.common.util.security.SecurityUtils;
+
+/**
+ * TODO Add javadoc
+ *
+ * @author <a href="mailto:d...@mina.apache.org";>Apache MINA SSHD Project</a>
+ */
+public class ECDSAPuttyKeyDecoder extends AbstractPuttyKeyDecoder<ECPublicKey, 
ECPrivateKey> {
+    public static final ECDSAPuttyKeyDecoder INSTANCE = new 
ECDSAPuttyKeyDecoder();
+
+    public ECDSAPuttyKeyDecoder() {
+        super(ECPublicKey.class, ECPrivateKey.class, ECCurves.KEY_TYPES);
+    }
+
+    @Override
+    public Collection<KeyPair> loadKeyPairs(String resourceKey, PuttyKeyReader 
pubReader, PuttyKeyReader prvReader)
+            throws IOException, GeneralSecurityException {
+        String keyType = pubReader.readString();
+        ECCurves curve = ECCurves.fromKeyType(keyType);
+        if (curve == null) {
+            throw new InvalidKeySpecException("Not an EC curve name: " + 
keyType);
+        }
+
+        if (!SecurityUtils.isECCSupported()) {
+            throw new NoSuchProviderException("ECC not supported");
+        }
+
+        String encCurveName = pubReader.readString();
+        String keyCurveName = curve.getName();
+        if (!keyCurveName.equals(encCurveName)) {
+            throw new InvalidKeySpecException("Mismatched key curve name (" + 
keyCurveName + ") vs. encoded one (" + encCurveName + ")");
+        }
+
+        byte[] octets = pubReader.read();
+        ECPoint w;
+        try {
+            w = ECCurves.octetStringToEcPoint(octets);
+            if (w == null) {
+                throw new InvalidKeySpecException("No public ECPoint generated 
for curve=" + keyCurveName
+                        + " from octets=" + BufferUtils.toHex(':', octets));
+            }
+        } catch (RuntimeException e) {
+            throw new InvalidKeySpecException("Failed (" + 
e.getClass().getSimpleName() + ")"
+                    + " to generate public ECPoint for curve=" + keyCurveName
+                    + " from octets=" + BufferUtils.toHex(':', octets)
+                    + ": " + e.getMessage());
+        }
+
+        KeyFactory kf = SecurityUtils.getKeyFactory(KeyUtils.EC_ALGORITHM);
+        ECParameterSpec paramSpec = curve.getParameters();
+        PublicKey pubKey = kf.generatePublic(new ECPublicKeySpec(w, 
paramSpec));
+
+        BigInteger s = prvReader.readInt();
+        PrivateKey prvKey = kf.generatePrivate(new ECPrivateKeySpec(s, 
paramSpec));
+        return Collections.singletonList(new KeyPair(pubKey, prvKey));
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/4aef497e/sshd-contrib/src/main/java/org/apache/sshd/common/config/keys/loader/putty/PuttyKeyPairResourceParser.java
----------------------------------------------------------------------
diff --git 
a/sshd-contrib/src/main/java/org/apache/sshd/common/config/keys/loader/putty/PuttyKeyPairResourceParser.java
 
b/sshd-contrib/src/main/java/org/apache/sshd/common/config/keys/loader/putty/PuttyKeyPairResourceParser.java
index 774624b..a1e795b 100644
--- 
a/sshd-contrib/src/main/java/org/apache/sshd/common/config/keys/loader/putty/PuttyKeyPairResourceParser.java
+++ 
b/sshd-contrib/src/main/java/org/apache/sshd/common/config/keys/loader/putty/PuttyKeyPairResourceParser.java
@@ -25,6 +25,8 @@ import java.security.GeneralSecurityException;
 import java.security.KeyPair;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
 import java.security.spec.InvalidKeySpecException;
 import java.util.Arrays;
 import java.util.Collections;
@@ -35,6 +37,7 @@ import javax.crypto.Cipher;
 import javax.crypto.spec.IvParameterSpec;
 import javax.crypto.spec.SecretKeySpec;
 
+import org.apache.sshd.common.config.keys.IdentityResourceLoader;
 import org.apache.sshd.common.config.keys.loader.KeyPairResourceParser;
 import org.apache.sshd.common.digest.BuiltinDigests;
 import org.apache.sshd.common.util.GenericUtils;
@@ -87,7 +90,8 @@ import org.apache.sshd.common.util.security.SecurityUtils;
  * @author <a href="mailto:d...@mina.apache.org";>Apache MINA SSHD Project</a>
  */
 //CHECKSTYLE:ON
-public interface PuttyKeyPairResourceParser extends KeyPairResourceParser {
+public interface PuttyKeyPairResourceParser<PUB extends PublicKey, PRV extends 
PrivateKey>
+        extends IdentityResourceLoader<PUB, PRV>, KeyPairResourceParser {
     String KEY_FILE_HEADER_PREFIX = "PuTTY-User-Key-File";
     String PUBLIC_LINES_HEADER = "Public-Lines";
     String PRIVATE_LINES_HEADER = "Private-Lines";
@@ -105,11 +109,6 @@ public interface PuttyKeyPairResourceParser extends 
KeyPairResourceParser {
      */
     String NO_PRIVATE_KEY_ENCRYPTION_VALUE = "none";
 
-    /**
-     * @return Type of key being parsed by the resource parser
-     */
-    String getKeyType();
-
     @Override
     default boolean canExtractKeyPairs(String resourceKey, List<String> lines)
             throws IOException, GeneralSecurityException {

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/4aef497e/sshd-contrib/src/main/java/org/apache/sshd/common/config/keys/loader/putty/PuttyKeyReader.java
----------------------------------------------------------------------
diff --git 
a/sshd-contrib/src/main/java/org/apache/sshd/common/config/keys/loader/putty/PuttyKeyReader.java
 
b/sshd-contrib/src/main/java/org/apache/sshd/common/config/keys/loader/putty/PuttyKeyReader.java
index 9f1bd73..4fb63d1 100644
--- 
a/sshd-contrib/src/main/java/org/apache/sshd/common/config/keys/loader/putty/PuttyKeyReader.java
+++ 
b/sshd-contrib/src/main/java/org/apache/sshd/common/config/keys/loader/putty/PuttyKeyReader.java
@@ -25,6 +25,8 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.StreamCorruptedException;
 import java.math.BigInteger;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
 
 /**
  * Helper class for {@code Putty} key files decoders
@@ -45,17 +47,27 @@ public class PuttyKeyReader implements Closeable {
         }
     }
 
-    private byte[] read() throws IOException {
+    public String readString() throws IOException {
+        return readString(StandardCharsets.UTF_8);
+    }
+
+    public String readString(Charset cs) throws IOException {
+        byte[] data = read();
+        return new String(data, cs);
+    }
+
+    public BigInteger readInt() throws IOException {
+        byte[] bytes = read();
+        return new BigInteger(bytes);
+    }
+
+    public byte[] read() throws IOException {
         int len = di.readInt();
         byte[] r = new byte[len];
         di.readFully(r);
         return r;
     }
 
-    public BigInteger readInt() throws IOException {
-        return new BigInteger(read());
-    }
-
     @Override
     public void close() throws IOException {
         di.close();

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/4aef497e/sshd-contrib/src/main/java/org/apache/sshd/common/config/keys/loader/putty/PuttyKeyUtils.java
----------------------------------------------------------------------
diff --git 
a/sshd-contrib/src/main/java/org/apache/sshd/common/config/keys/loader/putty/PuttyKeyUtils.java
 
b/sshd-contrib/src/main/java/org/apache/sshd/common/config/keys/loader/putty/PuttyKeyUtils.java
index 61ad233..a3b4745 100644
--- 
a/sshd-contrib/src/main/java/org/apache/sshd/common/config/keys/loader/putty/PuttyKeyUtils.java
+++ 
b/sshd-contrib/src/main/java/org/apache/sshd/common/config/keys/loader/putty/PuttyKeyUtils.java
@@ -20,9 +20,10 @@
 package org.apache.sshd.common.config.keys.loader.putty;
 
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
-import java.util.SortedMap;
+import java.util.NavigableMap;
 import java.util.TreeMap;
 
 import org.apache.sshd.common.config.keys.loader.KeyPairResourceParser;
@@ -31,20 +32,25 @@ import 
org.apache.sshd.common.config.keys.loader.KeyPairResourceParser;
  * @author <a href="mailto:d...@mina.apache.org";>Apache MINA SSHD Project</a>
  */
 public final class PuttyKeyUtils {
-    public static final List<PuttyKeyPairResourceParser> DEFAULT_PARSERS =
+    public static final List<PuttyKeyPairResourceParser<?, ?>> DEFAULT_PARSERS 
=
             Collections.unmodifiableList(
                     Arrays.asList(
                             RSAPuttyKeyDecoder.INSTANCE,
-                            DSSPuttyKeyDecoder.INSTANCE));
-    public static final SortedMap<String, PuttyKeyPairResourceParser> 
BY_KEY_TYPE =
-            Collections.unmodifiableSortedMap(
-                    new TreeMap<String, 
PuttyKeyPairResourceParser>(String.CASE_INSENSITIVE_ORDER) {
+                            DSSPuttyKeyDecoder.INSTANCE,
+                            ECDSAPuttyKeyDecoder.INSTANCE));
+
+    public static final NavigableMap<String, PuttyKeyPairResourceParser<?, ?>> 
BY_KEY_TYPE =
+            Collections.unmodifiableNavigableMap(
+                    new TreeMap<String, PuttyKeyPairResourceParser<?, 
?>>(String.CASE_INSENSITIVE_ORDER) {
                         // Not serializing it
                         private static final long serialVersionUID = 1L;
 
                         {
-                            for (PuttyKeyPairResourceParser p : 
DEFAULT_PARSERS) {
-                                put(p.getKeyType(), p);
+                            for (PuttyKeyPairResourceParser<?, ?> p : 
DEFAULT_PARSERS) {
+                                Collection<String> supported = 
p.getSupportedTypeNames();
+                                for (String k : supported) {
+                                    put(k, p);
+                                }
                             }
                         }
             });

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/4aef497e/sshd-contrib/src/main/java/org/apache/sshd/common/config/keys/loader/putty/RSAPuttyKeyDecoder.java
----------------------------------------------------------------------
diff --git 
a/sshd-contrib/src/main/java/org/apache/sshd/common/config/keys/loader/putty/RSAPuttyKeyDecoder.java
 
b/sshd-contrib/src/main/java/org/apache/sshd/common/config/keys/loader/putty/RSAPuttyKeyDecoder.java
index d0de05d..0a55d55 100644
--- 
a/sshd-contrib/src/main/java/org/apache/sshd/common/config/keys/loader/putty/RSAPuttyKeyDecoder.java
+++ 
b/sshd-contrib/src/main/java/org/apache/sshd/common/config/keys/loader/putty/RSAPuttyKeyDecoder.java
@@ -26,6 +26,8 @@ import java.security.KeyFactory;
 import java.security.KeyPair;
 import java.security.PrivateKey;
 import java.security.PublicKey;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
 import java.security.spec.RSAPrivateCrtKeySpec;
 import java.security.spec.RSAPrivateKeySpec;
 import java.security.spec.RSAPublicKeySpec;
@@ -39,11 +41,11 @@ import org.apache.sshd.common.util.security.SecurityUtils;
 /**
  * @author <a href="mailto:d...@mina.apache.org";>Apache MINA SSHD Project</a>
  */
-public class RSAPuttyKeyDecoder extends AbstractPuttyKeyDecoder {
+public class RSAPuttyKeyDecoder extends AbstractPuttyKeyDecoder<RSAPublicKey, 
RSAPrivateKey> {
     public static final RSAPuttyKeyDecoder INSTANCE = new RSAPuttyKeyDecoder();
 
     public RSAPuttyKeyDecoder() {
-        super(KeyPairProvider.SSH_RSA);
+        super(RSAPublicKey.class, RSAPrivateKey.class, 
Collections.singletonList(KeyPairProvider.SSH_RSA));
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/4aef497e/sshd-contrib/src/test/java/org/apache/sshd/common/config/keys/loader/putty/PuttyKeyUtilsTest.java
----------------------------------------------------------------------
diff --git 
a/sshd-contrib/src/test/java/org/apache/sshd/common/config/keys/loader/putty/PuttyKeyUtilsTest.java
 
b/sshd-contrib/src/test/java/org/apache/sshd/common/config/keys/loader/putty/PuttyKeyUtilsTest.java
index e8208d1..5ab953a 100644
--- 
a/sshd-contrib/src/test/java/org/apache/sshd/common/config/keys/loader/putty/PuttyKeyUtilsTest.java
+++ 
b/sshd-contrib/src/test/java/org/apache/sshd/common/config/keys/loader/putty/PuttyKeyUtilsTest.java
@@ -55,7 +55,7 @@ public class PuttyKeyUtilsTest extends BaseTestSupport {
     private final String keyType;
     private final String regularFile;
     private final String encryptedFile;
-    private final PuttyKeyPairResourceParser parser;
+    private final PuttyKeyPairResourceParser<?, ?> parser;
 
     public PuttyKeyUtilsTest(String keyType) {
         this.keyType = keyType;
@@ -77,17 +77,24 @@ public class PuttyKeyUtilsTest extends BaseTestSupport {
     public void testCanDecodePuttyKeyFile() throws IOException, 
GeneralSecurityException {
         for (String resource : new String[]{regularFile, encryptedFile}) {
             URL url = getClass().getResource(resource);
-            assertNotNull("Missing test resource: " + resource, url);
+            if (GenericUtils.isSameReference(regularFile, resource)) {
+                assertNotNull("Missing test resource: " + resource, url);
+            } else {
+                if (url == null) {
+                    outputDebugMessage("Skip non-existing encrypted file: %s", 
resource);
+                    continue;
+                }
+            }
 
             List<String> lines = IoUtils.readAllLines(url);
             assertTrue(resource + " - can extract key pair", 
parser.canExtractKeyPairs(resource, lines));
 
-            for (PuttyKeyPairResourceParser other : 
PuttyKeyUtils.BY_KEY_TYPE.values()) {
+            for (PuttyKeyPairResourceParser<?, ?> other : 
PuttyKeyUtils.BY_KEY_TYPE.values()) {
                 if (parser == other) {
                     continue;
                 }
 
-                assertFalse(other.getKeyType() + "/" + resource + " - 
unexpected extraction capability",
+                assertFalse(other.getClass().getSimpleName() + "/" + resource 
+ " - unexpected extraction capability",
                         other.canExtractKeyPairs(resource, lines));
             }
         }
@@ -107,6 +114,7 @@ public class PuttyKeyUtilsTest extends BaseTestSupport {
     public void testDecodeEncryptedPuttyKeyFile() throws IOException, 
GeneralSecurityException {
         Assume.assumeTrue(BuiltinCiphers.aes256cbc.getTransformation() + " 
N/A", BuiltinCiphers.aes256cbc.isSupported());
         URL url = getClass().getResource(encryptedFile);
+        Assume.assumeTrue("Skip non-existent encrypted file: " + 
encryptedFile, url != null);
         assertNotNull("Missing test resource: " + encryptedFile, url);
 
         Collection<KeyPair> keys = parser.loadKeyPairs(url, r -> PASSWORD);

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/4aef497e/sshd-contrib/src/test/resources/org/apache/sshd/common/config/keys/loader/putty/PuttyKeyUtilsTest-ecdsa-sha2-nistp256-KeyPair.ppk
----------------------------------------------------------------------
diff --git 
a/sshd-contrib/src/test/resources/org/apache/sshd/common/config/keys/loader/putty/PuttyKeyUtilsTest-ecdsa-sha2-nistp256-KeyPair.ppk
 
b/sshd-contrib/src/test/resources/org/apache/sshd/common/config/keys/loader/putty/PuttyKeyUtilsTest-ecdsa-sha2-nistp256-KeyPair.ppk
new file mode 100644
index 0000000..509538a
--- /dev/null
+++ 
b/sshd-contrib/src/test/resources/org/apache/sshd/common/config/keys/loader/putty/PuttyKeyUtilsTest-ecdsa-sha2-nistp256-KeyPair.ppk
@@ -0,0 +1,10 @@
+PuTTY-User-Key-File-2: ecdsa-sha2-nistp256
+Encryption: none
+Comment: ecdsa-key-20170917
+Public-Lines: 3
+AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBM99zj2+E6AN
+xMZ/2SKFP/fAvPfUJUdsgJyn4g7nf36vNpoaRyq1FyHLxyT34AgTl1n3DwcaBXXC
+O5pCv6xFwYk=
+Private-Lines: 1
+AAAAIQDdmu/Dr68r6a0PNbQUN1bX+zS6J5jFsOlEAx8sR73Tuw==
+Private-MAC: 012e0d61593a431ae84beb6216dd29e4b203c1c0

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/4aef497e/sshd-contrib/src/test/resources/org/apache/sshd/common/config/keys/loader/putty/PuttyKeyUtilsTest-ecdsa-sha2-nistp384-KeyPair.ppk
----------------------------------------------------------------------
diff --git 
a/sshd-contrib/src/test/resources/org/apache/sshd/common/config/keys/loader/putty/PuttyKeyUtilsTest-ecdsa-sha2-nistp384-KeyPair.ppk
 
b/sshd-contrib/src/test/resources/org/apache/sshd/common/config/keys/loader/putty/PuttyKeyUtilsTest-ecdsa-sha2-nistp384-KeyPair.ppk
new file mode 100644
index 0000000..238261c
--- /dev/null
+++ 
b/sshd-contrib/src/test/resources/org/apache/sshd/common/config/keys/loader/putty/PuttyKeyUtilsTest-ecdsa-sha2-nistp384-KeyPair.ppk
@@ -0,0 +1,11 @@
+PuTTY-User-Key-File-2: ecdsa-sha2-nistp384
+Encryption: none
+Comment: ecdsa-key-20170917
+Public-Lines: 3
+AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBNHjIMrdMfXw
+CUqBAhkZw0vXB+qypkiTcL1CmcopmPrKvGHFieFmedeCQotjwJkoAAeb5isZNOXy
+h+7TnHGNrE/pZkHuNwACilpOt659hbhR2OGHX0jdpb8y4RVkuPQssg==
+Private-Lines: 2
+AAAAMHNGt3UPG3evJVl1GRoXXnqTafWLDQdWA2A1tXi8oRW0hhHMRe9/v0SCGL7S
+nL3asg==
+Private-MAC: 6fb6e93559ecacfa468aa5ff9776e4d4283db5ba

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/4aef497e/sshd-contrib/src/test/resources/org/apache/sshd/common/config/keys/loader/putty/PuttyKeyUtilsTest-ecdsa-sha2-nistp521-KeyPair.ppk
----------------------------------------------------------------------
diff --git 
a/sshd-contrib/src/test/resources/org/apache/sshd/common/config/keys/loader/putty/PuttyKeyUtilsTest-ecdsa-sha2-nistp521-KeyPair.ppk
 
b/sshd-contrib/src/test/resources/org/apache/sshd/common/config/keys/loader/putty/PuttyKeyUtilsTest-ecdsa-sha2-nistp521-KeyPair.ppk
new file mode 100644
index 0000000..f60a78e
--- /dev/null
+++ 
b/sshd-contrib/src/test/resources/org/apache/sshd/common/config/keys/loader/putty/PuttyKeyUtilsTest-ecdsa-sha2-nistp521-KeyPair.ppk
@@ -0,0 +1,12 @@
+PuTTY-User-Key-File-2: ecdsa-sha2-nistp521
+Encryption: none
+Comment: ecdsa-key-20170917
+Public-Lines: 4
+AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBADGM237T9rT
+zE++sOFDN0VWfYfojlQ8dYP82OlgA24Yh0ZpOsezBBiHtHfMHl9tWHmch1YKmH7B
+lOfqbOgcIhz9cwA2V7Nu3IUGqxZT18LOXEpcdyDSphJ6jsy1urqBLrOz4DF6Udyr
+rFV4OQELovf8YdUsM91YPfe1DfnSRi1I5v20uA==
+Private-Lines: 2
+AAAAQgE28iZoHARx+2VzL7Y45FaY44TngX2b4StlC8wOlYF7NY/ba+Pt2RT/WcNL
+ytmLdj5QeV/fFJ9x8i00mTU6KCF2AA==
+Private-MAC: 7379e9986066087dff9339d2b0b968c2b31f45c7

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/4aef497e/sshd-contrib/src/test/resources/org/apache/sshd/common/config/keys/loader/putty/super-secret-passphrase-AES-256-CBC-ecdsa-sha2-nistp256-KeyPair.ppk
----------------------------------------------------------------------
diff --git 
a/sshd-contrib/src/test/resources/org/apache/sshd/common/config/keys/loader/putty/super-secret-passphrase-AES-256-CBC-ecdsa-sha2-nistp256-KeyPair.ppk
 
b/sshd-contrib/src/test/resources/org/apache/sshd/common/config/keys/loader/putty/super-secret-passphrase-AES-256-CBC-ecdsa-sha2-nistp256-KeyPair.ppk
new file mode 100644
index 0000000..4c601c7
--- /dev/null
+++ 
b/sshd-contrib/src/test/resources/org/apache/sshd/common/config/keys/loader/putty/super-secret-passphrase-AES-256-CBC-ecdsa-sha2-nistp256-KeyPair.ppk
@@ -0,0 +1,10 @@
+PuTTY-User-Key-File-2: ecdsa-sha2-nistp256
+Encryption: aes256-cbc
+Comment: ecdsa-key-20170917
+Public-Lines: 3
+AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBM99zj2+E6AN
+xMZ/2SKFP/fAvPfUJUdsgJyn4g7nf36vNpoaRyq1FyHLxyT34AgTl1n3DwcaBXXC
+O5pCv6xFwYk=
+Private-Lines: 1
+/8MdniIqAaST5t3/bRx4mFdFxqN8jIwI0Hh7VTy8IV143j+PktgGIoHsUwTiEujQ
+Private-MAC: be4b37d4b65ad09e6890534a2ba355599da796c6

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/4aef497e/sshd-contrib/src/test/resources/org/apache/sshd/common/config/keys/loader/putty/super-secret-passphrase-AES-256-CBC-ecdsa-sha2-nistp384-KeyPair.ppk
----------------------------------------------------------------------
diff --git 
a/sshd-contrib/src/test/resources/org/apache/sshd/common/config/keys/loader/putty/super-secret-passphrase-AES-256-CBC-ecdsa-sha2-nistp384-KeyPair.ppk
 
b/sshd-contrib/src/test/resources/org/apache/sshd/common/config/keys/loader/putty/super-secret-passphrase-AES-256-CBC-ecdsa-sha2-nistp384-KeyPair.ppk
new file mode 100644
index 0000000..f57f5fd
--- /dev/null
+++ 
b/sshd-contrib/src/test/resources/org/apache/sshd/common/config/keys/loader/putty/super-secret-passphrase-AES-256-CBC-ecdsa-sha2-nistp384-KeyPair.ppk
@@ -0,0 +1,11 @@
+PuTTY-User-Key-File-2: ecdsa-sha2-nistp384
+Encryption: aes256-cbc
+Comment: ecdsa-key-20170917
+Public-Lines: 3
+AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBNHjIMrdMfXw
+CUqBAhkZw0vXB+qypkiTcL1CmcopmPrKvGHFieFmedeCQotjwJkoAAeb5isZNOXy
+h+7TnHGNrE/pZkHuNwACilpOt659hbhR2OGHX0jdpb8y4RVkuPQssg==
+Private-Lines: 2
+MOgJnSZ8ZqGHFVtQvYKpOyTGWjMVIjIOMIUwhbxBuTiQ7WEyNPn9jjTsSwXtJxrG
+UI6NGeIqZ41P2e8JINhMIg==
+Private-MAC: 5ec40946270150ddfca35cce61f4265d7bfe7b7f

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/4aef497e/sshd-contrib/src/test/resources/org/apache/sshd/common/config/keys/loader/putty/super-secret-passphrase-AES-256-CBC-ecdsa-sha2-nistp521-KeyPair.ppk
----------------------------------------------------------------------
diff --git 
a/sshd-contrib/src/test/resources/org/apache/sshd/common/config/keys/loader/putty/super-secret-passphrase-AES-256-CBC-ecdsa-sha2-nistp521-KeyPair.ppk
 
b/sshd-contrib/src/test/resources/org/apache/sshd/common/config/keys/loader/putty/super-secret-passphrase-AES-256-CBC-ecdsa-sha2-nistp521-KeyPair.ppk
new file mode 100644
index 0000000..97077fd
--- /dev/null
+++ 
b/sshd-contrib/src/test/resources/org/apache/sshd/common/config/keys/loader/putty/super-secret-passphrase-AES-256-CBC-ecdsa-sha2-nistp521-KeyPair.ppk
@@ -0,0 +1,12 @@
+PuTTY-User-Key-File-2: ecdsa-sha2-nistp521
+Encryption: aes256-cbc
+Comment: ecdsa-key-20170917
+Public-Lines: 4
+AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBADGM237T9rT
+zE++sOFDN0VWfYfojlQ8dYP82OlgA24Yh0ZpOsezBBiHtHfMHl9tWHmch1YKmH7B
+lOfqbOgcIhz9cwA2V7Nu3IUGqxZT18LOXEpcdyDSphJ6jsy1urqBLrOz4DF6Udyr
+rFV4OQELovf8YdUsM91YPfe1DfnSRi1I5v20uA==
+Private-Lines: 2
++44AQO4aflPquBZbdB3UtdLuXuHV2u1YoghxYXPFGdhskMt+XjJhUlrOHNX8rmgR
+E9nni474zGw9ni/3LIZwMILQI/xTfiQm3t6nKFV8nyI=
+Private-MAC: 99c25e348a84de4876163758ad13b2ad1dc43629

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/4aef497e/sshd-core/src/main/java/org/apache/sshd/common/cipher/ECCurves.java
----------------------------------------------------------------------
diff --git 
a/sshd-core/src/main/java/org/apache/sshd/common/cipher/ECCurves.java 
b/sshd-core/src/main/java/org/apache/sshd/common/cipher/ECCurves.java
index 083778b..93e420c 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/cipher/ECCurves.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/cipher/ECCurves.java
@@ -34,6 +34,7 @@ import java.util.Collections;
 import java.util.Comparator;
 import java.util.EnumSet;
 import java.util.List;
+import java.util.NavigableSet;
 import java.util.Objects;
 import java.util.Set;
 import java.util.stream.Collectors;
@@ -110,8 +111,8 @@ public enum ECCurves implements NamedResource, 
OptionalFeature {
     /**
      * A {@link Set} of all the known curves names
      */
-    public static final Set<String> NAMES =
-            Collections.unmodifiableSet(GenericUtils.mapSort(
+    public static final NavigableSet<String> NAMES =
+            Collections.unmodifiableNavigableSet(GenericUtils.mapSort(
                     VALUES,
                     ECCurves::getName,
                     String.CASE_INSENSITIVE_ORDER));
@@ -119,8 +120,8 @@ public enum ECCurves implements NamedResource, 
OptionalFeature {
     /**
      * A {@link Set} of all the known curves key types
      */
-    public static final Set<String> KEY_TYPES =
-            Collections.unmodifiableSet(GenericUtils.mapSort(
+    public static final NavigableSet<String> KEY_TYPES =
+            Collections.unmodifiableNavigableSet(GenericUtils.mapSort(
                     VALUES,
                     ECCurves::getKeyType,
                     String.CASE_INSENSITIVE_ORDER));

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/4aef497e/sshd-core/src/main/java/org/apache/sshd/common/config/keys/IdentityResourceLoader.java
----------------------------------------------------------------------
diff --git 
a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/IdentityResourceLoader.java
 
b/sshd-core/src/main/java/org/apache/sshd/common/config/keys/IdentityResourceLoader.java
new file mode 100644
index 0000000..d826821
--- /dev/null
+++ 
b/sshd-core/src/main/java/org/apache/sshd/common/config/keys/IdentityResourceLoader.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sshd.common.config.keys;
+
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.util.Collection;
+
+/**
+ * @param <PUB> Type of {@link PublicKey}
+ * @param <PRV> Type of {@link PrivateKey}
+ * @author <a href="mailto:d...@mina.apache.org";>Apache MINA SSHD Project</a>
+ */
+public interface IdentityResourceLoader<PUB extends PublicKey, PRV extends 
PrivateKey> {
+    /**
+     * @return The {@link Class} of the {@link PublicKey} that is the result
+     * of decoding
+     */
+    Class<PUB> getPublicKeyType();
+
+    /**
+     * @return The {@link Class} of the {@link PrivateKey} that matches the
+     * public one
+     */
+    Class<PRV> getPrivateKeyType();
+
+    /**
+     * @return The {@link Collection} of {@code OpenSSH} key type names that
+     * are supported by this decoder - e.g., ECDSA keys have several curve 
names.
+     * <B>Caveat:</B> this collection may be un-modifiable...
+     */
+    Collection<String> getSupportedTypeNames();
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/4aef497e/sshd-core/src/main/java/org/apache/sshd/common/config/keys/KeyEntryResolver.java
----------------------------------------------------------------------
diff --git 
a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/KeyEntryResolver.java
 
b/sshd-core/src/main/java/org/apache/sshd/common/config/keys/KeyEntryResolver.java
index 8cf8fa6..4bfbea0 100644
--- 
a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/KeyEntryResolver.java
+++ 
b/sshd-core/src/main/java/org/apache/sshd/common/config/keys/KeyEntryResolver.java
@@ -32,7 +32,6 @@ import java.security.KeyPair;
 import java.security.KeyPairGenerator;
 import java.security.PrivateKey;
 import java.security.PublicKey;
-import java.util.Collection;
 
 import org.apache.sshd.common.util.io.IoUtils;
 
@@ -41,26 +40,7 @@ import org.apache.sshd.common.util.io.IoUtils;
  * @param <PRV> Type of {@link PrivateKey}
  * @author <a href="mailto:d...@mina.apache.org";>Apache MINA SSHD Project</a>
  */
-public interface KeyEntryResolver<PUB extends PublicKey, PRV extends 
PrivateKey> {
-    /**
-     * @return The {@link Class} of the {@link PublicKey} that is the result
-     * of decoding
-     */
-    Class<PUB> getPublicKeyType();
-
-    /**
-     * @return The {@link Class} of the {@link PrivateKey} that matches the
-     * public one
-     */
-    Class<PRV> getPrivateKeyType();
-
-    /**
-     * @return The {@link Collection} of {@code OpenSSH} key type names that
-     * are supported by this decoder - e.g., ECDSA keys have several curve 
names.
-     * <B>Caveat:</B> this collection may be un-modifiable...
-     */
-    Collection<String> getSupportedTypeNames();
-
+public interface KeyEntryResolver<PUB extends PublicKey, PRV extends 
PrivateKey> extends IdentityResourceLoader<PUB, PRV> {
     /**
      * @param keySize Key size in bits
      * @return A {@link KeyPair} with the specified key size

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/4aef497e/sshd-core/src/main/java/org/apache/sshd/common/config/keys/impl/AbstractIdentityResourceLoader.java
----------------------------------------------------------------------
diff --git 
a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/impl/AbstractIdentityResourceLoader.java
 
b/sshd-core/src/main/java/org/apache/sshd/common/config/keys/impl/AbstractIdentityResourceLoader.java
new file mode 100644
index 0000000..fbe8d71
--- /dev/null
+++ 
b/sshd-core/src/main/java/org/apache/sshd/common/config/keys/impl/AbstractIdentityResourceLoader.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sshd.common.config.keys.impl;
+
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.util.Collection;
+import java.util.Objects;
+
+import org.apache.sshd.common.config.keys.IdentityResourceLoader;
+import org.apache.sshd.common.util.ValidateUtils;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
+
+/**
+ * TODO Add javadoc
+ *
+ * @author <a href="mailto:d...@mina.apache.org";>Apache MINA SSHD Project</a>
+ */
+public abstract class AbstractIdentityResourceLoader<PUB extends PublicKey, 
PRV extends PrivateKey>
+        extends AbstractLoggingBean
+        implements IdentityResourceLoader<PUB, PRV> {
+    private final Class<PUB> pubType;
+    private final Class<PRV> prvType;
+    private final Collection<String> names;
+
+    protected AbstractIdentityResourceLoader(Class<PUB> pubType, Class<PRV> 
prvType, Collection<String> names) {
+        this.pubType = Objects.requireNonNull(pubType, "No public key type 
specified");
+        this.prvType = Objects.requireNonNull(prvType, "No private key type 
specified");
+        this.names = ValidateUtils.checkNotNullAndNotEmpty(names, "No type 
names provided");
+    }
+
+    @Override
+    public final Class<PUB> getPublicKeyType() {
+        return pubType;
+    }
+
+    @Override
+    public final Class<PRV> getPrivateKeyType() {
+        return prvType;
+    }
+
+    @Override
+    public Collection<String> getSupportedTypeNames() {
+        return names;
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/4aef497e/sshd-core/src/main/java/org/apache/sshd/common/config/keys/impl/AbstractKeyEntryResolver.java
----------------------------------------------------------------------
diff --git 
a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/impl/AbstractKeyEntryResolver.java
 
b/sshd-core/src/main/java/org/apache/sshd/common/config/keys/impl/AbstractKeyEntryResolver.java
index e8a78f3..7afa3a6 100644
--- 
a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/impl/AbstractKeyEntryResolver.java
+++ 
b/sshd-core/src/main/java/org/apache/sshd/common/config/keys/impl/AbstractKeyEntryResolver.java
@@ -25,11 +25,8 @@ import java.security.PrivateKey;
 import java.security.PublicKey;
 import java.security.spec.KeySpec;
 import java.util.Collection;
-import java.util.Objects;
 
 import org.apache.sshd.common.config.keys.KeyEntryResolver;
-import org.apache.sshd.common.util.ValidateUtils;
-import org.apache.sshd.common.util.logging.AbstractLoggingBean;
 
 /**
  * @param <PUB> Type of {@link PublicKey}
@@ -37,31 +34,10 @@ import 
org.apache.sshd.common.util.logging.AbstractLoggingBean;
  * @author <a href="mailto:d...@mina.apache.org";>Apache MINA SSHD Project</a>
  */
 public abstract class AbstractKeyEntryResolver<PUB extends PublicKey, PRV 
extends PrivateKey>
-            extends AbstractLoggingBean
+            extends AbstractIdentityResourceLoader<PUB, PRV>
             implements KeyEntryResolver<PUB, PRV>  {
-    private final Class<PUB> pubType;
-    private final Class<PRV> prvType;
-    private final Collection<String> names;
-
     protected AbstractKeyEntryResolver(Class<PUB> pubType, Class<PRV> prvType, 
Collection<String> names) {
-        this.pubType = Objects.requireNonNull(pubType, "No public key type 
specified");
-        this.prvType = Objects.requireNonNull(prvType, "No private key type 
specified");
-        this.names = ValidateUtils.checkNotNullAndNotEmpty(names, "No type 
names provided");
-    }
-
-    @Override
-    public final Class<PUB> getPublicKeyType() {
-        return pubType;
-    }
-
-    @Override
-    public final Class<PRV> getPrivateKeyType() {
-        return prvType;
-    }
-
-    @Override
-    public Collection<String> getSupportedTypeNames() {
-        return names;
+        super(pubType, prvType, names);
     }
 
     public PUB generatePublicKey(KeySpec keySpec) throws 
GeneralSecurityException {

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/4aef497e/sshd-core/src/main/java/org/apache/sshd/common/config/keys/impl/ECDSAPublicKeyEntryDecoder.java
----------------------------------------------------------------------
diff --git 
a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/impl/ECDSAPublicKeyEntryDecoder.java
 
b/sshd-core/src/main/java/org/apache/sshd/common/config/keys/impl/ECDSAPublicKeyEntryDecoder.java
index e6d4652..397a007 100644
--- 
a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/impl/ECDSAPublicKeyEntryDecoder.java
+++ 
b/sshd-core/src/main/java/org/apache/sshd/common/config/keys/impl/ECDSAPublicKeyEntryDecoder.java
@@ -70,7 +70,6 @@ public class ECDSAPublicKeyEntryDecoder extends 
AbstractPublicKeyEntryDecoder<EC
         }
 
         String keyCurveName = curve.getName();
-        ECParameterSpec paramSpec = curve.getParameters();
         // see rfc5656 section 3.1
         String encCurveName = KeyEntryResolver.decodeString(keyData);
         if (!keyCurveName.equals(encCurveName)) {
@@ -92,6 +91,7 @@ public class ECDSAPublicKeyEntryDecoder extends 
AbstractPublicKeyEntryDecoder<EC
                     + ": " + e.getMessage());
         }
 
+        ECParameterSpec paramSpec = curve.getParameters();
         return generatePublicKey(new ECPublicKeySpec(w, paramSpec));
     }
 

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/4aef497e/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
index 7628ec9..b5ded29 100644
--- 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
@@ -34,6 +34,7 @@ import java.util.LinkedHashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.NavigableSet;
 import java.util.Objects;
 import java.util.Set;
 import java.util.SortedMap;
@@ -425,7 +426,7 @@ public final class GenericUtils {
         return stream(values).map(mapper).collect(Collectors.toList());
     }
 
-    public static <T, U> SortedSet<U> mapSort(
+    public static <T, U> NavigableSet<U> mapSort(
             Collection<T> values, Function<? super T, ? extends U> mapper, 
Comparator<U> comparator) {
         return stream(values).map(mapper).collect(toSortedSet(comparator));
     }
@@ -446,7 +447,7 @@ public final class GenericUtils {
         };
     }
 
-    public static <T> Collector<T, ?, SortedSet<T>> toSortedSet(Comparator<T> 
comparator) {
+    public static <T> Collector<T, ?, NavigableSet<T>> 
toSortedSet(Comparator<T> comparator) {
         return Collectors.toCollection(() -> new TreeSet<>(comparator));
     }
 

Reply via email to