You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by tw...@apache.org on 2025/09/06 19:58:50 UTC

(mina-sshd) 02/05: Remove generics from key decoders

This is an automated email from the ASF dual-hosted git repository.

twolf pushed a commit to branch dev_3.0
in repository https://gitbox.apache.org/repos/asf/mina-sshd.git

commit 2299ba8fd1c8de98ed18d77a715a3de73e46d523
Author: Thomas Wolf <tw...@apache.org>
AuthorDate: Thu Sep 4 22:09:25 2025 +0200

    Remove generics from key decoders
    
    These classes attempted to statically enforce matching private and
    public key classes via generics, but this never worked correctly. In
    particular it fails for method parameters, and as result we had to
    use unchecked conversions or raw types, and had to suppress warnings
    because of that.
    
    Moreover, this forces key classes (or interfaces) into the generic
    parameters of subclasses, which gives trouble with key types that don't
    exist on all Java versions supported (like ed25519).
    
    So remove these generics and just use PrivateKey and PublicKey. We can
    do so since we also removed any operations to get a decoder based on a
    concrete key class -- this is bad practice anyway, and using either the
    key algorithm or the SSH key type to figure out what kind of key a
    particular instance is.
---
 .../sshd/common/config/keys/BuiltinIdentities.java | 100 ++--------
 .../apache/sshd/common/config/keys/Identity.java   |   6 -
 .../common/config/keys/IdentityResourceLoader.java |  45 -----
 .../sshd/common/config/keys/IdentityUtils.java     |   5 +-
 .../sshd/common/config/keys/KeyEntryResolver.java  |  18 +-
 .../apache/sshd/common/config/keys/KeyUtils.java   |  26 +--
 .../common/config/keys/PrivateKeyEntryDecoder.java |  15 +-
 .../sshd/common/config/keys/PublicKeyEntry.java    |   4 +-
 .../common/config/keys/PublicKeyEntryDecoder.java  |  12 +-
 .../config/keys/PublicKeyRawDataDecoder.java       |  10 +-
 .../keys/impl/AbstractIdentityResourceLoader.java  |  25 +--
 .../config/keys/impl/AbstractKeyEntryResolver.java |  20 +-
 .../keys/impl/AbstractPrivateKeyEntryDecoder.java  |  14 +-
 .../keys/impl/AbstractPublicKeyEntryDecoder.java   |   8 +-
 .../config/keys/impl/DSSPublicKeyEntryDecoder.java |  14 +-
 .../keys/impl/ECDSAPublicKeyEntryDecoder.java      |  18 +-
 .../keys/impl/OpenSSHCertificateDecoder.java       |  28 +--
 .../config/keys/impl/RSAPublicKeyDecoder.java      |  23 ++-
 .../keys/impl/SkECDSAPublicKeyEntryDecoder.java    |  15 +-
 .../keys/impl/SkED25519PublicKeyEntryDecoder.java  |  12 +-
 .../openssh/OpenSSHDSSPrivateKeyEntryDecoder.java  |  21 ++-
 .../OpenSSHECDSAPrivateKeyEntryDecoder.java        |  18 +-
 .../openssh/OpenSSHKeyPairResourceParser.java      |  18 +-
 .../openssh/OpenSSHRSAPrivateKeyDecoder.java       |  18 +-
 .../loader/ssh2/Ssh2PublicKeyEntryDecoder.java     |   4 +-
 .../openssh/OpenSSHKeyPairResourceWriter.java      |  10 +-
 .../util/security/SecurityProviderRegistrar.java   |   2 +-
 .../sshd/common/util/security/SecurityUtils.java   |  48 ++---
 .../BouncyCastleSecurityProviderRegistrar.java     |   2 +-
 .../security/eddsa/Ed25519PublicKeyDecoder.java    |   5 +-
 .../eddsa/EdDSASecurityProviderRegistrar.java      |   2 +-
 .../security/eddsa/EdDSASecurityProviderUtils.java |   4 +-
 .../security/eddsa/NetI2pCryptoEdDSASupport.java   |  40 +---
 .../OpenSSHEd25519PrivateKeyEntryDecoder.java      |   6 +-
 .../bouncycastle/BouncyCastleEdDSASupport.java     |  44 +----
 .../util/security/eddsa/generic/EdDSASupport.java  |  56 +++---
 .../util/security/eddsa/generic/EdDSAUtils.java    | 201 +++++++++++++++++++++
 .../generic/GenericEd25519PublicKeyDecoder.java    |  14 +-
 ...enericOpenSSHEd25519PrivateKeyEntryDecoder.java |  18 +-
 .../common/config/keys/BuiltinIdentitiesTest.java  |   5 +
 .../keys/EcdsaPublicKeyEntryDecoderTest.java       |   4 +-
 .../OpenSSHKeyPairResourceParserDecodingTest.java  |   6 -
 .../util/security/eddsa/Ed25519VectorsTest.java    |  35 ++--
 .../common/signature/SignatureFactoriesTest.java   |  10 +-
 .../apache/sshd/putty/AbstractPuttyKeyDecoder.java |  10 +-
 .../org/apache/sshd/putty/DSSPuttyKeyDecoder.java  |   6 +-
 .../apache/sshd/putty/ECDSAPuttyKeyDecoder.java    |   6 +-
 .../apache/sshd/putty/EdDSAPuttyKeyDecoder.java    |   6 +-
 .../sshd/putty/PuttyKeyPairResourceParser.java     |   7 +-
 .../java/org/apache/sshd/putty/PuttyKeyUtils.java  |  10 +-
 .../org/apache/sshd/putty/RSAPuttyKeyDecoder.java  |   6 +-
 .../sshd/putty/AbstractPuttyTestSupport.java       |   4 +-
 .../org/apache/sshd/putty/PuttyKeyUtilsTest.java   |   4 +-
 53 files changed, 499 insertions(+), 569 deletions(-)

diff --git a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/BuiltinIdentities.java b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/BuiltinIdentities.java
index 7d1bdfd01..8c9afcf45 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/BuiltinIdentities.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/BuiltinIdentities.java
@@ -21,19 +21,10 @@ package org.apache.sshd.common.config.keys;
 
 import java.security.Key;
 import java.security.KeyPair;
-import java.security.PrivateKey;
-import java.security.PublicKey;
-import java.security.interfaces.DSAPrivateKey;
-import java.security.interfaces.DSAPublicKey;
-import java.security.interfaces.ECPrivateKey;
-import java.security.interfaces.ECPublicKey;
-import java.security.interfaces.RSAPrivateKey;
-import java.security.interfaces.RSAPublicKey;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.EnumSet;
 import java.util.NavigableSet;
-import java.util.Objects;
 import java.util.Set;
 import java.util.stream.Collectors;
 
@@ -49,14 +40,11 @@ import org.apache.sshd.common.util.security.SecurityUtils;
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
 public enum BuiltinIdentities implements Identity {
-    RSA(Constants.RSA, RSAPublicKey.class, RSAPrivateKey.class, KeyPairProvider.SSH_RSA),
-    DSA(Constants.DSA, DSAPublicKey.class, DSAPrivateKey.class, KeyPairProvider.SSH_DSS),
-    ECDSA(Constants.ECDSA, KeyUtils.EC_ALGORITHM, ECPublicKey.class, ECPrivateKey.class,
+    RSA(Constants.RSA, KeyPairProvider.SSH_RSA),
+    DSA(Constants.DSA, KeyPairProvider.SSH_DSS),
+    ECDSA(Constants.ECDSA, KeyUtils.EC_ALGORITHM,
           ECCurves.VALUES.stream().map(KeyTypeIndicator::getKeyType).collect(Collectors.toList())),
-    ED25119(Constants.ED25519, SecurityUtils.EDDSA,
-            SecurityUtils.getEDDSAPublicKeyType(),
-            SecurityUtils.getEDDSAPrivateKeyType(),
-            KeyPairProvider.SSH_ED25519) {
+    ED25119(Constants.ED25519, SecurityUtils.EDDSA, KeyPairProvider.SSH_ED25519) {
         @Override
         public boolean isSupported() {
             return SecurityUtils.isEDDSACurveSupported();
@@ -74,31 +62,22 @@ public enum BuiltinIdentities implements Identity {
 
     private final String name;
     private final String algorithm;
-    private final Class<? extends PublicKey> pubType;
-    private final Class<? extends PrivateKey> prvType;
     private final NavigableSet<String> types;
 
-    BuiltinIdentities(String type, Class<? extends PublicKey> pubType, Class<? extends PrivateKey> prvType, String keyType) {
-        this(type, type, pubType, prvType, keyType);
+    BuiltinIdentities(String type, String keyType) {
+        this(type, type, keyType);
     }
 
-    BuiltinIdentities(String name, String algorithm,
-                      Class<? extends PublicKey> pubType,
-                      Class<? extends PrivateKey> prvType,
-                      String keyType) {
-        this(name, algorithm, pubType, prvType,
+    BuiltinIdentities(String name, String algorithm, String keyType) {
+        this(name, algorithm,
              Collections.singletonList(
                      ValidateUtils.checkNotNullAndNotEmpty(keyType, "No key type specified")));
     }
 
     BuiltinIdentities(String name, String algorithm,
-                      Class<? extends PublicKey> pubType,
-                      Class<? extends PrivateKey> prvType,
                       Collection<String> keyTypes) {
         this.name = name.toLowerCase();
         this.algorithm = algorithm.toUpperCase();
-        this.pubType = pubType;
-        this.prvType = prvType;
         this.types = Collections.unmodifiableNavigableSet(
                 GenericUtils.asSortedSet(String.CASE_INSENSITIVE_ORDER,
                         ValidateUtils.checkNotNullAndNotEmpty(keyTypes, "No key type names provided")));
@@ -124,16 +103,6 @@ public enum BuiltinIdentities implements Identity {
         return algorithm;
     }
 
-    @Override
-    public final Class<? extends PublicKey> getPublicKeyType() {
-        return pubType;
-    }
-
-    @Override
-    public final Class<? extends PrivateKey> getPrivateKeyType() {
-        return prvType;
-    }
-
     /**
      * @param  name The identity name - ignored if {@code null}/empty
      * @return      The matching {@link BuiltinIdentities} whose {@link #getName()} value matches case
@@ -164,7 +133,7 @@ public enum BuiltinIdentities implements Identity {
 
     /**
      * @param  kp The {@link KeyPair} - ignored if {@code null}
-     * @return    The matching {@link BuiltinIdentities} provided <U>both</U> public and public keys are of the same
+     * @return    The matching {@link BuiltinIdentities} provided <U>both</U> public and private keys are of the same
      *            type - {@code null} if no match could be found
      * @see       #fromKey(Key)
      */
@@ -172,14 +141,7 @@ public enum BuiltinIdentities implements Identity {
         if (kp == null) {
             return null;
         }
-
-        BuiltinIdentities i1 = fromKey(kp.getPublic());
-        BuiltinIdentities i2 = fromKey(kp.getPrivate());
-        if (Objects.equals(i1, i2)) {
-            return i1;
-        } else {
-            return null; // some kind of mixed keys...
-        }
+        return fromKeyType(KeyUtils.getKeyType(kp));
     }
 
     /**
@@ -189,48 +151,14 @@ public enum BuiltinIdentities implements Identity {
      * @see        #fromKeyType(Class)
      */
     public static BuiltinIdentities fromKey(Key key) {
-        return fromKeyType((key == null) ? null : key.getClass());
-    }
-
-    /**
-     * @param  clazz The key type - ignored if {@code null} or not a {@link Key} class
-     * @return       The matching {@link BuiltinIdentities} whose either public or private key type matches the
-     *               requested one or {@code null} if no match found
-     * @see          #getPublicKeyType()
-     * @see          #getPrivateKeyType()
-     */
-    public static BuiltinIdentities fromKeyType(Class<?> clazz) {
-        if ((clazz == null) || (!Key.class.isAssignableFrom(clazz))) {
+        if (key == null) {
             return null;
         }
-
-        for (BuiltinIdentities id : VALUES) {
-            Class<?> pubType = id.getPublicKeyType();
-            Class<?> prvType = id.getPrivateKeyType();
-            // Ignore placeholder classes (e.g., if ed25519 is not supported)
-            if ((prvType == null) || (pubType == null)) {
-                continue;
-            }
-            if ((prvType == PrivateKey.class) || (pubType == PublicKey.class)) {
-                continue;
-            }
-            if (pubType.isAssignableFrom(clazz) || prvType.isAssignableFrom(clazz)) {
-                return id;
-            }
-        }
-
-        return null;
+        return fromKeyType(KeyUtils.getKeyType(key));
     }
 
-    /**
-     * @param  typeName The {@code OpenSSH} key type e.g., {@code ssh-rsa, ssh-dss, ecdsa-sha2-nistp384}. Ignored if
-     *                  {@code null}/empty.
-     * @return          The {@link BuiltinIdentities} that reported the type name as its {@link #getSupportedKeyTypes()}
-     *                  (case <U>insensitive</U>) - {@code null} if no match found
-     * @see             KeyTypeNamesSupport#findSupporterByKeyTypeName(String, Collection)
-     */
-    public static BuiltinIdentities fromKeyTypeName(String typeName) {
-        return KeyTypeNamesSupport.findSupporterByKeyTypeName(typeName, VALUES);
+    private static BuiltinIdentities fromKeyType(String type) {
+        return VALUES.stream().filter(b -> b.getSupportedKeyTypes().contains(type)).findFirst().orElse(null);
     }
 
     /**
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/Identity.java b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/Identity.java
index cc805101d..48377e87f 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/Identity.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/Identity.java
@@ -19,9 +19,6 @@
 
 package org.apache.sshd.common.config.keys;
 
-import java.security.PrivateKey;
-import java.security.PublicKey;
-
 import org.apache.sshd.common.AlgorithmNameProvider;
 import org.apache.sshd.common.NamedResource;
 import org.apache.sshd.common.OptionalFeature;
@@ -37,7 +34,4 @@ public interface Identity
         NamedResource,
         OptionalFeature,
         KeyTypeNamesSupport {
-    Class<? extends PublicKey> getPublicKeyType();
-
-    Class<? extends PrivateKey> getPrivateKeyType();
 }
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/IdentityResourceLoader.java b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/IdentityResourceLoader.java
deleted file mode 100644
index 026c69be7..000000000
--- a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/IdentityResourceLoader.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.sshd.common.config.keys;
-
-import java.math.BigInteger;
-import java.security.PrivateKey;
-import java.security.PublicKey;
-
-/**
- * @param  <PUB> Type of {@link PublicKey}
- * @param  <PRV> Type of {@link PrivateKey}
- * @author       <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public interface IdentityResourceLoader<PUB extends PublicKey, PRV extends PrivateKey> extends KeyTypeNamesSupport {
-    /**
-     * A reasonable max. number of octets used for a {@link BigInteger} in the context of keys based on such numbers
-     */
-    int MAX_BIGINT_OCTETS_COUNT = Short.MAX_VALUE;
-
-    /**
-     * @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();
-}
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/IdentityUtils.java b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/IdentityUtils.java
index f727165c4..5948e9da6 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/IdentityUtils.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/IdentityUtils.java
@@ -79,9 +79,6 @@ public final class IdentityUtils {
         Map<String, KeyPair> pairsMap = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
         ids.forEach((type, kp) -> {
             BuiltinIdentities id = BuiltinIdentities.fromName(type);
-            if (id == null) {
-                id = BuiltinIdentities.fromKeyPair(kp);
-            }
 
             if (supportedOnly && ((id == null) || (!id.isSupported()))) {
                 return;
@@ -144,7 +141,7 @@ public final class IdentityUtils {
 
             for (KeyPair kp : pairs) {
                 KeyPair prev = ids.put(type, kp);
-                ValidateUtils.checkTrue(prev == null, "Multiple keys for type=%s due to %s", type, path);
+                ValidateUtils.checkTrue(prev == null, "Multiple keys for type=%s in %s", type, path);
             }
         }
 
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/KeyEntryResolver.java b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/KeyEntryResolver.java
index 87bb58431..fb1dc74f4 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/KeyEntryResolver.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/KeyEntryResolver.java
@@ -30,8 +30,6 @@ import java.security.GeneralSecurityException;
 import java.security.KeyFactory;
 import java.security.KeyPair;
 import java.security.KeyPairGenerator;
-import java.security.PrivateKey;
-import java.security.PublicKey;
 import java.util.AbstractMap.SimpleImmutableEntry;
 import java.util.Map;
 
@@ -39,12 +37,16 @@ import org.apache.sshd.common.util.NumberUtils;
 import org.apache.sshd.common.util.io.IoUtils;
 
 /**
- * @param  <PUB> Type of {@link PublicKey}
- * @param  <PRV> Type of {@link PrivateKey}
- * @author       <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
-public interface KeyEntryResolver<PUB extends PublicKey, PRV extends PrivateKey>
-        extends IdentityResourceLoader<PUB, PRV> {
+public interface KeyEntryResolver extends KeyTypeNamesSupport {
+
+    /**
+     * A reasonable max. number of octets used for a {@link java.math.BigInteger} in the context of keys based on such
+     * numbers
+     */
+    int MAX_BIGINT_OCTETS_COUNT = Short.MAX_VALUE;
+
     /**
      * @param  keySize                  Key size in bits
      * @return                          A {@link KeyPair} with the specified key size
@@ -119,7 +121,7 @@ public interface KeyEntryResolver<PUB extends PublicKey, PRV extends PrivateKey>
     }
 
     static BigInteger decodeBigInt(InputStream s) throws IOException {
-        return new BigInteger(readRLEBytes(s, IdentityResourceLoader.MAX_BIGINT_OCTETS_COUNT));
+        return new BigInteger(readRLEBytes(s, MAX_BIGINT_OCTETS_COUNT));
     }
 
     static byte[] readRLEBytes(InputStream s, int maxAllowed) throws IOException {
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/KeyUtils.java b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/KeyUtils.java
index 2babf02b7..4ff385c73 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/KeyUtils.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/KeyUtils.java
@@ -140,7 +140,7 @@ public final class KeyUtils {
 
     private static final AtomicReference<DigestFactory> DEFAULT_DIGEST_HOLDER = new AtomicReference<>();
 
-    private static final Map<String, PublicKeyEntryDecoder<?, ?>> BY_KEY_TYPE_DECODERS_MAP
+    private static final Map<String, PublicKeyEntryDecoder> BY_KEY_TYPE_DECODERS_MAP
             = new ConcurrentHashMap<>();
 
     private static final Map<String, String> KEY_TYPE_ALIASES
@@ -342,7 +342,7 @@ public final class KeyUtils {
      * @see                             PublicKeyEntryDecoder<?, ?>#generateKeyPair(int)
      */
     public static KeyPair generateKeyPair(String keyType, int keySize) throws GeneralSecurityException {
-        PublicKeyEntryDecoder<?, ?> decoder = getPublicKeyEntryDecoder(keyType);
+        PublicKeyEntryDecoder decoder = getPublicKeyEntryDecoder(keyType);
         if (decoder == null) {
             throw new InvalidKeySpecException("No decoder for key type=" + keyType);
         }
@@ -354,9 +354,9 @@ public final class KeyUtils {
      * Registers the specified decoder for all the types it {@link PublicKeyEntryDecoder<?, ?>#getSupportedKeyTypes()
      * supports}
      *
-     * @param decoder The (never {@code null}) {@link PublicKeyEntryDecoder<?, ?> decoder} to register
+     * @param decoder The (never {@code null}) {@link PublicKeyEntryDecoder decoder} to register
      */
-    public static void registerPublicKeyEntryDecoder(PublicKeyEntryDecoder<?, ?> decoder) {
+    public static void registerPublicKeyEntryDecoder(PublicKeyEntryDecoder decoder) {
         Objects.requireNonNull(decoder, "No decoder specified");
 
         Collection<String> names
@@ -374,14 +374,14 @@ public final class KeyUtils {
      *                 {@link PublicKeyEntryDecoder<?, ?>#getSupportedKeyTypes() supported} ones.
      * @see            #unregisterPublicKeyEntryDecoderForKeyType(String)
      */
-    public static Set<String> unregisterPublicKeyEntryDecoder(PublicKeyEntryDecoder<?, ?> decoder) {
+    public static Set<String> unregisterPublicKeyEntryDecoder(PublicKeyEntryDecoder decoder) {
         Objects.requireNonNull(decoder, "No decoder specified");
 
         Collection<String> names = ValidateUtils.checkNotNullAndNotEmpty(
                 decoder.getSupportedKeyTypes(), "No supported key types");
         Set<String> removed = new HashSet<>();
         for (String n : names) {
-            PublicKeyEntryDecoder<?, ?> prev = unregisterPublicKeyEntryDecoderForKeyType(n);
+            PublicKeyEntryDecoder prev = unregisterPublicKeyEntryDecoderForKeyType(n);
             if (prev != null) {
                 removed.add(n);
             }
@@ -396,7 +396,7 @@ public final class KeyUtils {
      * @return         The unregistered {@link PublicKeyEntryDecoder<?, ?>} - {@code null} if none registered for this
      *                 key type
      */
-    public static PublicKeyEntryDecoder<?, ?> unregisterPublicKeyEntryDecoderForKeyType(String keyType) {
+    public static PublicKeyEntryDecoder unregisterPublicKeyEntryDecoderForKeyType(String keyType) {
         keyType = ValidateUtils.checkNotNullAndNotEmpty(keyType, "No key type specified");
         return BY_KEY_TYPE_DECODERS_MAP.remove(keyType);
     }
@@ -406,7 +406,7 @@ public final class KeyUtils {
      *                 {@code null}/empty
      * @return         The registered {@link PublicKeyEntryDecoder<?, ?>} or {code null} if not found
      */
-    public static PublicKeyEntryDecoder<?, ?> getPublicKeyEntryDecoder(String keyType) {
+    public static PublicKeyEntryDecoder getPublicKeyEntryDecoder(String keyType) {
         if (GenericUtils.isEmpty(keyType)) {
             return null;
         }
@@ -419,13 +419,13 @@ public final class KeyUtils {
      *            the same decoder - {@code null} if no match found
      * @see       #getPublicKeyEntryDecoder(Key)
      */
-    public static PublicKeyEntryDecoder<?, ?> getPublicKeyEntryDecoder(KeyPair kp) {
+    public static PublicKeyEntryDecoder getPublicKeyEntryDecoder(KeyPair kp) {
         if (kp == null) {
             return null;
         }
 
-        PublicKeyEntryDecoder<?, ?> d1 = getPublicKeyEntryDecoder(kp.getPublic());
-        PublicKeyEntryDecoder<?, ?> d2 = getPublicKeyEntryDecoder(kp.getPrivate());
+        PublicKeyEntryDecoder d1 = getPublicKeyEntryDecoder(kp.getPublic());
+        PublicKeyEntryDecoder d2 = getPublicKeyEntryDecoder(kp.getPrivate());
         if (d1 == d2) {
             return d1;
         } else {
@@ -435,9 +435,9 @@ public final class KeyUtils {
 
     /**
      * @param  key The {@link Key} (public or private) - ignored if {@code null}
-     * @return     The registered {@link PublicKeyEntryDecoder<?, ?>} for this key or {code null} if no match found
+     * @return     The registered {@link PublicKeyEntryDecoder} for this key or {code null} if no match found
      */
-    public static PublicKeyEntryDecoder<?, ?> getPublicKeyEntryDecoder(Key key) {
+    public static PublicKeyEntryDecoder getPublicKeyEntryDecoder(Key key) {
         if (key == null) {
             return null;
         }
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/PrivateKeyEntryDecoder.java b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/PrivateKeyEntryDecoder.java
index c66272099..3d5571323 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/PrivateKeyEntryDecoder.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/PrivateKeyEntryDecoder.java
@@ -42,8 +42,7 @@ import org.apache.sshd.common.util.io.output.SecureByteArrayOutputStream;
  * @param  <PRV> Type of {@link PrivateKey}
  * @author       <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
-public interface PrivateKeyEntryDecoder<PUB extends PublicKey, PRV extends PrivateKey>
-        extends KeyEntryResolver<PUB, PRV>, PrivateKeyEntryResolver {
+public interface PrivateKeyEntryDecoder extends KeyEntryResolver, PrivateKeyEntryResolver {
 
     @Override
     default PrivateKey resolve(
@@ -69,13 +68,13 @@ public interface PrivateKeyEntryDecoder<PUB extends PublicKey, PRV extends Priva
      * @throws IOException              If failed to decode the key
      * @throws GeneralSecurityException If failed to generate the key
      */
-    default PRV decodePrivateKey(
+    default PrivateKey decodePrivateKey(
             SessionContext session, FilePasswordProvider passwordProvider, byte... keyData)
             throws IOException, GeneralSecurityException {
         return decodePrivateKey(session, passwordProvider, keyData, 0, NumberUtils.length(keyData));
     }
 
-    default PRV decodePrivateKey(
+    default PrivateKey decodePrivateKey(
             SessionContext session, FilePasswordProvider passwordProvider, byte[] keyData, int offset, int length)
             throws IOException, GeneralSecurityException {
         if (length <= 0) {
@@ -87,7 +86,7 @@ public interface PrivateKeyEntryDecoder<PUB extends PublicKey, PRV extends Priva
         }
     }
 
-    default PRV decodePrivateKey(
+    default PrivateKey decodePrivateKey(
             SessionContext session, FilePasswordProvider passwordProvider, InputStream keyData)
             throws IOException, GeneralSecurityException {
         // the actual data is preceded by a string that repeats the key type
@@ -116,7 +115,7 @@ public interface PrivateKeyEntryDecoder<PUB extends PublicKey, PRV extends Priva
      * @throws IOException              If failed to read from the data stream
      * @throws GeneralSecurityException If failed to generate the key
      */
-    PRV decodePrivateKey(
+    PrivateKey decodePrivateKey(
             SessionContext session, String keyType, FilePasswordProvider passwordProvider, InputStream keyData)
             throws IOException, GeneralSecurityException;
 
@@ -132,7 +131,7 @@ public interface PrivateKeyEntryDecoder<PUB extends PublicKey, PRV extends Priva
      *                     not supported
      * @throws IOException If failed to generate the encoding
      */
-    default String encodePrivateKey(SecureByteArrayOutputStream s, PRV key, PUB pubKey) throws IOException {
+    default String encodePrivateKey(SecureByteArrayOutputStream s, PrivateKey key, PublicKey pubKey) throws IOException {
         Objects.requireNonNull(key, "No private key provided");
         return null;
     }
@@ -148,7 +147,7 @@ public interface PrivateKeyEntryDecoder<PUB extends PublicKey, PRV extends Priva
      * @return                          The recovered {@link PublicKey} - {@code null} if cannot recover it
      * @throws GeneralSecurityException If failed to generate the public key
      */
-    default PUB recoverPublicKey(PRV prvKey) throws GeneralSecurityException {
+    default PublicKey recoverPublicKey(PrivateKey prvKey) throws GeneralSecurityException {
         return null;
     }
 }
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/PublicKeyEntry.java b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/PublicKeyEntry.java
index f8345c07b..6acb57fa7 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/PublicKeyEntry.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/PublicKeyEntry.java
@@ -507,9 +507,7 @@ public class PublicKeyEntry implements Serializable, KeyTypeIndicator {
             keyType = unsupported.getKeyType();
             bytes = unsupported.getKeyData();
         } else {
-            @SuppressWarnings("unchecked")
-            PublicKeyEntryDecoder<PublicKey, ?> decoder = (PublicKeyEntryDecoder<PublicKey, ?>) KeyUtils
-                    .getPublicKeyEntryDecoder(key);
+            PublicKeyEntryDecoder decoder = KeyUtils.getPublicKeyEntryDecoder(key);
             if (decoder == null) {
                 throw new StreamCorruptedException("Cannot retrieve decoder for key=" + key.getAlgorithm());
             }
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/PublicKeyEntryDecoder.java b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/PublicKeyEntryDecoder.java
index ca1fdfc14..c77162b8f 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/PublicKeyEntryDecoder.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/PublicKeyEntryDecoder.java
@@ -24,7 +24,6 @@ import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.StreamCorruptedException;
 import java.security.GeneralSecurityException;
-import java.security.PrivateKey;
 import java.security.PublicKey;
 import java.security.spec.InvalidKeySpecException;
 import java.util.Collection;
@@ -38,12 +37,9 @@ import org.apache.sshd.common.util.ValidateUtils;
 /**
  * Represents a decoder of an {@code OpenSSH} encoded key data
  *
- * @param  <PUB> Type of {@link PublicKey}
- * @param  <PRV> Type of {@link PrivateKey}
- * @author       <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
-public interface PublicKeyEntryDecoder<PUB extends PublicKey, PRV extends PrivateKey>
-        extends KeyEntryResolver<PUB, PRV>, PublicKeyRawDataDecoder<PUB>, PublicKeyEntryResolver {
+public interface PublicKeyEntryDecoder extends KeyEntryResolver, PublicKeyRawDataDecoder, PublicKeyEntryResolver {
 
     @Override
     default PublicKey resolve(
@@ -59,7 +55,7 @@ public interface PublicKeyEntryDecoder<PUB extends PublicKey, PRV extends Privat
     }
 
     @Override
-    default PUB decodePublicKeyByType(
+    default PublicKey decodePublicKeyByType(
             SessionContext session, String keyType, InputStream keyData, Map<String, String> headers)
             throws IOException, GeneralSecurityException {
         // the actual data is preceded by a string that repeats the key type
@@ -85,5 +81,5 @@ public interface PublicKeyEntryDecoder<PUB extends PublicKey, PRV extends Privat
      * @return             The key type value - one of the {@link #getSupportedKeyTypes()}
      * @throws IOException If failed to generate the encoding
      */
-    String encodePublicKey(OutputStream s, PUB key) throws IOException;
+    String encodePublicKey(OutputStream s, PublicKey key) throws IOException;
 }
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/PublicKeyRawDataDecoder.java b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/PublicKeyRawDataDecoder.java
index 6f154096b..345b086b4 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/PublicKeyRawDataDecoder.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/PublicKeyRawDataDecoder.java
@@ -33,7 +33,7 @@ import org.apache.sshd.common.util.NumberUtils;
  * @param  <PUB> Generic {@link PublicKey} type
  * @author       <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
-public interface PublicKeyRawDataDecoder<PUB extends PublicKey> {
+public interface PublicKeyRawDataDecoder {
     /**
      * @param  session                  The {@link SessionContext} for invoking this command - may be {@code null} if
      *                                  not invoked within a session context (e.g., offline tool or session unknown).
@@ -45,13 +45,13 @@ public interface PublicKeyRawDataDecoder<PUB extends PublicKey> {
      * @throws IOException              If failed to decode the key
      * @throws GeneralSecurityException If failed to generate the key
      */
-    default PUB decodePublicKey(
+    default PublicKey decodePublicKey(
             SessionContext session, String keyType, byte[] keyData, Map<String, String> headers)
             throws IOException, GeneralSecurityException {
         return decodePublicKey(session, keyType, keyData, 0, NumberUtils.length(keyData), headers);
     }
 
-    default PUB decodePublicKey(
+    default PublicKey decodePublicKey(
             SessionContext session, String keyType, byte[] keyData, int offset, int length, Map<String, String> headers)
             throws IOException, GeneralSecurityException {
         if (length <= 0) {
@@ -63,7 +63,7 @@ public interface PublicKeyRawDataDecoder<PUB extends PublicKey> {
         }
     }
 
-    PUB decodePublicKeyByType(
+    PublicKey decodePublicKeyByType(
             SessionContext session, String keyType, InputStream keyData, Map<String, String> headers)
             throws IOException, GeneralSecurityException;
 
@@ -78,6 +78,6 @@ public interface PublicKeyRawDataDecoder<PUB extends PublicKey> {
      * @throws IOException              If failed to read from the data stream
      * @throws GeneralSecurityException If failed to generate the key
      */
-    PUB decodePublicKey(SessionContext session, String keyType, InputStream keyData, Map<String, String> headers)
+    PublicKey decodePublicKey(SessionContext session, String keyType, InputStream keyData, Map<String, String> headers)
             throws IOException, GeneralSecurityException;
 }
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/impl/AbstractIdentityResourceLoader.java b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/impl/AbstractIdentityResourceLoader.java
index 6739551a2..5207f97c4 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/impl/AbstractIdentityResourceLoader.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/impl/AbstractIdentityResourceLoader.java
@@ -18,14 +18,11 @@
  */
 package org.apache.sshd.common.config.keys.impl;
 
-import java.security.PrivateKey;
-import java.security.PublicKey;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.NavigableSet;
-import java.util.Objects;
 
-import org.apache.sshd.common.config.keys.IdentityResourceLoader;
+import org.apache.sshd.common.config.keys.KeyTypeNamesSupport;
 import org.apache.sshd.common.util.GenericUtils;
 import org.apache.sshd.common.util.ValidateUtils;
 import org.apache.sshd.common.util.logging.AbstractLoggingBean;
@@ -35,31 +32,17 @@ import org.apache.sshd.common.util.logging.AbstractLoggingBean;
  * @param  <PRV> Generic private key type
  * @author       <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
-public abstract class AbstractIdentityResourceLoader<PUB extends PublicKey, PRV extends PrivateKey>
+public abstract class AbstractIdentityResourceLoader
         extends AbstractLoggingBean
-        implements IdentityResourceLoader<PUB, PRV> {
-    private final Class<PUB> pubType;
-    private final Class<PRV> prvType;
+        implements KeyTypeNamesSupport {
     private final NavigableSet<String> types;
 
-    protected AbstractIdentityResourceLoader(Class<PUB> pubType, Class<PRV> prvType, Collection<String> keyTypes) {
-        this.pubType = Objects.requireNonNull(pubType, "No public key type specified");
-        this.prvType = Objects.requireNonNull(prvType, "No private key type specified");
+    protected AbstractIdentityResourceLoader(Collection<String> keyTypes) {
         this.types = Collections.unmodifiableNavigableSet(
                 GenericUtils.asSortedSet(String.CASE_INSENSITIVE_ORDER,
                         ValidateUtils.checkNotNullAndNotEmpty(keyTypes, "No key type names provided")));
     }
 
-    @Override
-    public final Class<PUB> getPublicKeyType() {
-        return pubType;
-    }
-
-    @Override
-    public final Class<PRV> getPrivateKeyType() {
-        return prvType;
-    }
-
     @Override
     public NavigableSet<String> getSupportedKeyTypes() {
         return types;
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/impl/AbstractKeyEntryResolver.java b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/impl/AbstractKeyEntryResolver.java
index d7c88a631..7d14e6b8b 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/impl/AbstractKeyEntryResolver.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/impl/AbstractKeyEntryResolver.java
@@ -33,27 +33,23 @@ import org.apache.sshd.common.config.keys.KeyEntryResolver;
  * @param  <PRV> Type of {@link PrivateKey}
  * @author       <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
-public abstract class AbstractKeyEntryResolver<PUB extends PublicKey, PRV extends PrivateKey>
-        extends AbstractIdentityResourceLoader<PUB, PRV>
-        implements KeyEntryResolver<PUB, PRV> {
-    protected AbstractKeyEntryResolver(Class<PUB> pubType, Class<PRV> prvType, Collection<String> names) {
-        super(pubType, prvType, names);
+public abstract class AbstractKeyEntryResolver extends AbstractIdentityResourceLoader implements KeyEntryResolver {
+    protected AbstractKeyEntryResolver(Collection<String> names) {
+        super(names);
     }
 
-    public PUB generatePublicKey(KeySpec keySpec) throws GeneralSecurityException {
+    public PublicKey generatePublicKey(KeySpec keySpec) throws GeneralSecurityException {
         KeyFactory factory = getKeyFactoryInstance();
-        Class<PUB> keyType = getPublicKeyType();
-        return keyType.cast(factory.generatePublic(keySpec));
+        return factory.generatePublic(keySpec);
     }
 
-    public PRV generatePrivateKey(KeySpec keySpec) throws GeneralSecurityException {
+    public PrivateKey generatePrivateKey(KeySpec keySpec) throws GeneralSecurityException {
         KeyFactory factory = getKeyFactoryInstance();
-        Class<PRV> keyType = getPrivateKeyType();
-        return keyType.cast(factory.generatePrivate(keySpec));
+        return factory.generatePrivate(keySpec);
     }
 
     @Override
     public String toString() {
-        return getPublicKeyType().getSimpleName() + ": " + getSupportedKeyTypes();
+        return getSupportedKeyTypes().toString();
     }
 }
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/impl/AbstractPrivateKeyEntryDecoder.java b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/impl/AbstractPrivateKeyEntryDecoder.java
index 00157884a..bf6b8bc7e 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/impl/AbstractPrivateKeyEntryDecoder.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/impl/AbstractPrivateKeyEntryDecoder.java
@@ -19,21 +19,15 @@
 
 package org.apache.sshd.common.config.keys.impl;
 
-import java.security.PrivateKey;
-import java.security.PublicKey;
 import java.util.Collection;
 
 import org.apache.sshd.common.config.keys.PrivateKeyEntryDecoder;
 
 /**
- * @param  <PUB> Type of {@link PublicKey}
- * @param  <PRV> Type of {@link PrivateKey}
- * @author       <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
-public abstract class AbstractPrivateKeyEntryDecoder<PUB extends PublicKey, PRV extends PrivateKey>
-        extends AbstractKeyEntryResolver<PUB, PRV>
-        implements PrivateKeyEntryDecoder<PUB, PRV> {
-    protected AbstractPrivateKeyEntryDecoder(Class<PUB> pubType, Class<PRV> prvType, Collection<String> names) {
-        super(pubType, prvType, names);
+public abstract class AbstractPrivateKeyEntryDecoder extends AbstractKeyEntryResolver implements PrivateKeyEntryDecoder {
+    protected AbstractPrivateKeyEntryDecoder(Collection<String> names) {
+        super(names);
     }
 }
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/impl/AbstractPublicKeyEntryDecoder.java b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/impl/AbstractPublicKeyEntryDecoder.java
index 71bbe8b3e..cf9cde054 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/impl/AbstractPublicKeyEntryDecoder.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/impl/AbstractPublicKeyEntryDecoder.java
@@ -35,11 +35,9 @@ import org.apache.sshd.common.util.MapEntryUtils;
  * @param  <PRV> Type of {@link PrivateKey}
  * @author       <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
-public abstract class AbstractPublicKeyEntryDecoder<PUB extends PublicKey, PRV extends PrivateKey>
-        extends AbstractKeyEntryResolver<PUB, PRV>
-        implements PublicKeyEntryDecoder<PUB, PRV> {
-    protected AbstractPublicKeyEntryDecoder(Class<PUB> pubType, Class<PRV> prvType, Collection<String> names) {
-        super(pubType, prvType, names);
+public abstract class AbstractPublicKeyEntryDecoder extends AbstractKeyEntryResolver implements PublicKeyEntryDecoder {
+    protected AbstractPublicKeyEntryDecoder(Collection<String> names) {
+        super(names);
     }
 
     protected final boolean parseBooleanHeader(Map<String, String> headers, String propertyKey, boolean defaultVal) {
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/impl/DSSPublicKeyEntryDecoder.java b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/impl/DSSPublicKeyEntryDecoder.java
index b91b50722..3962a5fd5 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/impl/DSSPublicKeyEntryDecoder.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/impl/DSSPublicKeyEntryDecoder.java
@@ -26,8 +26,8 @@ import java.math.BigInteger;
 import java.security.GeneralSecurityException;
 import java.security.KeyFactory;
 import java.security.KeyPairGenerator;
+import java.security.PublicKey;
 import java.security.interfaces.DSAParams;
-import java.security.interfaces.DSAPrivateKey;
 import java.security.interfaces.DSAPublicKey;
 import java.security.spec.DSAPublicKeySpec;
 import java.security.spec.InvalidKeySpecException;
@@ -39,21 +39,21 @@ import org.apache.sshd.common.config.keys.KeyEntryResolver;
 import org.apache.sshd.common.config.keys.KeyUtils;
 import org.apache.sshd.common.keyprovider.KeyPairProvider;
 import org.apache.sshd.common.session.SessionContext;
+import org.apache.sshd.common.util.ValidateUtils;
 import org.apache.sshd.common.util.security.SecurityUtils;
 
 /**
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
-public class DSSPublicKeyEntryDecoder extends AbstractPublicKeyEntryDecoder<DSAPublicKey, DSAPrivateKey> {
+public class DSSPublicKeyEntryDecoder extends AbstractPublicKeyEntryDecoder {
     public static final DSSPublicKeyEntryDecoder INSTANCE = new DSSPublicKeyEntryDecoder();
 
     public DSSPublicKeyEntryDecoder() {
-        super(DSAPublicKey.class, DSAPrivateKey.class,
-              Collections.unmodifiableList(Collections.singletonList(KeyPairProvider.SSH_DSS)));
+        super(Collections.unmodifiableList(Collections.singletonList(KeyPairProvider.SSH_DSS)));
     }
 
     @Override
-    public DSAPublicKey decodePublicKey(
+    public PublicKey decodePublicKey(
             SessionContext session, String keyType, InputStream keyData, Map<String, String> headers)
             throws IOException, GeneralSecurityException {
         if (!KeyPairProvider.SSH_DSS.equals(keyType)) { // just in case we were invoked directly
@@ -69,8 +69,8 @@ public class DSSPublicKeyEntryDecoder extends AbstractPublicKeyEntryDecoder<DSAP
     }
 
     @Override
-    public String encodePublicKey(OutputStream s, DSAPublicKey key) throws IOException {
-        Objects.requireNonNull(key, "No public key provided");
+    public String encodePublicKey(OutputStream s, PublicKey k) throws IOException {
+        DSAPublicKey key = ValidateUtils.checkInstanceOf(k, DSAPublicKey.class, "Key must be a DSAPublicKey");
 
         DSAParams keyParams = Objects.requireNonNull(key.getParams(), "No DSA params available");
         KeyEntryResolver.encodeString(s, KeyPairProvider.SSH_DSS);
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/impl/ECDSAPublicKeyEntryDecoder.java b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/impl/ECDSAPublicKeyEntryDecoder.java
index aab561584..24c572470 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/impl/ECDSAPublicKeyEntryDecoder.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/impl/ECDSAPublicKeyEntryDecoder.java
@@ -26,7 +26,7 @@ import java.security.GeneralSecurityException;
 import java.security.KeyFactory;
 import java.security.KeyPair;
 import java.security.KeyPairGenerator;
-import java.security.interfaces.ECPrivateKey;
+import java.security.PublicKey;
 import java.security.interfaces.ECPublicKey;
 import java.security.spec.ECParameterSpec;
 import java.security.spec.ECPoint;
@@ -36,18 +36,18 @@ import java.util.Map;
 import java.util.Objects;
 
 import org.apache.sshd.common.cipher.ECCurves;
-import org.apache.sshd.common.config.keys.IdentityResourceLoader;
 import org.apache.sshd.common.config.keys.KeyEntryResolver;
 import org.apache.sshd.common.config.keys.KeyUtils;
 import org.apache.sshd.common.session.SessionContext;
+import org.apache.sshd.common.util.ValidateUtils;
 import org.apache.sshd.common.util.buffer.BufferUtils;
 import org.apache.sshd.common.util.security.SecurityUtils;
 
 /**
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
-public class ECDSAPublicKeyEntryDecoder extends AbstractPublicKeyEntryDecoder<ECPublicKey, ECPrivateKey> {
-    public static final int MAX_ALLOWED_POINT_SIZE = IdentityResourceLoader.MAX_BIGINT_OCTETS_COUNT;
+public class ECDSAPublicKeyEntryDecoder extends AbstractPublicKeyEntryDecoder {
+    public static final int MAX_ALLOWED_POINT_SIZE = KeyEntryResolver.MAX_BIGINT_OCTETS_COUNT;
     public static final int MAX_CURVE_NAME_LENGTH = 1024;
 
     public static final ECDSAPublicKeyEntryDecoder INSTANCE = new ECDSAPublicKeyEntryDecoder();
@@ -58,11 +58,11 @@ public class ECDSAPublicKeyEntryDecoder extends AbstractPublicKeyEntryDecoder<EC
     public static final byte ECPOINT_COMPRESSED_VARIANT_3 = 0x02;
 
     public ECDSAPublicKeyEntryDecoder() {
-        super(ECPublicKey.class, ECPrivateKey.class, ECCurves.KEY_TYPES);
+        super(ECCurves.KEY_TYPES);
     }
 
     @Override
-    public ECPublicKey decodePublicKey(
+    public PublicKey decodePublicKey(
             SessionContext session, String keyType, InputStream keyData, Map<String, String> headers)
             throws IOException, GeneralSecurityException {
         ECCurves curve = ECCurves.fromKeyType(keyType);
@@ -73,7 +73,7 @@ public class ECDSAPublicKeyEntryDecoder extends AbstractPublicKeyEntryDecoder<EC
         return decodePublicKey(curve, keyData);
     }
 
-    ECPublicKey decodePublicKey(ECCurves curve, InputStream keyData) throws IOException, GeneralSecurityException {
+    PublicKey decodePublicKey(ECCurves curve, InputStream keyData) throws IOException, GeneralSecurityException {
         String keyCurveName = curve.getName();
         // see rfc5656 section 3.1
         String encCurveName = KeyEntryResolver.decodeString(keyData, MAX_CURVE_NAME_LENGTH);
@@ -101,8 +101,8 @@ public class ECDSAPublicKeyEntryDecoder extends AbstractPublicKeyEntryDecoder<EC
     }
 
     @Override
-    public String encodePublicKey(OutputStream s, ECPublicKey key) throws IOException {
-        Objects.requireNonNull(key, "No public key provided");
+    public String encodePublicKey(OutputStream s, PublicKey k) throws IOException {
+        ECPublicKey key = ValidateUtils.checkInstanceOf(k, ECPublicKey.class, "Key must be an ECPublicKey");
 
         ECParameterSpec params = Objects.requireNonNull(key.getParams(), "No EC parameters available");
         ECCurves curve = Objects.requireNonNull(ECCurves.fromCurveParameters(params), "Cannot determine curve");
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/impl/OpenSSHCertificateDecoder.java b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/impl/OpenSSHCertificateDecoder.java
index 8556d1537..25b2bc1cb 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/impl/OpenSSHCertificateDecoder.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/impl/OpenSSHCertificateDecoder.java
@@ -26,7 +26,7 @@ import java.security.GeneralSecurityException;
 import java.security.KeyFactory;
 import java.security.KeyPair;
 import java.security.KeyPairGenerator;
-import java.security.PrivateKey;
+import java.security.PublicKey;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Map;
@@ -36,6 +36,7 @@ import org.apache.sshd.common.config.keys.KeyUtils;
 import org.apache.sshd.common.config.keys.OpenSshCertificate;
 import org.apache.sshd.common.keyprovider.KeyPairProvider;
 import org.apache.sshd.common.session.SessionContext;
+import org.apache.sshd.common.util.ValidateUtils;
 import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
 import org.apache.sshd.common.util.buffer.keys.OpenSSHCertPublicKeyParser;
 import org.apache.sshd.common.util.io.IoUtils;
@@ -43,20 +44,19 @@ import org.apache.sshd.common.util.io.IoUtils;
 /**
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
-public class OpenSSHCertificateDecoder extends AbstractPublicKeyEntryDecoder<OpenSshCertificate, PrivateKey> {
+public class OpenSSHCertificateDecoder extends AbstractPublicKeyEntryDecoder {
     public static final OpenSSHCertificateDecoder INSTANCE = new OpenSSHCertificateDecoder();
 
     public OpenSSHCertificateDecoder() {
-        super(OpenSshCertificate.class, PrivateKey.class,
-              Collections.unmodifiableList(Arrays.asList(
-                      KeyUtils.RSA_SHA256_CERT_TYPE_ALIAS,
-                      KeyUtils.RSA_SHA512_CERT_TYPE_ALIAS,
-                      KeyPairProvider.SSH_RSA_CERT,
-                      KeyPairProvider.SSH_DSS_CERT,
-                      KeyPairProvider.SSH_ED25519_CERT,
-                      KeyPairProvider.SSH_ECDSA_SHA2_NISTP256_CERT,
-                      KeyPairProvider.SSH_ECDSA_SHA2_NISTP384_CERT,
-                      KeyPairProvider.SSH_ECDSA_SHA2_NISTP521_CERT)));
+        super(Collections.unmodifiableList(Arrays.asList(
+                KeyUtils.RSA_SHA256_CERT_TYPE_ALIAS,
+                KeyUtils.RSA_SHA512_CERT_TYPE_ALIAS,
+                KeyPairProvider.SSH_RSA_CERT,
+                KeyPairProvider.SSH_DSS_CERT,
+                KeyPairProvider.SSH_ED25519_CERT,
+                KeyPairProvider.SSH_ECDSA_SHA2_NISTP256_CERT,
+                KeyPairProvider.SSH_ECDSA_SHA2_NISTP384_CERT,
+                KeyPairProvider.SSH_ECDSA_SHA2_NISTP521_CERT)));
     }
 
     @Override
@@ -76,7 +76,9 @@ public class OpenSSHCertificateDecoder extends AbstractPublicKeyEntryDecoder<Ope
     }
 
     @Override
-    public String encodePublicKey(OutputStream s, OpenSshCertificate key) throws IOException {
+    public String encodePublicKey(OutputStream s, PublicKey k) throws IOException {
+        OpenSshCertificate key = ValidateUtils.checkInstanceOf(k, OpenSshCertificate.class,
+                "Key must be an OpenSshCertificate");
         Objects.requireNonNull(key, "No public key provided");
 
         ByteArrayBuffer buffer = new ByteArrayBuffer();
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/impl/RSAPublicKeyDecoder.java b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/impl/RSAPublicKeyDecoder.java
index 55ea87436..3a694ba46 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/impl/RSAPublicKeyDecoder.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/impl/RSAPublicKeyDecoder.java
@@ -26,38 +26,37 @@ import java.math.BigInteger;
 import java.security.GeneralSecurityException;
 import java.security.KeyFactory;
 import java.security.KeyPairGenerator;
-import java.security.interfaces.RSAPrivateKey;
+import java.security.PublicKey;
 import java.security.interfaces.RSAPublicKey;
 import java.security.spec.InvalidKeySpecException;
 import java.security.spec.RSAPublicKeySpec;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Map;
-import java.util.Objects;
 
 import org.apache.sshd.common.config.keys.KeyEntryResolver;
 import org.apache.sshd.common.config.keys.KeyUtils;
 import org.apache.sshd.common.keyprovider.KeyPairProvider;
 import org.apache.sshd.common.session.SessionContext;
+import org.apache.sshd.common.util.ValidateUtils;
 import org.apache.sshd.common.util.security.SecurityUtils;
 
 /**
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
-public class RSAPublicKeyDecoder extends AbstractPublicKeyEntryDecoder<RSAPublicKey, RSAPrivateKey> {
+public class RSAPublicKeyDecoder extends AbstractPublicKeyEntryDecoder {
     public static final RSAPublicKeyDecoder INSTANCE = new RSAPublicKeyDecoder();
 
     public RSAPublicKeyDecoder() {
-        super(RSAPublicKey.class, RSAPrivateKey.class,
-              Collections.unmodifiableList(
-                      Arrays.asList(KeyPairProvider.SSH_RSA,
-                              // Not really required, but allow it
-                              KeyUtils.RSA_SHA256_KEY_TYPE_ALIAS,
-                              KeyUtils.RSA_SHA512_KEY_TYPE_ALIAS)));
+        super(Collections.unmodifiableList(
+                Arrays.asList(KeyPairProvider.SSH_RSA,
+                        // Not really required, but allow it
+                        KeyUtils.RSA_SHA256_KEY_TYPE_ALIAS,
+                        KeyUtils.RSA_SHA512_KEY_TYPE_ALIAS)));
     }
 
     @Override
-    public RSAPublicKey decodePublicKey(
+    public PublicKey decodePublicKey(
             SessionContext session, String keyType, InputStream keyData, Map<String, String> headers)
             throws IOException, GeneralSecurityException {
         // Not really required, but allow it
@@ -73,8 +72,8 @@ public class RSAPublicKeyDecoder extends AbstractPublicKeyEntryDecoder<RSAPublic
     }
 
     @Override
-    public String encodePublicKey(OutputStream s, RSAPublicKey key) throws IOException {
-        Objects.requireNonNull(key, "No public key provided");
+    public String encodePublicKey(OutputStream s, PublicKey k) throws IOException {
+        RSAPublicKey key = ValidateUtils.checkInstanceOf(k, RSAPublicKey.class, "Key must be a RSAPublicKey");
         KeyEntryResolver.encodeString(s, KeyPairProvider.SSH_RSA);
         KeyEntryResolver.encodeBigInt(s, key.getPublicExponent());
         KeyEntryResolver.encodeBigInt(s, key.getModulus());
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/impl/SkECDSAPublicKeyEntryDecoder.java b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/impl/SkECDSAPublicKeyEntryDecoder.java
index 5e2dbda57..f43a7a9ca 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/impl/SkECDSAPublicKeyEntryDecoder.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/impl/SkECDSAPublicKeyEntryDecoder.java
@@ -26,22 +26,22 @@ import java.security.GeneralSecurityException;
 import java.security.KeyFactory;
 import java.security.KeyPair;
 import java.security.KeyPairGenerator;
-import java.security.PrivateKey;
+import java.security.PublicKey;
 import java.security.interfaces.ECPublicKey;
 import java.security.spec.InvalidKeySpecException;
 import java.util.Collections;
 import java.util.Map;
-import java.util.Objects;
 
 import org.apache.sshd.common.cipher.ECCurves;
 import org.apache.sshd.common.config.keys.KeyEntryResolver;
 import org.apache.sshd.common.config.keys.u2f.SkEcdsaPublicKey;
 import org.apache.sshd.common.session.SessionContext;
+import org.apache.sshd.common.util.ValidateUtils;
 
 /**
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
-public class SkECDSAPublicKeyEntryDecoder extends AbstractPublicKeyEntryDecoder<SkEcdsaPublicKey, PrivateKey> {
+public class SkECDSAPublicKeyEntryDecoder extends AbstractPublicKeyEntryDecoder {
     public static final String KEY_TYPE = "sk-ecdsa-sha2-nistp256@openssh.com";
     public static final int MAX_APP_NAME_LENGTH = 1024;
 
@@ -51,7 +51,7 @@ public class SkECDSAPublicKeyEntryDecoder extends AbstractPublicKeyEntryDecoder<
     private static final String VERIFY_REQUIRED_HEADER = "verify-required";
 
     public SkECDSAPublicKeyEntryDecoder() {
-        super(SkEcdsaPublicKey.class, PrivateKey.class, Collections.singleton(KEY_TYPE));
+        super(Collections.singleton(KEY_TYPE));
     }
 
     @Override
@@ -64,14 +64,15 @@ public class SkECDSAPublicKeyEntryDecoder extends AbstractPublicKeyEntryDecoder<
 
         boolean noTouchRequired = parseBooleanHeader(headers, NO_TOUCH_REQUIRED_HEADER, false);
         boolean verifyRequired = parseBooleanHeader(headers, VERIFY_REQUIRED_HEADER, false);
-        ECPublicKey ecPublicKey = ECDSAPublicKeyEntryDecoder.INSTANCE.decodePublicKey(ECCurves.nistp256, keyData);
+        PublicKey pk = ECDSAPublicKeyEntryDecoder.INSTANCE.decodePublicKey(ECCurves.nistp256, keyData);
+        ECPublicKey ecPublicKey = ValidateUtils.checkInstanceOf(pk, ECPublicKey.class, "Key must be an ECPublicKey");
         String appName = KeyEntryResolver.decodeString(keyData, MAX_APP_NAME_LENGTH);
         return new SkEcdsaPublicKey(appName, noTouchRequired, verifyRequired, ecPublicKey);
     }
 
     @Override
-    public String encodePublicKey(OutputStream s, SkEcdsaPublicKey key) throws IOException {
-        Objects.requireNonNull(key, "No public key provided");
+    public String encodePublicKey(OutputStream s, PublicKey k) throws IOException {
+        SkEcdsaPublicKey key = ValidateUtils.checkInstanceOf(k, SkEcdsaPublicKey.class, "Key must be an SkEcdsaPublicKey");
         ECDSAPublicKeyEntryDecoder.encodePublicKey(s, KEY_TYPE, ECCurves.nistp256, key.getDelegatePublicKey().getW());
         KeyEntryResolver.encodeString(s, key.getAppName());
         return KEY_TYPE;
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/impl/SkED25519PublicKeyEntryDecoder.java b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/impl/SkED25519PublicKeyEntryDecoder.java
index 6fa4e22f0..b80d644d2 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/impl/SkED25519PublicKeyEntryDecoder.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/impl/SkED25519PublicKeyEntryDecoder.java
@@ -27,24 +27,23 @@ import java.security.InvalidKeyException;
 import java.security.KeyFactory;
 import java.security.KeyPair;
 import java.security.KeyPairGenerator;
-import java.security.PrivateKey;
 import java.security.PublicKey;
 import java.security.spec.InvalidKeySpecException;
 import java.util.Collections;
 import java.util.Map;
-import java.util.Objects;
 
 import org.apache.sshd.common.config.keys.KeyEntryResolver;
 import org.apache.sshd.common.config.keys.u2f.SkED25519PublicKey;
 import org.apache.sshd.common.keyprovider.KeyPairProvider;
 import org.apache.sshd.common.session.SessionContext;
+import org.apache.sshd.common.util.ValidateUtils;
 import org.apache.sshd.common.util.security.SecurityUtils;
 import org.apache.sshd.common.util.security.eddsa.generic.EdDSAUtils;
 
 /**
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
-public class SkED25519PublicKeyEntryDecoder extends AbstractPublicKeyEntryDecoder<SkED25519PublicKey, PrivateKey> {
+public class SkED25519PublicKeyEntryDecoder extends AbstractPublicKeyEntryDecoder {
     public static final String KEY_TYPE = "sk-ssh-ed25519@openssh.com";
     public static final int MAX_APP_NAME_LENGTH = 1024;
 
@@ -54,7 +53,7 @@ public class SkED25519PublicKeyEntryDecoder extends AbstractPublicKeyEntryDecode
     private static final String VERIFY_REQUIRED_HEADER = "verify-required";
 
     public SkED25519PublicKeyEntryDecoder() {
-        super(SkED25519PublicKey.class, PrivateKey.class, Collections.singleton(KEY_TYPE));
+        super(Collections.singleton(KEY_TYPE));
     }
 
     @Override
@@ -74,8 +73,9 @@ public class SkED25519PublicKeyEntryDecoder extends AbstractPublicKeyEntryDecode
     }
 
     @Override
-    public String encodePublicKey(OutputStream s, SkED25519PublicKey key) throws IOException {
-        Objects.requireNonNull(key, "No public key provided");
+    public String encodePublicKey(OutputStream s, PublicKey k) throws IOException {
+        SkED25519PublicKey key = ValidateUtils.checkInstanceOf(k, SkED25519PublicKey.class,
+                "Key must be an SkED25519PublicKey");
         KeyEntryResolver.encodeString(s, KEY_TYPE);
         try {
             byte[] keyData = EdDSAUtils.getBytes(key.getDelegatePublicKey());
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHDSSPrivateKeyEntryDecoder.java b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHDSSPrivateKeyEntryDecoder.java
index a821846cb..ad1d202ab 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHDSSPrivateKeyEntryDecoder.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHDSSPrivateKeyEntryDecoder.java
@@ -25,6 +25,8 @@ import java.math.BigInteger;
 import java.security.GeneralSecurityException;
 import java.security.KeyFactory;
 import java.security.KeyPairGenerator;
+import java.security.PrivateKey;
+import java.security.PublicKey;
 import java.security.interfaces.DSAParams;
 import java.security.interfaces.DSAPrivateKey;
 import java.security.interfaces.DSAPublicKey;
@@ -39,22 +41,22 @@ import org.apache.sshd.common.config.keys.KeyUtils;
 import org.apache.sshd.common.config.keys.impl.AbstractPrivateKeyEntryDecoder;
 import org.apache.sshd.common.keyprovider.KeyPairProvider;
 import org.apache.sshd.common.session.SessionContext;
+import org.apache.sshd.common.util.ValidateUtils;
 import org.apache.sshd.common.util.io.output.SecureByteArrayOutputStream;
 import org.apache.sshd.common.util.security.SecurityUtils;
 
 /**
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
-public class OpenSSHDSSPrivateKeyEntryDecoder extends AbstractPrivateKeyEntryDecoder<DSAPublicKey, DSAPrivateKey> {
+public class OpenSSHDSSPrivateKeyEntryDecoder extends AbstractPrivateKeyEntryDecoder {
     public static final OpenSSHDSSPrivateKeyEntryDecoder INSTANCE = new OpenSSHDSSPrivateKeyEntryDecoder();
 
     public OpenSSHDSSPrivateKeyEntryDecoder() {
-        super(DSAPublicKey.class, DSAPrivateKey.class,
-              Collections.unmodifiableList(Collections.singletonList(KeyPairProvider.SSH_DSS)));
+        super(Collections.unmodifiableList(Collections.singletonList(KeyPairProvider.SSH_DSS)));
     }
 
     @Override
-    public DSAPrivateKey decodePrivateKey(
+    public PrivateKey decodePrivateKey(
             SessionContext session, String keyType, FilePasswordProvider passwordProvider, InputStream keyData)
             throws IOException, GeneralSecurityException {
         if (!KeyPairProvider.SSH_DSS.equals(keyType)) { // just in case we were invoked directly
@@ -72,7 +74,11 @@ public class OpenSSHDSSPrivateKeyEntryDecoder extends AbstractPrivateKeyEntryDec
     }
 
     @Override
-    public String encodePrivateKey(SecureByteArrayOutputStream s, DSAPrivateKey key, DSAPublicKey pubKey) throws IOException {
+    public String encodePrivateKey(SecureByteArrayOutputStream s, PrivateKey k, PublicKey pk) throws IOException {
+        DSAPrivateKey key = ValidateUtils.checkInstanceOf(k, DSAPrivateKey.class, "Key must be a DSAPrivateKey");
+        DSAPublicKey pubKey = pk == null
+                ? null
+                : ValidateUtils.checkInstanceOf(pk, DSAPublicKey.class, "Key must be a DSAPublicKey");
         Objects.requireNonNull(key, "No private key provided");
 
         DSAParams keyParams = Objects.requireNonNull(key.getParams(), "No DSA params available");
@@ -96,8 +102,9 @@ public class OpenSSHDSSPrivateKeyEntryDecoder extends AbstractPrivateKeyEntryDec
     }
 
     @Override
-    public DSAPublicKey recoverPublicKey(DSAPrivateKey privateKey) throws GeneralSecurityException {
-        return KeyUtils.recoverDSAPublicKey(privateKey);
+    public PublicKey recoverPublicKey(PrivateKey k) throws GeneralSecurityException {
+        DSAPrivateKey key = ValidateUtils.checkInstanceOf(k, DSAPrivateKey.class, "Key must be a DSAPrivateKey");
+        return KeyUtils.recoverDSAPublicKey(key);
     }
 
     @Override
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHECDSAPrivateKeyEntryDecoder.java b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHECDSAPrivateKeyEntryDecoder.java
index cb659cd32..82259e3a1 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHECDSAPrivateKeyEntryDecoder.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHECDSAPrivateKeyEntryDecoder.java
@@ -27,6 +27,8 @@ import java.security.InvalidKeyException;
 import java.security.KeyFactory;
 import java.security.KeyPair;
 import java.security.KeyPairGenerator;
+import java.security.PrivateKey;
+import java.security.PublicKey;
 import java.security.interfaces.ECPrivateKey;
 import java.security.interfaces.ECPublicKey;
 import java.security.spec.ECParameterSpec;
@@ -41,21 +43,22 @@ import org.apache.sshd.common.config.keys.KeyUtils;
 import org.apache.sshd.common.config.keys.impl.AbstractPrivateKeyEntryDecoder;
 import org.apache.sshd.common.config.keys.impl.ECDSAPublicKeyEntryDecoder;
 import org.apache.sshd.common.session.SessionContext;
+import org.apache.sshd.common.util.ValidateUtils;
 import org.apache.sshd.common.util.io.output.SecureByteArrayOutputStream;
 import org.apache.sshd.common.util.security.SecurityUtils;
 
 /**
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
-public class OpenSSHECDSAPrivateKeyEntryDecoder extends AbstractPrivateKeyEntryDecoder<ECPublicKey, ECPrivateKey> {
+public class OpenSSHECDSAPrivateKeyEntryDecoder extends AbstractPrivateKeyEntryDecoder {
     public static final OpenSSHECDSAPrivateKeyEntryDecoder INSTANCE = new OpenSSHECDSAPrivateKeyEntryDecoder();
 
     public OpenSSHECDSAPrivateKeyEntryDecoder() {
-        super(ECPublicKey.class, ECPrivateKey.class, ECCurves.KEY_TYPES);
+        super(ECCurves.KEY_TYPES);
     }
 
     @Override
-    public ECPrivateKey decodePrivateKey(
+    public PrivateKey decodePrivateKey(
             SessionContext session, String keyType, FilePasswordProvider passwordProvider, InputStream keyData)
             throws IOException, GeneralSecurityException {
         ECCurves curve = ECCurves.fromKeyType(keyType);
@@ -79,9 +82,9 @@ public class OpenSSHECDSAPrivateKeyEntryDecoder extends AbstractPrivateKeyEntryD
     }
 
     @Override
-    public String encodePrivateKey(SecureByteArrayOutputStream s, ECPrivateKey key, ECPublicKey pubKey) throws IOException {
-        Objects.requireNonNull(key, "No private key provided");
-        Objects.requireNonNull(pubKey, "No public key provided");
+    public String encodePrivateKey(SecureByteArrayOutputStream s, PrivateKey k, PublicKey pk) throws IOException {
+        ECPrivateKey key = ValidateUtils.checkInstanceOf(k, ECPrivateKey.class, "Key must be an ECPrivateKey");
+        ECPublicKey pubKey = ValidateUtils.checkInstanceOf(pk, ECPublicKey.class, "Key must be an ECPublicKey");
         ECCurves curve = ECCurves.fromECKey(key);
         if (curve == null) {
             return null;
@@ -95,7 +98,8 @@ public class OpenSSHECDSAPrivateKeyEntryDecoder extends AbstractPrivateKeyEntryD
     }
 
     @Override
-    public ECPublicKey recoverPublicKey(ECPrivateKey prvKey) throws GeneralSecurityException {
+    public PublicKey recoverPublicKey(PrivateKey key) throws GeneralSecurityException {
+        ECPrivateKey prvKey = ValidateUtils.checkInstanceOf(key, ECPrivateKey.class, "Key must be an ECPrivateKey");
         ECCurves curve = ECCurves.fromECKey(prvKey);
         if (curve == null) {
             throw new InvalidKeyException("Unknown curve");
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParser.java b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParser.java
index 107849cfd..5c2f77811 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParser.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParser.java
@@ -79,7 +79,7 @@ public class OpenSSHKeyPairResourceParser extends AbstractKeyPairResourceParser
     public static final OpenSSHKeyPairResourceParser INSTANCE = new OpenSSHKeyPairResourceParser();
 
     private static final byte[] AUTH_MAGIC_BYTES = AUTH_MAGIC.getBytes(StandardCharsets.UTF_8);
-    private static final Map<String, PrivateKeyEntryDecoder<?, ?>> BY_KEY_TYPE_DECODERS_MAP
+    private static final Map<String, PrivateKeyEntryDecoder> BY_KEY_TYPE_DECODERS_MAP
             = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
 
     static {
@@ -212,7 +212,7 @@ public class OpenSSHKeyPairResourceParser extends AbstractKeyPairResourceParser
         byte[] keyData = KeyEntryResolver.readRLEBytes(stream, MAX_PUBLIC_KEY_DATA_SIZE);
         try (InputStream bais = new ByteArrayInputStream(keyData)) {
             String keyType = KeyEntryResolver.decodeString(bais, MAX_KEY_TYPE_NAME_LENGTH);
-            PublicKeyEntryDecoder<?, ?> decoder = KeyUtils.getPublicKeyEntryDecoder(keyType);
+            PublicKeyEntryDecoder decoder = KeyUtils.getPublicKeyEntryDecoder(keyType);
             if (decoder == null) {
                 throw new NoSuchAlgorithmException("Unsupported key type (" + keyType + ") in " + resourceKey);
             }
@@ -295,7 +295,7 @@ public class OpenSSHKeyPairResourceParser extends AbstractKeyPairResourceParser
                                                + " in " + resourceKey);
         }
 
-        PrivateKeyEntryDecoder<?, ?> decoder = getPrivateKeyEntryDecoder(prvType);
+        PrivateKeyEntryDecoder decoder = getPrivateKeyEntryDecoder(prvType);
         if (decoder == null) {
             throw new NoSuchAlgorithmException("Unsupported key type (" + prvType + ") in " + resourceKey);
         }
@@ -338,7 +338,7 @@ public class OpenSSHKeyPairResourceParser extends AbstractKeyPairResourceParser
      * @see                             PrivateKeyEntryDecoder#getPublicKeyType()
      * @see                             PrivateKeyEntryDecoder#getSupportedKeyTypes()
      */
-    public static void registerPrivateKeyEntryDecoder(PrivateKeyEntryDecoder<?, ?> decoder) {
+    public static void registerPrivateKeyEntryDecoder(PrivateKeyEntryDecoder decoder) {
         Objects.requireNonNull(decoder, "No decoder specified");
 
         Collection<String> names
@@ -355,7 +355,7 @@ public class OpenSSHKeyPairResourceParser extends AbstractKeyPairResourceParser
      *                 {@code null}/empty
      * @return         The registered {@link PrivateKeyEntryDecoder} or {code null} if not found
      */
-    public static PrivateKeyEntryDecoder<?, ?> getPrivateKeyEntryDecoder(String keyType) {
+    public static PrivateKeyEntryDecoder getPrivateKeyEntryDecoder(String keyType) {
         if (GenericUtils.isEmpty(keyType)) {
             return null;
         }
@@ -371,13 +371,13 @@ public class OpenSSHKeyPairResourceParser extends AbstractKeyPairResourceParser
      *            same decoder - {@code null} if no match found
      * @see       #getPrivateKeyEntryDecoder(Key)
      */
-    public static PrivateKeyEntryDecoder<?, ?> getPrivateKeyEntryDecoder(KeyPair kp) {
+    public static PrivateKeyEntryDecoder getPrivateKeyEntryDecoder(KeyPair kp) {
         if (kp == null) {
             return null;
         }
 
-        PrivateKeyEntryDecoder<?, ?> d1 = getPrivateKeyEntryDecoder(kp.getPublic());
-        PrivateKeyEntryDecoder<?, ?> d2 = getPrivateKeyEntryDecoder(kp.getPrivate());
+        PrivateKeyEntryDecoder d1 = getPrivateKeyEntryDecoder(kp.getPublic());
+        PrivateKeyEntryDecoder d2 = getPrivateKeyEntryDecoder(kp.getPrivate());
         if (d1 == d2) {
             return d1;
         } else {
@@ -389,7 +389,7 @@ public class OpenSSHKeyPairResourceParser extends AbstractKeyPairResourceParser
      * @param  key The {@link Key} (public or private) - ignored if {@code null}
      * @return     The registered {@link PrivateKeyEntryDecoder} for this key or {code null} if no match found
      */
-    public static PrivateKeyEntryDecoder<?, ?> getPrivateKeyEntryDecoder(Key key) {
+    public static PrivateKeyEntryDecoder getPrivateKeyEntryDecoder(Key key) {
         if (key == null) {
             return null;
         } else {
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHRSAPrivateKeyDecoder.java b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHRSAPrivateKeyDecoder.java
index b149217df..f5b14fe89 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHRSAPrivateKeyDecoder.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHRSAPrivateKeyDecoder.java
@@ -25,9 +25,10 @@ import java.math.BigInteger;
 import java.security.GeneralSecurityException;
 import java.security.KeyFactory;
 import java.security.KeyPairGenerator;
+import java.security.PrivateKey;
+import java.security.PublicKey;
 import java.security.interfaces.RSAPrivateCrtKey;
 import java.security.interfaces.RSAPrivateKey;
-import java.security.interfaces.RSAPublicKey;
 import java.security.spec.InvalidKeySpecException;
 import java.security.spec.RSAPrivateCrtKeySpec;
 import java.util.Collections;
@@ -39,23 +40,23 @@ import org.apache.sshd.common.config.keys.KeyUtils;
 import org.apache.sshd.common.config.keys.impl.AbstractPrivateKeyEntryDecoder;
 import org.apache.sshd.common.keyprovider.KeyPairProvider;
 import org.apache.sshd.common.session.SessionContext;
+import org.apache.sshd.common.util.ValidateUtils;
 import org.apache.sshd.common.util.io.output.SecureByteArrayOutputStream;
 import org.apache.sshd.common.util.security.SecurityUtils;
 
 /**
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
-public class OpenSSHRSAPrivateKeyDecoder extends AbstractPrivateKeyEntryDecoder<RSAPublicKey, RSAPrivateKey> {
+public class OpenSSHRSAPrivateKeyDecoder extends AbstractPrivateKeyEntryDecoder {
     public static final BigInteger DEFAULT_PUBLIC_EXPONENT = KeyUtils.DEFAULT_RSA_PUBLIC_EXPONENT;
     public static final OpenSSHRSAPrivateKeyDecoder INSTANCE = new OpenSSHRSAPrivateKeyDecoder();
 
     public OpenSSHRSAPrivateKeyDecoder() {
-        super(RSAPublicKey.class, RSAPrivateKey.class,
-              Collections.unmodifiableList(Collections.singletonList(KeyPairProvider.SSH_RSA)));
+        super(Collections.unmodifiableList(Collections.singletonList(KeyPairProvider.SSH_RSA)));
     }
 
     @Override
-    public RSAPrivateKey decodePrivateKey(
+    public PrivateKey decodePrivateKey(
             SessionContext session, String keyType, FilePasswordProvider passwordProvider, InputStream keyData)
             throws IOException, GeneralSecurityException {
         if (!KeyPairProvider.SSH_RSA.equals(keyType)) { // just in case we were invoked directly
@@ -82,7 +83,7 @@ public class OpenSSHRSAPrivateKeyDecoder extends AbstractPrivateKeyEntryDecoder<
     }
 
     @Override
-    public String encodePrivateKey(SecureByteArrayOutputStream s, RSAPrivateKey key, RSAPublicKey pubKey) throws IOException {
+    public String encodePrivateKey(SecureByteArrayOutputStream s, PrivateKey key, PublicKey pubKey) throws IOException {
         Objects.requireNonNull(key, "No private key provided");
         if (key instanceof RSAPrivateCrtKey) {
             RSAPrivateCrtKey a = (RSAPrivateCrtKey) key;
@@ -104,8 +105,9 @@ public class OpenSSHRSAPrivateKeyDecoder extends AbstractPrivateKeyEntryDecoder<
     }
 
     @Override
-    public RSAPublicKey recoverPublicKey(RSAPrivateKey privateKey) throws GeneralSecurityException {
-        return KeyUtils.recoverRSAPublicKey(privateKey);
+    public PublicKey recoverPublicKey(PrivateKey k) throws GeneralSecurityException {
+        RSAPrivateKey key = ValidateUtils.checkInstanceOf(k, RSAPrivateKey.class, "Key must be a RSAPrivateKey");
+        return KeyUtils.recoverRSAPublicKey(key);
     }
 
     @Override
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/ssh2/Ssh2PublicKeyEntryDecoder.java b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/ssh2/Ssh2PublicKeyEntryDecoder.java
index 082f16ddf..43ad6743c 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/ssh2/Ssh2PublicKeyEntryDecoder.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/ssh2/Ssh2PublicKeyEntryDecoder.java
@@ -56,7 +56,7 @@ import org.apache.sshd.common.util.ValidateUtils;
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
 public class Ssh2PublicKeyEntryDecoder
-        implements PublicKeyRawDataDecoder<PublicKey>, PublicKeyEntryResolver,
+        implements PublicKeyRawDataDecoder, PublicKeyEntryResolver,
         PublicKeyRawDataReader<PublicKey>, KeyTypeNamesSupport {
     public static final NavigableSet<String> SUPPORTED_KEY_TYPES = Collections.unmodifiableNavigableSet(
             GenericUtils.asSortedSet(String.CASE_INSENSITIVE_ORDER,
@@ -119,7 +119,7 @@ public class Ssh2PublicKeyEntryDecoder
     public PublicKey decodePublicKeyByType(
             SessionContext session, String keyType, InputStream keyData, Map<String, String> headers)
             throws IOException, GeneralSecurityException {
-        PublicKeyEntryDecoder<?, ?> decoder = KeyUtils.getPublicKeyEntryDecoder(keyType);
+        PublicKeyEntryDecoder decoder = KeyUtils.getPublicKeyEntryDecoder(keyType);
         if (decoder == null) {
             throw new InvalidKeySpecException("No decoder for key type=" + keyType);
         }
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/writer/openssh/OpenSSHKeyPairResourceWriter.java b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/writer/openssh/OpenSSHKeyPairResourceWriter.java
index 9df264183..fd267ca77 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/writer/openssh/OpenSSHKeyPairResourceWriter.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/writer/openssh/OpenSSHKeyPairResourceWriter.java
@@ -28,7 +28,6 @@ import java.nio.charset.StandardCharsets;
 import java.security.GeneralSecurityException;
 import java.security.KeyPair;
 import java.security.NoSuchAlgorithmException;
-import java.security.PrivateKey;
 import java.security.PublicKey;
 import java.util.Arrays;
 import java.util.Base64;
@@ -152,10 +151,7 @@ public class OpenSSHKeyPairResourceWriter implements KeyPairResourceWriter<OpenS
             KeyEntryResolver.encodeInt(out, check);
             KeyEntryResolver.encodeInt(out, check);
             KeyEntryResolver.encodeString(out, keyType);
-            @SuppressWarnings("unchecked") // Problem with generics
-            PrivateKeyEntryDecoder<PublicKey, PrivateKey> encoder
-                    = (PrivateKeyEntryDecoder<PublicKey, PrivateKey>) OpenSSHKeyPairResourceParser
-                            .getPrivateKeyEntryDecoder(keyType);
+            PrivateKeyEntryDecoder encoder = OpenSSHKeyPairResourceParser.getPrivateKeyEntryDecoder(keyType);
             if (encoder.encodePrivateKey(out, key.getPrivate(), key.getPublic()) == null) {
                 throw new GeneralSecurityException("Cannot encode key of type " + keyType);
             }
@@ -176,9 +172,7 @@ public class OpenSSHKeyPairResourceWriter implements KeyPairResourceWriter<OpenS
 
     public static byte[] encodePublicKey(PublicKey key, String keyType)
             throws IOException, GeneralSecurityException {
-        @SuppressWarnings("unchecked") // Problem with generics.
-        PublicKeyEntryDecoder<PublicKey, ?> decoder
-                = (PublicKeyEntryDecoder<PublicKey, ?>) KeyUtils.getPublicKeyEntryDecoder(keyType);
+        PublicKeyEntryDecoder decoder = KeyUtils.getPublicKeyEntryDecoder(keyType);
         if (decoder == null) {
             throw new GeneralSecurityException("Unknown key type: " + keyType);
         }
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/util/security/SecurityProviderRegistrar.java b/sshd-common/src/main/java/org/apache/sshd/common/util/security/SecurityProviderRegistrar.java
index a9cf72ab2..ec39cdf89 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/util/security/SecurityProviderRegistrar.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/util/security/SecurityProviderRegistrar.java
@@ -193,7 +193,7 @@ public interface SecurityProviderRegistrar extends SecurityProviderChoice, Optio
     /**
      * @return the EdDSA support implementation associated with the security provider (if applicable)
      */
-    default Optional<EdDSASupport<?, ?>> getEdDSASupport() {
+    default Optional<EdDSASupport> getEdDSASupport() {
         return Optional.empty();
     }
 
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/util/security/SecurityUtils.java b/sshd-common/src/main/java/org/apache/sshd/common/util/security/SecurityUtils.java
index f88f56048..21fa16215 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/util/security/SecurityUtils.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/util/security/SecurityUtils.java
@@ -565,7 +565,7 @@ public final class SecurityUtils {
         return isProviderRegistered(EDDSA);
     }
 
-    public static Optional<EdDSASupport<?, ?>> getEdDSASupport() {
+    public static Optional<EdDSASupport> getEdDSASupport() {
         if (isFipsMode()) {
             return Optional.empty();
         }
@@ -575,14 +575,14 @@ public final class SecurityUtils {
             // Prefer the net.i2p.crypto provider if it's available for backwards compatibility
             SecurityProviderRegistrar netI2pCryptoProvider = REGISTERED_PROVIDERS.get(EDDSA);
             if (netI2pCryptoProvider != null) {
-                Optional<EdDSASupport<?, ?>> support = netI2pCryptoProvider.getEdDSASupport();
+                Optional<EdDSASupport> support = netI2pCryptoProvider.getEdDSASupport();
                 if (support.isPresent()) {
                     return support;
                 }
             }
 
             for (Map.Entry<String, SecurityProviderRegistrar> entry : REGISTERED_PROVIDERS.entrySet()) {
-                Optional<EdDSASupport<?, ?>> support = entry.getValue().getEdDSASupport();
+                Optional<EdDSASupport> support = entry.getValue().getEdDSASupport();
                 if (support.isPresent()) {
                     return support;
                 }
@@ -593,8 +593,8 @@ public final class SecurityUtils {
 
     /* -------------------------------------------------------------------- */
 
-    public static PublicKeyEntryDecoder<? extends PublicKey, ? extends PrivateKey> getEDDSAPublicKeyEntryDecoder() {
-        Optional<EdDSASupport<?, ?>> support = getEdDSASupport();
+    public static PublicKeyEntryDecoder getEDDSAPublicKeyEntryDecoder() {
+        Optional<EdDSASupport> support = getEdDSASupport();
         if (!support.isPresent()) {
             throw new UnsupportedOperationException(EDDSA + " provider N/A");
         }
@@ -602,8 +602,8 @@ public final class SecurityUtils {
         return support.get().getEDDSAPublicKeyEntryDecoder();
     }
 
-    public static PrivateKeyEntryDecoder<? extends PublicKey, ? extends PrivateKey> getOpenSSHEDDSAPrivateKeyEntryDecoder() {
-        Optional<EdDSASupport<?, ?>> support = getEdDSASupport();
+    public static PrivateKeyEntryDecoder getOpenSSHEDDSAPrivateKeyEntryDecoder() {
+        Optional<EdDSASupport> support = getEdDSASupport();
         if (!support.isPresent()) {
             throw new UnsupportedOperationException(EDDSA + " provider N/A");
         }
@@ -612,7 +612,7 @@ public final class SecurityUtils {
     }
 
     public static org.apache.sshd.common.signature.Signature getEDDSASigner() {
-        Optional<EdDSASupport<?, ?>> support = getEdDSASupport();
+        Optional<EdDSASupport> support = getEdDSASupport();
         if (support.isPresent()) {
             return support.get().getEDDSASigner();
         }
@@ -621,38 +621,22 @@ public final class SecurityUtils {
     }
 
     public static int getEDDSAKeySize(Key key) {
-        Optional<EdDSASupport<?, ?>> support = getEdDSASupport();
+        Optional<EdDSASupport> support = getEdDSASupport();
         return support.map(edDSASupport -> edDSASupport.getEDDSAKeySize(key)).orElse(-1);
     }
 
-    public static Class<? extends PublicKey> getEDDSAPublicKeyType() {
-        Optional<EdDSASupport<?, ?>> support = getEdDSASupport();
-        if (!support.isPresent()) {
-            return PublicKey.class;
-        }
-        return support.get().getEDDSAPublicKeyType();
-    }
-
-    public static Class<? extends PrivateKey> getEDDSAPrivateKeyType() {
-        Optional<EdDSASupport<?, ?>> support = getEdDSASupport();
-        if (!support.isPresent()) {
-            return PrivateKey.class;
-        }
-        return support.get().getEDDSAPrivateKeyType();
-    }
-
     public static boolean compareEDDSAPPublicKeys(PublicKey k1, PublicKey k2) {
-        Optional<EdDSASupport<?, ?>> support = getEdDSASupport();
+        Optional<EdDSASupport> support = getEdDSASupport();
         return support.map(edDSASupport -> edDSASupport.compareEDDSAPPublicKeys(k1, k2)).orElse(false);
     }
 
     public static boolean compareEDDSAPrivateKeys(PrivateKey k1, PrivateKey k2) {
-        Optional<EdDSASupport<?, ?>> support = getEdDSASupport();
+        Optional<EdDSASupport> support = getEdDSASupport();
         return support.map(edDSASupport -> edDSASupport.compareEDDSAPrivateKeys(k1, k2)).orElse(false);
     }
 
     public static PublicKey recoverEDDSAPublicKey(PrivateKey key) throws GeneralSecurityException {
-        Optional<EdDSASupport<?, ?>> support = getEdDSASupport();
+        Optional<EdDSASupport> support = getEdDSASupport();
         if (!support.isPresent()) {
             throw new NoSuchAlgorithmException(EDDSA + " provider not supported");
         }
@@ -665,7 +649,7 @@ public final class SecurityUtils {
             throw new InvalidKeyException("Unsupported key type: " + keyType);
         }
 
-        Optional<EdDSASupport<?, ?>> support = getEdDSASupport();
+        Optional<EdDSASupport> support = getEdDSASupport();
         if (!support.isPresent()) {
             throw new NoSuchAlgorithmException(EDDSA + " provider not supported");
         }
@@ -678,7 +662,7 @@ public final class SecurityUtils {
             throw new InvalidKeyException("Unsupported key type: " + keyType);
         }
 
-        Optional<EdDSASupport<?, ?>> support = getEdDSASupport();
+        Optional<EdDSASupport> support = getEdDSASupport();
         if (!support.isPresent()) {
             throw new NoSuchAlgorithmException(EDDSA + " provider not supported");
         }
@@ -687,7 +671,7 @@ public final class SecurityUtils {
     }
 
     public static <B extends Buffer> B putRawEDDSAPublicKey(B buffer, PublicKey key) {
-        Optional<EdDSASupport<?, ?>> support = getEdDSASupport();
+        Optional<EdDSASupport> support = getEdDSASupport();
         if (!support.isPresent()) {
             throw new UnsupportedOperationException(EDDSA + " provider not supported");
         }
@@ -700,7 +684,7 @@ public final class SecurityUtils {
     }
 
     public static <B extends Buffer> B putEDDSAKeyPair(B buffer, PublicKey pubKey, PrivateKey prvKey) {
-        Optional<EdDSASupport<?, ?>> support = getEdDSASupport();
+        Optional<EdDSASupport> support = getEdDSASupport();
         if (!support.isPresent()) {
             throw new UnsupportedOperationException(EDDSA + " provider not supported");
         }
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/util/security/bouncycastle/BouncyCastleSecurityProviderRegistrar.java b/sshd-common/src/main/java/org/apache/sshd/common/util/security/bouncycastle/BouncyCastleSecurityProviderRegistrar.java
index f79991e02..a5f177066 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/util/security/bouncycastle/BouncyCastleSecurityProviderRegistrar.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/util/security/bouncycastle/BouncyCastleSecurityProviderRegistrar.java
@@ -173,7 +173,7 @@ public class BouncyCastleSecurityProviderRegistrar extends AbstractSecurityProvi
     }
 
     @Override
-    public Optional<EdDSASupport<?, ?>> getEdDSASupport() {
+    public Optional<EdDSASupport> getEdDSASupport() {
         if (!isEdDSASupported()) {
             return Optional.empty();
         }
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/Ed25519PublicKeyDecoder.java b/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/Ed25519PublicKeyDecoder.java
index 7c5ac4d5a..eb1ffcd45 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/Ed25519PublicKeyDecoder.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/Ed25519PublicKeyDecoder.java
@@ -18,7 +18,6 @@
  */
 package org.apache.sshd.common.util.security.eddsa;
 
-import net.i2p.crypto.eddsa.EdDSAPrivateKey;
 import net.i2p.crypto.eddsa.EdDSAPublicKey;
 import org.apache.sshd.common.util.security.eddsa.generic.GenericEd25519PublicKeyDecoder;
 
@@ -28,12 +27,12 @@ import org.apache.sshd.common.util.security.eddsa.generic.GenericEd25519PublicKe
  *
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
-public final class Ed25519PublicKeyDecoder extends GenericEd25519PublicKeyDecoder<EdDSAPublicKey, EdDSAPrivateKey> {
+public final class Ed25519PublicKeyDecoder extends GenericEd25519PublicKeyDecoder {
 
     public static final Ed25519PublicKeyDecoder INSTANCE = new Ed25519PublicKeyDecoder();
 
     private Ed25519PublicKeyDecoder() {
-        super(EdDSAPublicKey.class, EdDSAPrivateKey.class, new NetI2pCryptoEdDSASupport());
+        super(new NetI2pCryptoEdDSASupport());
     }
 
     public static byte[] getSeedValue(EdDSAPublicKey key) {
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/EdDSASecurityProviderRegistrar.java b/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/EdDSASecurityProviderRegistrar.java
index 7233495b8..7fcffd240 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/EdDSASecurityProviderRegistrar.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/EdDSASecurityProviderRegistrar.java
@@ -99,7 +99,7 @@ public class EdDSASecurityProviderRegistrar extends AbstractSecurityProviderRegi
     }
 
     @Override
-    public Optional<EdDSASupport<?, ?>> getEdDSASupport() {
+    public Optional<EdDSASupport> getEdDSASupport() {
         if (!isSupported()) {
             return Optional.empty();
         }
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/EdDSASecurityProviderUtils.java b/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/EdDSASecurityProviderUtils.java
index 6d63916b2..0c6501f87 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/EdDSASecurityProviderUtils.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/EdDSASecurityProviderUtils.java
@@ -111,12 +111,12 @@ public final class EdDSASecurityProviderUtils {
         return SecurityUtils.EDDSA.equalsIgnoreCase(algorithm);
     }
 
-    public static PublicKeyEntryDecoder<? extends PublicKey, ? extends PrivateKey> getEDDSAPublicKeyEntryDecoder() {
+    public static PublicKeyEntryDecoder getEDDSAPublicKeyEntryDecoder() {
         ValidateUtils.checkTrue(SecurityUtils.isEDDSACurveSupported(), SecurityUtils.EDDSA + " not supported");
         return Ed25519PublicKeyDecoder.INSTANCE;
     }
 
-    public static PrivateKeyEntryDecoder<? extends PublicKey, ? extends PrivateKey> getOpenSSHEDDSAPrivateKeyEntryDecoder() {
+    public static PrivateKeyEntryDecoder getOpenSSHEDDSAPrivateKeyEntryDecoder() {
         ValidateUtils.checkTrue(SecurityUtils.isEDDSACurveSupported(), SecurityUtils.EDDSA + " not supported");
         return OpenSSHEd25519PrivateKeyEntryDecoder.INSTANCE;
     }
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/NetI2pCryptoEdDSASupport.java b/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/NetI2pCryptoEdDSASupport.java
index 098442879..3e2eae767 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/NetI2pCryptoEdDSASupport.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/NetI2pCryptoEdDSASupport.java
@@ -19,17 +19,13 @@
 
 package org.apache.sshd.common.util.security.eddsa;
 
-import java.io.IOException;
 import java.security.GeneralSecurityException;
 import java.security.Key;
 import java.security.PrivateKey;
 import java.security.PublicKey;
-import java.security.spec.KeySpec;
 
 import net.i2p.crypto.eddsa.EdDSAPrivateKey;
 import net.i2p.crypto.eddsa.EdDSAPublicKey;
-import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec;
-import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec;
 import org.apache.sshd.common.config.keys.PrivateKeyEntryDecoder;
 import org.apache.sshd.common.config.keys.PublicKeyEntryDecoder;
 import org.apache.sshd.common.signature.Signature;
@@ -37,19 +33,19 @@ import org.apache.sshd.common.util.buffer.Buffer;
 import org.apache.sshd.common.util.security.SecurityUtils;
 import org.apache.sshd.common.util.security.eddsa.generic.EdDSASupport;
 
-public class NetI2pCryptoEdDSASupport implements EdDSASupport<EdDSAPublicKey, EdDSAPrivateKey> {
+public class NetI2pCryptoEdDSASupport implements EdDSASupport {
 
     public NetI2pCryptoEdDSASupport() {
         super();
     }
 
     @Override
-    public PublicKeyEntryDecoder<EdDSAPublicKey, EdDSAPrivateKey> getEDDSAPublicKeyEntryDecoder() {
+    public PublicKeyEntryDecoder getEDDSAPublicKeyEntryDecoder() {
         return Ed25519PublicKeyDecoder.INSTANCE;
     }
 
     @Override
-    public PrivateKeyEntryDecoder<EdDSAPublicKey, EdDSAPrivateKey> getOpenSSHEDDSAPrivateKeyEntryDecoder() {
+    public PrivateKeyEntryDecoder getOpenSSHEDDSAPrivateKeyEntryDecoder() {
         return OpenSSHEd25519PrivateKeyEntryDecoder.INSTANCE;
     }
 
@@ -63,16 +59,6 @@ public class NetI2pCryptoEdDSASupport implements EdDSASupport<EdDSAPublicKey, Ed
         return EdDSASecurityProviderUtils.getEDDSAKeySize(key);
     }
 
-    @Override
-    public Class<EdDSAPublicKey> getEDDSAPublicKeyType() {
-        return EdDSAPublicKey.class;
-    }
-
-    @Override
-    public Class<EdDSAPrivateKey> getEDDSAPrivateKeyType() {
-        return EdDSAPrivateKey.class;
-    }
-
     @Override
     public boolean compareEDDSAPPublicKeys(PublicKey k1, PublicKey k2) {
         return EdDSASecurityProviderUtils.compareEDDSAPPublicKeys(k1, k2);
@@ -108,26 +94,6 @@ public class NetI2pCryptoEdDSASupport implements EdDSASupport<EdDSAPublicKey, Ed
         return EdDSASecurityProviderUtils.putEDDSAKeyPair(buffer, pubKey, prvKey);
     }
 
-    @Override
-    public KeySpec createPublicKeySpec(EdDSAPublicKey publicKey) {
-        return new EdDSAPublicKeySpec(publicKey.getA(), publicKey.getParams());
-    }
-
-    @Override
-    public KeySpec createPrivateKeySpec(EdDSAPrivateKey privateKey) {
-        return new EdDSAPrivateKeySpec(privateKey.getSeed(), privateKey.getParams());
-    }
-
-    @Override
-    public byte[] getPublicKeyData(EdDSAPublicKey publicKey) {
-        return publicKey == null ? null : publicKey.getAbyte();
-    }
-
-    @Override
-    public byte[] getPrivateKeyData(EdDSAPrivateKey privateKey) throws IOException {
-        return privateKey.getSeed();
-    }
-
     @Override
     public String getKeyFactoryAlgorithm() {
         return SecurityUtils.EDDSA;
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/OpenSSHEd25519PrivateKeyEntryDecoder.java b/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/OpenSSHEd25519PrivateKeyEntryDecoder.java
index b4012a90f..7cfb3555b 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/OpenSSHEd25519PrivateKeyEntryDecoder.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/OpenSSHEd25519PrivateKeyEntryDecoder.java
@@ -19,8 +19,6 @@
 
 package org.apache.sshd.common.util.security.eddsa;
 
-import net.i2p.crypto.eddsa.EdDSAPrivateKey;
-import net.i2p.crypto.eddsa.EdDSAPublicKey;
 import org.apache.sshd.common.util.security.eddsa.generic.GenericOpenSSHEd25519PrivateKeyEntryDecoder;
 
 /**
@@ -30,11 +28,11 @@ import org.apache.sshd.common.util.security.eddsa.generic.GenericOpenSSHEd25519P
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
 public class OpenSSHEd25519PrivateKeyEntryDecoder
-        extends GenericOpenSSHEd25519PrivateKeyEntryDecoder<EdDSAPublicKey, EdDSAPrivateKey> {
+        extends GenericOpenSSHEd25519PrivateKeyEntryDecoder {
     public static final OpenSSHEd25519PrivateKeyEntryDecoder INSTANCE = new OpenSSHEd25519PrivateKeyEntryDecoder();
 
     public OpenSSHEd25519PrivateKeyEntryDecoder() {
-        super(EdDSAPublicKey.class, EdDSAPrivateKey.class, new NetI2pCryptoEdDSASupport());
+        super(new NetI2pCryptoEdDSASupport());
     }
 
 }
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/bouncycastle/BouncyCastleEdDSASupport.java b/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/bouncycastle/BouncyCastleEdDSASupport.java
index cc2659bff..cd8baa249 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/bouncycastle/BouncyCastleEdDSASupport.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/bouncycastle/BouncyCastleEdDSASupport.java
@@ -26,7 +26,6 @@ import java.security.Key;
 import java.security.KeyFactory;
 import java.security.PrivateKey;
 import java.security.PublicKey;
-import java.security.spec.KeySpec;
 import java.security.spec.PKCS8EncodedKeySpec;
 
 import org.apache.sshd.common.config.keys.PrivateKeyEntryDecoder;
@@ -41,27 +40,26 @@ import org.apache.sshd.common.util.security.eddsa.generic.GenericOpenSSHEd25519P
 import org.apache.sshd.common.util.security.eddsa.generic.GenericSignatureEd25519;
 import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
 import org.bouncycastle.crypto.params.Ed25519PrivateKeyParameters;
-import org.bouncycastle.crypto.util.PrivateKeyFactory;
 import org.bouncycastle.crypto.util.PrivateKeyInfoFactory;
 import org.bouncycastle.jcajce.interfaces.EdDSAKey;
 import org.bouncycastle.jcajce.interfaces.EdDSAPrivateKey;
 import org.bouncycastle.jcajce.interfaces.EdDSAPublicKey;
 import org.bouncycastle.jcajce.spec.RawEncodedKeySpec;
 
-public class BouncyCastleEdDSASupport implements EdDSASupport<EdDSAPublicKey, EdDSAPrivateKey> {
+public class BouncyCastleEdDSASupport implements EdDSASupport {
 
     public BouncyCastleEdDSASupport() {
         super();
     }
 
     @Override
-    public PublicKeyEntryDecoder<EdDSAPublicKey, EdDSAPrivateKey> getEDDSAPublicKeyEntryDecoder() {
-        return new GenericEd25519PublicKeyDecoder<>(EdDSAPublicKey.class, EdDSAPrivateKey.class, this);
+    public PublicKeyEntryDecoder getEDDSAPublicKeyEntryDecoder() {
+        return new GenericEd25519PublicKeyDecoder(this);
     }
 
     @Override
-    public PrivateKeyEntryDecoder<EdDSAPublicKey, EdDSAPrivateKey> getOpenSSHEDDSAPrivateKeyEntryDecoder() {
-        return new GenericOpenSSHEd25519PrivateKeyEntryDecoder<>(EdDSAPublicKey.class, EdDSAPrivateKey.class, this);
+    public PrivateKeyEntryDecoder getOpenSSHEDDSAPrivateKeyEntryDecoder() {
+        return new GenericOpenSSHEd25519PrivateKeyEntryDecoder(this);
     }
 
     @Override
@@ -74,16 +72,6 @@ public class BouncyCastleEdDSASupport implements EdDSASupport<EdDSAPublicKey, Ed
         return key instanceof EdDSAKey ? KEY_SIZE : -1;
     }
 
-    @Override
-    public Class<EdDSAPublicKey> getEDDSAPublicKeyType() {
-        return EdDSAPublicKey.class;
-    }
-
-    @Override
-    public Class<EdDSAPrivateKey> getEDDSAPrivateKeyType() {
-        return EdDSAPrivateKey.class;
-    }
-
     @Override
     public boolean compareEDDSAPPublicKeys(PublicKey k1, PublicKey k2) {
         if (!(k1 instanceof EdDSAPublicKey) || !(k2 instanceof EdDSAPublicKey)) {
@@ -140,28 +128,6 @@ public class BouncyCastleEdDSASupport implements EdDSASupport<EdDSAPublicKey, Ed
         throw new UnsupportedOperationException("Full SSHD-440 implementation N/A");
     }
 
-    @Override
-    public KeySpec createPublicKeySpec(EdDSAPublicKey publicKey) {
-        return new RawEncodedKeySpec(publicKey.getPointEncoding());
-    }
-
-    @Override
-    public KeySpec createPrivateKeySpec(EdDSAPrivateKey privateKey) {
-        return new PKCS8EncodedKeySpec(privateKey.getEncoded());
-    }
-
-    @Override
-    public byte[] getPublicKeyData(EdDSAPublicKey publicKey) {
-        return publicKey == null ? null : publicKey.getPointEncoding();
-    }
-
-    @Override
-    public byte[] getPrivateKeyData(EdDSAPrivateKey privateKey) throws IOException {
-        Ed25519PrivateKeyParameters parameters
-                = (Ed25519PrivateKeyParameters) PrivateKeyFactory.createKey(privateKey.getEncoded());
-        return parameters.getEncoded();
-    }
-
     @Override
     public String getKeyFactoryAlgorithm() {
         return SecurityUtils.ED25519;
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/generic/EdDSASupport.java b/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/generic/EdDSASupport.java
index 162ffc09a..1ccbd6b41 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/generic/EdDSASupport.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/generic/EdDSASupport.java
@@ -22,11 +22,11 @@ package org.apache.sshd.common.util.security.eddsa.generic;
 import java.io.IOException;
 import java.io.StreamCorruptedException;
 import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
 import java.security.Key;
 import java.security.KeyPair;
 import java.security.PrivateKey;
 import java.security.PublicKey;
-import java.security.spec.KeySpec;
 
 import org.apache.sshd.common.config.keys.PrivateKeyEntryDecoder;
 import org.apache.sshd.common.config.keys.PublicKeyEntryDecoder;
@@ -41,11 +41,9 @@ import org.apache.sshd.common.util.security.SecurityUtils;
 /**
  * Provides generic operations required of a security provider to support EdDSA and Ed25519.
  *
- * @param  <PUB> type of the public key supported by the security provider
- * @param  <PRV> type of the private key supported by the security provider
- * @author       <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
-public interface EdDSASupport<PUB extends PublicKey, PRV extends PrivateKey> {
+public interface EdDSASupport {
 
     int KEY_SIZE = 256;
 
@@ -87,12 +85,12 @@ public interface EdDSASupport<PUB extends PublicKey, PRV extends PrivateKey> {
     /**
      * @return the public key entry decoder implementation associated with the security provider.
      */
-    PublicKeyEntryDecoder<PUB, PRV> getEDDSAPublicKeyEntryDecoder();
+    PublicKeyEntryDecoder getEDDSAPublicKeyEntryDecoder();
 
     /**
      * @return the private key entry decoder implementation associated with the security provider.
      */
-    PrivateKeyEntryDecoder<PUB, PRV> getOpenSSHEDDSAPrivateKeyEntryDecoder();
+    PrivateKeyEntryDecoder getOpenSSHEDDSAPrivateKeyEntryDecoder();
 
     /**
      * @return the signature implementation associated with the security provider.
@@ -105,16 +103,6 @@ public interface EdDSASupport<PUB extends PublicKey, PRV extends PrivateKey> {
      */
     int getEDDSAKeySize(Key key);
 
-    /**
-     * @return the public key class type associated with the security provider.
-     */
-    Class<PUB> getEDDSAPublicKeyType();
-
-    /**
-     * @return the private key class type associated with the security provider.
-     */
-    Class<PRV> getEDDSAPrivateKeyType();
-
     /**
      * @param  k1 the first key
      * @param  k2 the second key
@@ -135,19 +123,19 @@ public interface EdDSASupport<PUB extends PublicKey, PRV extends PrivateKey> {
      * @param  key the private key
      * @return     the public key associated with the private key.
      */
-    PUB recoverEDDSAPublicKey(PrivateKey key) throws GeneralSecurityException;
+    PublicKey recoverEDDSAPublicKey(PrivateKey key) throws GeneralSecurityException;
 
     /**
      * @param  seed the raw public key bytes
      * @return      the associated public key
      */
-    PUB generateEDDSAPublicKey(byte[] seed) throws GeneralSecurityException;
+    PublicKey generateEDDSAPublicKey(byte[] seed) throws GeneralSecurityException;
 
     /**
      * @param  seed the raw private key bytes
      * @return      the associated private key
      */
-    PRV generateEDDSAPrivateKey(byte[] seed) throws GeneralSecurityException, IOException;
+    PrivateKey generateEDDSAPrivateKey(byte[] seed) throws GeneralSecurityException, IOException;
 
     /**
      * @param  buffer the buffer to insert the public key into
@@ -166,29 +154,29 @@ public interface EdDSASupport<PUB extends PublicKey, PRV extends PrivateKey> {
      */
     <B extends Buffer> B putEDDSAKeyPair(B buffer, PublicKey pubKey, PrivateKey prvKey);
 
-    /**
-     * @param  publicKey the public key
-     * @return           a key spec from the public key
-     */
-    KeySpec createPublicKeySpec(PUB publicKey);
-
-    /**
-     * @param  privateKey the private key
-     * @return            a key spec from the private key
-     */
-    KeySpec createPrivateKeySpec(PRV privateKey);
-
     /**
      * @param  publicKey the public key
      * @return           the raw public key bytes associated with the key
      */
-    byte[] getPublicKeyData(PUB publicKey);
+    default byte[] getPublicKeyData(PublicKey publicKey) {
+        try {
+            return EdDSAUtils.getBytes(publicKey);
+        } catch (InvalidKeyException e) {
+            throw new IllegalArgumentException(e);
+        }
+    };
 
     /**
      * @param  privateKey the private key
      * @return            the raw private key bytes associated with the key
      */
-    byte[] getPrivateKeyData(PRV privateKey) throws IOException;
+    default byte[] getPrivateKeyData(PrivateKey privateKey) throws IOException {
+        try {
+            return EdDSAUtils.getBytes(privateKey);
+        } catch (InvalidKeyException e) {
+            throw new IOException(e);
+        }
+    }
 
     /**
      * @return the algorithm name used by the provider's {@link java.security.KeyFactory}.
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/generic/EdDSAUtils.java b/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/generic/EdDSAUtils.java
index 713b49e37..5aa82508c 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/generic/EdDSAUtils.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/generic/EdDSAUtils.java
@@ -18,10 +18,17 @@
  */
 package org.apache.sshd.common.util.security.eddsa.generic;
 
+import java.io.IOException;
 import java.security.InvalidKeyException;
+import java.security.PrivateKey;
 import java.security.PublicKey;
+import java.security.spec.KeySpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
 import java.util.Arrays;
 
+import org.apache.sshd.common.util.io.der.DERParser;
+
 /**
  * Utilities to extract the raw key bytes from ed25519 or ed448 public keys, in a manner that is independent of the
  * actual concrete key implementation classes.
@@ -44,10 +51,43 @@ public final class EdDSAUtils {
     private static final byte[] ED448_X509_PREFIX = {
             0x30, 0x43, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x71, 0x03, 0x3a, 0x00 };
 
+    // For reconstructing private keys from raw bytes we construct a minimal PKCS#8 encoding, using RFC 5208 (version 0)
+    // without the public key and without attributes. This is allowed by RFC 5958 (Asymmetric key packages).
+
+    // Sequence, length 46, (3 bytes: Version 0), Sequence, length 5, OID, length 3, O, I, D, Octet String, length 34,
+    // Octet String, length 32
+    private static final byte[] ED25519_PKCS8_PREFIX = {
+            0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70,
+            0x04, 0x22, 0x04, 0x20 };
+    // Sequence, length 71, (3 bytes: Version 0), Sequence, length 5, OID, length 3, O, I, D, Octet String, length 59,
+    // Octet String, length 57
+    private static final byte[] ED448_PKCS8_PREFIX = {
+            0x30, 0x47, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x71,
+            0x04, 0x3b, 0x04, 0x39 };
+
+    // The first two numbers of the dotted notation are combined into one byte: (1 * 40 + 3) = 43 = 0x2b
+    private static final byte[] ED25519_OID = { 0x2b, 0x65, 0x70 }; // 1.3.101.112
+    private static final byte[] ED448_OID = { 0x2b, 0x65, 0x71 }; // 1.3.101.113
+
     private EdDSAUtils() {
         throw new IllegalStateException("No instantiation");
     }
 
+    private static boolean arrayEq(byte[] a, byte[] b) {
+        if (a == null && b == null) {
+            return true;
+        }
+        if (a == null || b == null) {
+            return false;
+        }
+        int unequal = a.length ^ b.length;
+        int length = Math.min(a.length, b.length);
+        for (int i = 0; i < length; i++) {
+            unequal |= a[i] ^ b[i];
+        }
+        return unequal == 0;
+    }
+
     private static boolean startsWith(byte[] data, byte[] prefix) {
         if (data == null || prefix == null || prefix.length == 0 || data.length < prefix.length) {
             return false;
@@ -86,4 +126,165 @@ public final class EdDSAUtils {
         }
         return Arrays.copyOfRange(encoded, encoded.length - n, encoded.length);
     }
+
+    /**
+     * Retrieves the raw key bytes from an ed25519 or ed448 {@link PrivateKey}.
+     *
+     * @param  key                 {@link PrivateKey} to get the bytes of
+     * @return                     the raw key bytes
+     * @throws InvalidKeyException if the key is not an ed25519 or ed448 key, or if it doesn't use PKCS#8 encoding
+     */
+    public static byte[] getBytes(PrivateKey key) throws InvalidKeyException {
+        // Extract the private key bytes from the PKCS#8 encoding.
+        if (!"PKCS#8".equalsIgnoreCase(key.getFormat())) {
+            throw new InvalidKeyException("Cannot extract private key bytes from a non-PKCS#8 encoding");
+        }
+        byte[] encoded = key.getEncoded();
+        if (encoded == null) {
+            throw new InvalidKeyException("Private key " + key.getClass().getCanonicalName() + " does not support encoding");
+        }
+        try {
+            return asn1Parse(encoded);
+        } finally {
+            Arrays.fill(encoded, (byte) 0);
+        }
+    }
+
+    /**
+     * Extracts the private key bytes from an encoded EdDSA private key by parsing the bytes as ASN.1 according to RFC
+     * 5958 (PKCS #8 encoding):
+     *
+     * <pre>
+     * OneAsymmetricKey ::= SEQUENCE {
+     *   version Version,
+     *   privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
+     *   privateKey PrivateKey,
+     *   ...
+     * }
+     *
+     * Version ::= INTEGER
+     * PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier
+     * PrivateKey ::= OCTET STRING
+     *
+     * AlgorithmIdentifier  ::=  SEQUENCE  {
+     *   algorithm   OBJECT IDENTIFIER,
+     *   parameters  ANY DEFINED BY algorithm OPTIONAL
+     * }
+     * </pre>
+     * <p>
+     * and RFC 8410: "... when encoding a OneAsymmetricKey object, the private key is wrapped in a CurvePrivateKey
+     * object and wrapped by the OCTET STRING of the 'privateKey' field."
+     * </p>
+     *
+     * <pre>
+     * CurvePrivateKey ::= OCTET STRING
+     * </pre>
+     *
+     * @param  encoded             encoded private key to extract the private key bytes from
+     * @return                     the extracted private key bytes
+     * @throws InvalidKeyException if the private key cannot be extracted
+     * @see                        <a href="https://tools.ietf.org/html/rfc5958">RFC 5958</a>
+     * @see                        <a href="https://tools.ietf.org/html/rfc8410">RFC 8410</a>
+     */
+    private static byte[] asn1Parse(byte[] encoded) throws InvalidKeyException {
+        byte[] privateKey = null;
+        try (DERParser byteParser = new DERParser(encoded);
+             DERParser oneAsymmetricKey = byteParser.readObject().createParser()) {
+            oneAsymmetricKey.readObject(); // Skip version
+            int n;
+            try (DERParser algorithmIdentifier = oneAsymmetricKey.readObject().createParser()) {
+                byte[] oid = algorithmIdentifier.readObject().getValue();
+                if (arrayEq(ED25519_OID, oid)) {
+                    n = ED25519_LENGTH;
+                } else if (arrayEq(ED448_OID, oid)) {
+                    n = ED448_LENGTH;
+                } else {
+                    throw new InvalidKeyException("Private key is neither ed25519 nor ed448");
+                }
+            }
+            privateKey = oneAsymmetricKey.readObject().getValue();
+            // The last n bytes of this must be the private key bytes.
+            return Arrays.copyOfRange(privateKey, privateKey.length - n, privateKey.length);
+            // Depending on the version there may be optional stuff following, but we don't care about that.
+        } catch (IOException e) {
+            throw new InvalidKeyException("Cannot parse EdDSA private key", e);
+        } finally {
+            if (privateKey != null) {
+                Arrays.fill(privateKey, (byte) 0);
+            }
+        }
+    }
+
+    /**
+     * Creates a {@link KeySpec} for re-creating the given ed25519 or ed448 public key.
+     *
+     * @param  key                 ed25519 or ed448 key to create a {@link KeySpec} for
+     * @return                     the {@link KeySpec}
+     * @throws InvalidKeyException if the key is neither an ed25519 nor an ed448 key
+     */
+    public static KeySpec createKeySpec(PublicKey key) throws InvalidKeyException {
+        return createPublicKeySpec(getBytes(key));
+    }
+
+    /**
+     * Creates a {@link KeySpec} for re-creating the given ed25519 or ed448 private key.
+     *
+     * @param  key                 ed25519 or ed448 key to create a {@link KeySpec} for
+     * @return                     the {@link KeySpec}
+     * @throws InvalidKeyException if the key is neither an ed25519 nor an ed448 key
+     */
+    public static KeySpec createKeySpec(PrivateKey key) throws InvalidKeyException {
+        return createPrivateKeySpec(getBytes(key));
+    }
+
+    /**
+     * Creates a {@link KeySpec} for re-creating an ed25519 or ed448 public key from the raw key bytes.
+     *
+     * @param  keyData             the raw key bytes
+     * @return                     the {@link KeySpec}
+     * @throws InvalidKeyException if the key bytes do not have the appropriate length for an ed25519 or ed448 key
+     */
+    public static KeySpec createPublicKeySpec(byte[] keyData) throws InvalidKeyException {
+        // Create an X.509 encoding for ed25519 or ed448, depending on the length of keyData.
+        if (keyData.length == ED25519_LENGTH) {
+            byte[] x509 = Arrays.copyOf(ED25519_X509_PREFIX, ED25519_X509_PREFIX.length + ED25519_LENGTH);
+            System.arraycopy(keyData, 0, x509, ED25519_X509_PREFIX.length, ED25519_LENGTH);
+            return new X509EncodedKeySpec(x509);
+        } else if (keyData.length == ED448_LENGTH) {
+            byte[] x509 = Arrays.copyOf(ED448_X509_PREFIX, ED448_X509_PREFIX.length + ED448_LENGTH);
+            System.arraycopy(keyData, 0, x509, ED448_X509_PREFIX.length, ED448_LENGTH);
+            return new X509EncodedKeySpec(x509);
+        }
+        throw new InvalidKeyException("Public key data is neither ed25519 nor ed448");
+    }
+
+    /**
+     * Creates a {@link KeySpec} for re-creating an ed25519 or ed448 public key from the raw key bytes.
+     *
+     * @param  keyData             the raw key bytes
+     * @return                     the {@link KeySpec}
+     * @throws InvalidKeyException if the key bytes do not have the appropriate length for an ed25519 or ed448 key
+     */
+    public static KeySpec createPrivateKeySpec(byte[] keyData) throws InvalidKeyException {
+        // Create a PKCS#8 encoding for ed25519 or ed448, depending on the length of keyData.
+        if (keyData.length == ED25519_LENGTH) {
+            byte[] pkcs8 = Arrays.copyOf(ED25519_PKCS8_PREFIX, ED25519_PKCS8_PREFIX.length + ED25519_LENGTH);
+            try {
+                System.arraycopy(keyData, 0, pkcs8, ED25519_PKCS8_PREFIX.length, ED25519_LENGTH);
+                return new PKCS8EncodedKeySpec(pkcs8);
+            } finally {
+                Arrays.fill(pkcs8, (byte) 0);
+            }
+        } else if (keyData.length == ED448_LENGTH) {
+            byte[] pkcs8 = Arrays.copyOf(ED448_PKCS8_PREFIX, ED448_PKCS8_PREFIX.length + ED448_LENGTH);
+            try {
+                System.arraycopy(keyData, 0, pkcs8, ED448_PKCS8_PREFIX.length, ED448_LENGTH);
+                return new PKCS8EncodedKeySpec(pkcs8);
+            } finally {
+                Arrays.fill(pkcs8, (byte) 0);
+            }
+        }
+        throw new InvalidKeyException("Private key data is neither ed25519 nor ed448");
+    }
+
 }
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/generic/GenericEd25519PublicKeyDecoder.java b/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/generic/GenericEd25519PublicKeyDecoder.java
index 98455f65c..f3294821a 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/generic/GenericEd25519PublicKeyDecoder.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/generic/GenericEd25519PublicKeyDecoder.java
@@ -24,7 +24,6 @@ import java.io.OutputStream;
 import java.security.GeneralSecurityException;
 import java.security.KeyFactory;
 import java.security.KeyPairGenerator;
-import java.security.PrivateKey;
 import java.security.PublicKey;
 import java.util.Collections;
 import java.util.Map;
@@ -39,14 +38,13 @@ import org.apache.sshd.common.util.security.SecurityUtils;
 /**
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
-public class GenericEd25519PublicKeyDecoder<PUB extends PublicKey, PRV extends PrivateKey>
-        extends AbstractPublicKeyEntryDecoder<PUB, PRV> {
+public class GenericEd25519PublicKeyDecoder extends AbstractPublicKeyEntryDecoder {
     public static final int MAX_ALLOWED_SEED_LEN = 1024; // in reality it is much less than this
 
-    protected final EdDSASupport<PUB, PRV> edDSASupport;
+    protected final EdDSASupport edDSASupport;
 
-    public GenericEd25519PublicKeyDecoder(Class<PUB> pubType, Class<PRV> prvType, EdDSASupport<PUB, PRV> edDSASupport) {
-        super(pubType, prvType, Collections.singletonList(KeyPairProvider.SSH_ED25519));
+    public GenericEd25519PublicKeyDecoder(EdDSASupport edDSASupport) {
+        super(Collections.singletonList(KeyPairProvider.SSH_ED25519));
         this.edDSASupport = edDSASupport;
     }
 
@@ -56,7 +54,7 @@ public class GenericEd25519PublicKeyDecoder<PUB extends PublicKey, PRV extends P
     }
 
     @Override
-    public String encodePublicKey(OutputStream s, PUB key) throws IOException {
+    public String encodePublicKey(OutputStream s, PublicKey key) throws IOException {
         Objects.requireNonNull(key, "No public key provided");
         KeyEntryResolver.encodeString(s, KeyPairProvider.SSH_ED25519);
         byte[] seed = edDSASupport.getPublicKeyData(key);
@@ -70,7 +68,7 @@ public class GenericEd25519PublicKeyDecoder<PUB extends PublicKey, PRV extends P
     }
 
     @Override
-    public PUB decodePublicKey(
+    public PublicKey decodePublicKey(
             SessionContext session, String keyType, InputStream keyData, Map<String, String> headers)
             throws IOException, GeneralSecurityException {
         byte[] seed = KeyEntryResolver.readRLEBytes(keyData, MAX_ALLOWED_SEED_LEN);
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/generic/GenericOpenSSHEd25519PrivateKeyEntryDecoder.java b/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/generic/GenericOpenSSHEd25519PrivateKeyEntryDecoder.java
index 6d48b67cb..62dec443b 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/generic/GenericOpenSSHEd25519PrivateKeyEntryDecoder.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/generic/GenericOpenSSHEd25519PrivateKeyEntryDecoder.java
@@ -45,22 +45,20 @@ import org.apache.sshd.common.util.security.SecurityUtils;
 /**
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
-public class GenericOpenSSHEd25519PrivateKeyEntryDecoder<PUB extends PublicKey, PRV extends PrivateKey>
-        extends AbstractPrivateKeyEntryDecoder<PUB, PRV> {
+public class GenericOpenSSHEd25519PrivateKeyEntryDecoder extends AbstractPrivateKeyEntryDecoder {
     private static final int PK_SIZE = 32;
     private static final int SK_SIZE = 32;
     private static final int KEYPAIR_SIZE = PK_SIZE + SK_SIZE;
 
-    protected final EdDSASupport<PUB, PRV> edDSASupport;
+    protected final EdDSASupport edDSASupport;
 
-    public GenericOpenSSHEd25519PrivateKeyEntryDecoder(Class<PUB> pubType, Class<PRV> prvType,
-                                                       EdDSASupport<PUB, PRV> edDSASupport) {
-        super(pubType, prvType, Collections.singletonList(KeyPairProvider.SSH_ED25519));
+    public GenericOpenSSHEd25519PrivateKeyEntryDecoder(EdDSASupport edDSASupport) {
+        super(Collections.singletonList(KeyPairProvider.SSH_ED25519));
         this.edDSASupport = edDSASupport;
     }
 
     @Override
-    public PRV decodePrivateKey(
+    public PrivateKey decodePrivateKey(
             SessionContext session, String keyType, FilePasswordProvider passwordProvider, InputStream keyData)
             throws IOException, GeneralSecurityException {
         if (!KeyPairProvider.SSH_ED25519.equals(keyType)) {
@@ -98,7 +96,7 @@ public class GenericOpenSSHEd25519PrivateKeyEntryDecoder<PUB extends PublicKey,
             }
 
             byte[] sk = Arrays.copyOf(keypair, SK_SIZE);
-            PRV privateKey = edDSASupport.generateEDDSAPrivateKey(sk);
+            PrivateKey privateKey = edDSASupport.generateEDDSAPrivateKey(sk);
 
             // we can now verify the generated pk matches the one we read
             if (!Arrays.equals(edDSASupport.getPublicKeyData(recoverPublicKey(privateKey)), pk)) {
@@ -114,7 +112,7 @@ public class GenericOpenSSHEd25519PrivateKeyEntryDecoder<PUB extends PublicKey,
     }
 
     @Override
-    public String encodePrivateKey(SecureByteArrayOutputStream s, PRV key, PUB pubKey)
+    public String encodePrivateKey(SecureByteArrayOutputStream s, PrivateKey key, PublicKey pubKey)
             throws IOException {
         Objects.requireNonNull(key, "No private key provided");
 
@@ -143,7 +141,7 @@ public class GenericOpenSSHEd25519PrivateKeyEntryDecoder<PUB extends PublicKey,
     }
 
     @Override
-    public PUB recoverPublicKey(PRV prvKey) throws GeneralSecurityException {
+    public PublicKey recoverPublicKey(PrivateKey prvKey) throws GeneralSecurityException {
         return edDSASupport.recoverEDDSAPublicKey(prvKey);
     }
 
diff --git a/sshd-common/src/test/java/org/apache/sshd/common/config/keys/BuiltinIdentitiesTest.java b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/BuiltinIdentitiesTest.java
index 529f7969b..de4c2dd71 100644
--- a/sshd-common/src/test/java/org/apache/sshd/common/config/keys/BuiltinIdentitiesTest.java
+++ b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/BuiltinIdentitiesTest.java
@@ -100,6 +100,11 @@ class BuiltinIdentitiesTest extends JUnitTestSupport {
     void fromKey(BuiltinIdentities expected) throws GeneralSecurityException {
         Assumptions.assumeTrue(expected.isSupported(), "Unsupported built-in identity");
         KeyPairGenerator gen = SecurityUtils.getKeyPairGenerator(expected.getAlgorithm());
+        if ("EC".equals(expected.getAlgorithm())) {
+            // BC defaults to prime239v1, which is not one of the EC curves supported by SSH.
+            // So force 256 to get the nistp256 curve.
+            gen.initialize(256);
+        }
         KeyPair kp = gen.generateKeyPair();
         outputDebugMessage("Checking built-in identity: %s", expected);
         assertSame(expected, BuiltinIdentities.fromKeyPair(kp), expected + "[pair]");
diff --git a/sshd-common/src/test/java/org/apache/sshd/common/config/keys/EcdsaPublicKeyEntryDecoderTest.java b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/EcdsaPublicKeyEntryDecoderTest.java
index 4e564f2e2..1a6848ec3 100644
--- a/sshd-common/src/test/java/org/apache/sshd/common/config/keys/EcdsaPublicKeyEntryDecoderTest.java
+++ b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/EcdsaPublicKeyEntryDecoderTest.java
@@ -59,9 +59,7 @@ class EcdsaPublicKeyEntryDecoderTest extends JUnitTestSupport {
 
             KeyPair keyPair = KeyUtils.generateKeyPair(keyType, keySize);
             PublicKey expected = keyPair.getPublic();
-            @SuppressWarnings("unchecked")
-            PublicKeyEntryDecoder<PublicKey, ?> decoder
-                    = (PublicKeyEntryDecoder<PublicKey, ?>) KeyUtils.getPublicKeyEntryDecoder(expected);
+            PublicKeyEntryDecoder decoder = KeyUtils.getPublicKeyEntryDecoder(expected);
             byte[] encodedPublicKey;
             try (ByteArrayOutputStream ostrm = new ByteArrayOutputStream()) {
                 decoder.encodePublicKey(ostrm, expected);
diff --git a/sshd-common/src/test/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParserDecodingTest.java b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParserDecodingTest.java
index 360d8a303..d71f268c4 100644
--- a/sshd-common/src/test/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParserDecodingTest.java
+++ b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParserDecodingTest.java
@@ -64,16 +64,12 @@ class OpenSSHKeyPairResourceParserDecodingTest extends OpenSSHKeyPairResourcePar
             throws Exception {
         assertEquals(1, GenericUtils.size(pairs), "Mismatched pairs count");
 
-        Class<? extends PublicKey> pubType = identity.getPublicKeyType();
-        Class<? extends PrivateKey> prvType = identity.getPrivateKeyType();
         Collection<String> supportedTypeNames = identity.getSupportedKeyTypes();
         for (KeyPair kp : pairs) {
             PublicKey pubKey = kp.getPublic();
-            assertObjectInstanceOf("Mismatched public key type", pubType, pubKey);
             assertKeyEquals("Mismatched identity public key", pubEntry, pubKey);
 
             PrivateKey prvKey = kp.getPrivate();
-            assertObjectInstanceOf("Mismatched private key type", prvType, prvKey);
 
             String pubName = KeyUtils.getKeyType(pubKey);
             String prvName = KeyUtils.getKeyType(prvKey);
@@ -85,12 +81,10 @@ class OpenSSHKeyPairResourceParserDecodingTest extends OpenSSHKeyPairResourcePar
 
             validateKeyPairSignable(pubName, kp);
 
-            @SuppressWarnings("rawtypes")
             PrivateKeyEntryDecoder decoder = OpenSSHKeyPairResourceParser.getPrivateKeyEntryDecoder(prvKey);
             assertNotNull(decoder, "No private key decoder");
 
             if (decoder.isPublicKeyRecoverySupported()) {
-                @SuppressWarnings("unchecked")
                 PublicKey recKey = decoder.recoverPublicKey(prvKey);
                 assertKeyEquals("Mismatched recovered public key", pubKey, recKey);
             }
diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/security/eddsa/Ed25519VectorsTest.java b/sshd-common/src/test/java/org/apache/sshd/common/util/security/eddsa/Ed25519VectorsTest.java
index b0028f696..673644668 100644
--- a/sshd-common/src/test/java/org/apache/sshd/common/util/security/eddsa/Ed25519VectorsTest.java
+++ b/sshd-common/src/test/java/org/apache/sshd/common/util/security/eddsa/Ed25519VectorsTest.java
@@ -36,6 +36,7 @@ import org.apache.sshd.common.util.buffer.BufferUtils;
 import org.apache.sshd.common.util.security.SecurityUtils;
 import org.apache.sshd.common.util.security.eddsa.bouncycastle.BouncyCastleEdDSASupport;
 import org.apache.sshd.common.util.security.eddsa.generic.EdDSASupport;
+import org.apache.sshd.common.util.security.eddsa.generic.EdDSAUtils;
 import org.apache.sshd.util.test.JUnitTestSupport;
 import org.junit.jupiter.api.Assumptions;
 import org.junit.jupiter.api.BeforeAll;
@@ -55,14 +56,14 @@ import org.junit.jupiter.params.provider.MethodSource;
 class Ed25519VectorsTest<PUB extends PublicKey, PRV extends PrivateKey> extends JUnitTestSupport {
 
     private byte[] prvBytes;
-    private PRV privateKey;
+    private PrivateKey privateKey;
     private byte[] pubBytes;
-    private PUB publicKey;
+    private PublicKey publicKey;
     private byte[] msgBytes;
     private byte[] expSignature;
 
     void initEd25519VectorsTest(
-            String name, EdDSASupport<PUB, PRV> support, String prvKey, String pubKey, String msg, String signature)
+            String name, EdDSASupport support, String prvKey, String pubKey, String msg, String signature)
             throws GeneralSecurityException, IOException {
         prvBytes = BufferUtils.decodeHex(BufferUtils.EMPTY_HEX_SEPARATOR, prvKey);
         privateKey = support.generateEDDSAPrivateKey(prvBytes.clone());
@@ -74,10 +75,10 @@ class Ed25519VectorsTest<PUB extends PublicKey, PRV extends PrivateKey> extends
 
     static List<Object[]> parameters() {
         List<Object[]> parameters = new ArrayList<>();
-        Map<String, EdDSASupport<?, ?>> supportedSecurityProviders = new LinkedHashMap<>();
+        Map<String, EdDSASupport> supportedSecurityProviders = new LinkedHashMap<>();
         supportedSecurityProviders.put(SecurityUtils.EDDSA, new NetI2pCryptoEdDSASupport());
         supportedSecurityProviders.put(SecurityUtils.BOUNCY_CASTLE, new BouncyCastleEdDSASupport());
-        for (Map.Entry<String, EdDSASupport<?, ?>> entry : supportedSecurityProviders.entrySet()) {
+        for (Map.Entry<String, EdDSASupport> entry : supportedSecurityProviders.entrySet()) {
             String supportClassName = entry.getValue().getClass().getSimpleName();
             parameters.add(new Object[] {
                     supportClassName + " TEST1 - empty message",
@@ -202,7 +203,7 @@ class Ed25519VectorsTest<PUB extends PublicKey, PRV extends PrivateKey> extends
     @MethodSource("parameters")
     @ParameterizedTest(name = "{0}")
     void publicKeyBytes(
-            String name, EdDSASupport<PUB, PRV> support, String provider, String prvKey, String pubKey, String msg,
+            String name, EdDSASupport support, String provider, String prvKey, String pubKey, String msg,
             String signature) throws Exception {
         initEd25519VectorsTest(name, support, prvKey, pubKey, msg, signature);
         byte[] publicSeed = support.getPublicKeyData(publicKey);
@@ -212,7 +213,7 @@ class Ed25519VectorsTest<PUB extends PublicKey, PRV extends PrivateKey> extends
     @MethodSource("parameters")
     @ParameterizedTest(name = "{0}")
     void privateKeyBytes(
-            String name, EdDSASupport<PUB, PRV> support, String provider, String prvKey, String pubKey, String msg,
+            String name, EdDSASupport support, String provider, String prvKey, String pubKey, String msg,
             String signature) throws Exception {
         initEd25519VectorsTest(name, support, prvKey, pubKey, msg, signature);
         byte[] privateSeed = support.getPrivateKeyData(privateKey);
@@ -222,7 +223,7 @@ class Ed25519VectorsTest<PUB extends PublicKey, PRV extends PrivateKey> extends
     @MethodSource("parameters")
     @ParameterizedTest(name = "{0}")
     void signature(
-            String name, EdDSASupport<PUB, PRV> support, String provider, String prvKey, String pubKey, String msg,
+            String name, EdDSASupport support, String provider, String prvKey, String pubKey, String msg,
             String signature) throws Exception {
         initEd25519VectorsTest(name, support, prvKey, pubKey, msg, signature);
         Signature signer = support.getEDDSASigner();
@@ -241,7 +242,7 @@ class Ed25519VectorsTest<PUB extends PublicKey, PRV extends PrivateKey> extends
     @MethodSource("parameters")
     @ParameterizedTest(name = "{0}")
     void partialBufferSignature(
-            String name, EdDSASupport<PUB, PRV> support, String provider, String prvKey, String pubKey, String msg,
+            String name, EdDSASupport support, String provider, String prvKey, String pubKey, String msg,
             String signature)
             throws Exception {
         initEd25519VectorsTest(name, support, prvKey, pubKey, msg, signature);
@@ -268,10 +269,10 @@ class Ed25519VectorsTest<PUB extends PublicKey, PRV extends PrivateKey> extends
     @MethodSource("parameters")
     @ParameterizedTest(name = "{0}")
     void recoverEDDSAPublicKey(
-            String name, EdDSASupport<PUB, PRV> support, String provider, String prvKey, String pubKey, String msg,
+            String name, EdDSASupport support, String provider, String prvKey, String pubKey, String msg,
             String signature) throws Exception {
         initEd25519VectorsTest(name, support, prvKey, pubKey, msg, signature);
-        PUB recoveredKey = support.recoverEDDSAPublicKey(privateKey);
+        PublicKey recoveredKey = support.recoverEDDSAPublicKey(privateKey);
         assertTrue(support.compareEDDSAPPublicKeys(publicKey, recoveredKey), "Recovered key is not equal");
         byte[] recoveredBytes = support.getPublicKeyData(recoveredKey);
         assertArrayEquals(pubBytes, recoveredBytes, "Mismatched public seed value");
@@ -280,12 +281,12 @@ class Ed25519VectorsTest<PUB extends PublicKey, PRV extends PrivateKey> extends
     @MethodSource("parameters")
     @ParameterizedTest(name = "{0}")
     void createPublicKeySpec(
-            String name, EdDSASupport<PUB, PRV> support, String provider, String prvKey, String pubKey, String msg,
+            String name, EdDSASupport support, String provider, String prvKey, String pubKey, String msg,
             String signature) throws Exception {
         initEd25519VectorsTest(name, support, prvKey, pubKey, msg, signature);
-        KeySpec keySpec = support.createPublicKeySpec(publicKey);
+        KeySpec keySpec = EdDSAUtils.createKeySpec(publicKey);
         KeyFactory keyFactory = KeyFactory.getInstance(support.getKeyFactoryAlgorithm(), provider);
-        PUB generatedKey = (PUB) keyFactory.generatePublic(keySpec);
+        PublicKey generatedKey = keyFactory.generatePublic(keySpec);
         assertTrue(support.compareEDDSAPPublicKeys(publicKey, generatedKey), "Generated key is not equal");
         byte[] generatedBytes = support.getPublicKeyData(generatedKey);
         assertArrayEquals(pubBytes, generatedBytes, "Mismatched public seed value");
@@ -294,12 +295,12 @@ class Ed25519VectorsTest<PUB extends PublicKey, PRV extends PrivateKey> extends
     @MethodSource("parameters")
     @ParameterizedTest(name = "{0}")
     void createPrivateKeySpec(
-            String name, EdDSASupport<PUB, PRV> support, String provider, String prvKey, String pubKey, String msg,
+            String name, EdDSASupport support, String provider, String prvKey, String pubKey, String msg,
             String signature) throws Exception {
         initEd25519VectorsTest(name, support, prvKey, pubKey, msg, signature);
-        KeySpec keySpec = support.createPrivateKeySpec(privateKey);
+        KeySpec keySpec = EdDSAUtils.createKeySpec(privateKey);
         KeyFactory keyFactory = KeyFactory.getInstance(support.getKeyFactoryAlgorithm(), provider);
-        PRV generatedKey = (PRV) keyFactory.generatePrivate(keySpec);
+        PrivateKey generatedKey = keyFactory.generatePrivate(keySpec);
         assertTrue(support.compareEDDSAPrivateKeys(privateKey, generatedKey), "Generated key is not equal");
         byte[] generatedBytes = support.getPrivateKeyData(generatedKey);
         assertArrayEquals(prvBytes, generatedBytes, "Mismatched private seed value");
diff --git a/sshd-core/src/test/java/org/apache/sshd/common/signature/SignatureFactoriesTest.java b/sshd-core/src/test/java/org/apache/sshd/common/signature/SignatureFactoriesTest.java
index 257563b8e..fc2072918 100644
--- a/sshd-core/src/test/java/org/apache/sshd/common/signature/SignatureFactoriesTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/common/signature/SignatureFactoriesTest.java
@@ -66,11 +66,11 @@ class SignatureFactoriesTest extends BaseTestSupport implements KeyTypeIndicator
     private String keyType;
     private int keySize;
     private boolean supported;
-    private PublicKeyEntryDecoder<?, ?> pubKeyDecoder;
+    private PublicKeyEntryDecoder pubKeyDecoder;
 
     private void initSignatureFactoriesTest(
             String keyType, NamedFactory<Signature> factory,
-            int keySize, boolean supported, PublicKeyEntryDecoder<?, ?> decoder) {
+            int keySize, boolean supported, PublicKeyEntryDecoder decoder) {
         this.keyType = ValidateUtils.checkNotNullAndNotEmpty(keyType, "No key type specified");
         if (supported) {
             Objects.requireNonNull(factory, "No signature factory provided");
@@ -100,7 +100,7 @@ class SignatureFactoriesTest extends BaseTestSupport implements KeyTypeIndicator
 
     private static void addTests(
             List<Object[]> list, String keyType, NamedFactory<Signature> factory, Collection<Integer> sizes,
-            PublicKeyEntryDecoder<?, ?> decoder) {
+            PublicKeyEntryDecoder decoder) {
         for (Integer keySize : sizes) {
             list.add(new Object[] { keyType, factory, keySize, decoder != null, decoder });
         }
@@ -154,14 +154,14 @@ class SignatureFactoriesTest extends BaseTestSupport implements KeyTypeIndicator
     @ParameterizedTest(name = "type={0}, size={2}")
     void publicKeyAuth(
             String keyType, NamedFactory<Signature> factory, int keySize, boolean supported,
-            PublicKeyEntryDecoder<?, ?> decoder) throws Exception {
+            PublicKeyEntryDecoder decoder) throws Exception {
         initSignatureFactoriesTest(keyType, factory, keySize, supported, decoder);
         Assumptions.assumeTrue(isSupported());
         testKeyPairProvider(getKeyType(), getKeySize(), pubKeyDecoder, Collections.singletonList(factory));
     }
 
     protected void testKeyPairProvider(
-            String keyName, int keySize, PublicKeyEntryDecoder<?, ?> decoder, List<NamedFactory<Signature>> signatures)
+            String keyName, int keySize, PublicKeyEntryDecoder decoder, List<NamedFactory<Signature>> signatures)
             throws Exception {
         testKeyPairProvider(keyName, () -> {
             try {
diff --git a/sshd-putty/src/main/java/org/apache/sshd/putty/AbstractPuttyKeyDecoder.java b/sshd-putty/src/main/java/org/apache/sshd/putty/AbstractPuttyKeyDecoder.java
index 9bc7106d6..e377aec7f 100644
--- a/sshd-putty/src/main/java/org/apache/sshd/putty/AbstractPuttyKeyDecoder.java
+++ b/sshd-putty/src/main/java/org/apache/sshd/putty/AbstractPuttyKeyDecoder.java
@@ -25,8 +25,6 @@ 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.security.spec.InvalidKeySpecException;
 import java.util.Arrays;
 import java.util.Base64;
@@ -50,13 +48,11 @@ import org.apache.sshd.common.util.ValidateUtils;
  * @param  <PRV> Generic private key type
  * @author       <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
-public abstract class AbstractPuttyKeyDecoder<PUB extends PublicKey, PRV extends PrivateKey>
-        extends AbstractIdentityResourceLoader<PUB, PRV>
-        implements PuttyKeyPairResourceParser<PUB, PRV> {
+public abstract class AbstractPuttyKeyDecoder extends AbstractIdentityResourceLoader implements PuttyKeyPairResourceParser {
     public static final String ENCRYPTION_HEADER = "Encryption";
 
-    protected AbstractPuttyKeyDecoder(Class<PUB> pubType, Class<PRV> prvType, Collection<String> names) {
-        super(pubType, prvType, names);
+    protected AbstractPuttyKeyDecoder(Collection<String> names) {
+        super(names);
     }
 
     @Override
diff --git a/sshd-putty/src/main/java/org/apache/sshd/putty/DSSPuttyKeyDecoder.java b/sshd-putty/src/main/java/org/apache/sshd/putty/DSSPuttyKeyDecoder.java
index 04426cd41..104bd7a28 100644
--- a/sshd-putty/src/main/java/org/apache/sshd/putty/DSSPuttyKeyDecoder.java
+++ b/sshd-putty/src/main/java/org/apache/sshd/putty/DSSPuttyKeyDecoder.java
@@ -26,8 +26,6 @@ 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;
@@ -42,11 +40,11 @@ import org.apache.sshd.common.util.security.SecurityUtils;
 /**
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
-public class DSSPuttyKeyDecoder extends AbstractPuttyKeyDecoder<DSAPublicKey, DSAPrivateKey> {
+public class DSSPuttyKeyDecoder extends AbstractPuttyKeyDecoder {
     public static final DSSPuttyKeyDecoder INSTANCE = new DSSPuttyKeyDecoder();
 
     public DSSPuttyKeyDecoder() {
-        super(DSAPublicKey.class, DSAPrivateKey.class, Collections.singletonList(KeyPairProvider.SSH_DSS));
+        super(Collections.singletonList(KeyPairProvider.SSH_DSS));
     }
 
     @Override
diff --git a/sshd-putty/src/main/java/org/apache/sshd/putty/ECDSAPuttyKeyDecoder.java b/sshd-putty/src/main/java/org/apache/sshd/putty/ECDSAPuttyKeyDecoder.java
index ce1eeb2e2..e0027fb17 100644
--- a/sshd-putty/src/main/java/org/apache/sshd/putty/ECDSAPuttyKeyDecoder.java
+++ b/sshd-putty/src/main/java/org/apache/sshd/putty/ECDSAPuttyKeyDecoder.java
@@ -25,8 +25,6 @@ import java.security.KeyFactory;
 import java.security.KeyPair;
 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;
@@ -47,11 +45,11 @@ import org.apache.sshd.common.util.security.SecurityUtils;
  *
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
-public class ECDSAPuttyKeyDecoder extends AbstractPuttyKeyDecoder<ECPublicKey, ECPrivateKey> {
+public class ECDSAPuttyKeyDecoder extends AbstractPuttyKeyDecoder {
     public static final ECDSAPuttyKeyDecoder INSTANCE = new ECDSAPuttyKeyDecoder();
 
     public ECDSAPuttyKeyDecoder() {
-        super(ECPublicKey.class, ECPrivateKey.class, ECCurves.KEY_TYPES);
+        super(ECCurves.KEY_TYPES);
     }
 
     @Override
diff --git a/sshd-putty/src/main/java/org/apache/sshd/putty/EdDSAPuttyKeyDecoder.java b/sshd-putty/src/main/java/org/apache/sshd/putty/EdDSAPuttyKeyDecoder.java
index efc0c9997..b9c6db621 100644
--- a/sshd-putty/src/main/java/org/apache/sshd/putty/EdDSAPuttyKeyDecoder.java
+++ b/sshd-putty/src/main/java/org/apache/sshd/putty/EdDSAPuttyKeyDecoder.java
@@ -38,13 +38,11 @@ import org.apache.sshd.common.util.security.SecurityUtils;
  *
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
-public class EdDSAPuttyKeyDecoder<PUB extends PublicKey, PRIV extends PrivateKey> extends AbstractPuttyKeyDecoder<PUB, PRIV> {
+public class EdDSAPuttyKeyDecoder extends AbstractPuttyKeyDecoder {
     public static final EdDSAPuttyKeyDecoder INSTANCE = new EdDSAPuttyKeyDecoder();
 
     public EdDSAPuttyKeyDecoder() {
-        super((Class<PUB>) SecurityUtils.getEdDSASupport().get().getEDDSAPublicKeyType(),
-              (Class<PRIV>) SecurityUtils.getEdDSASupport().get().getEDDSAPrivateKeyType(),
-              Collections.singletonList(KeyPairProvider.SSH_ED25519));
+        super(Collections.singletonList(KeyPairProvider.SSH_ED25519));
     }
 
     @Override
diff --git a/sshd-putty/src/main/java/org/apache/sshd/putty/PuttyKeyPairResourceParser.java b/sshd-putty/src/main/java/org/apache/sshd/putty/PuttyKeyPairResourceParser.java
index 5398940f6..d8bea1d3c 100644
--- a/sshd-putty/src/main/java/org/apache/sshd/putty/PuttyKeyPairResourceParser.java
+++ b/sshd-putty/src/main/java/org/apache/sshd/putty/PuttyKeyPairResourceParser.java
@@ -25,8 +25,6 @@ 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;
@@ -39,7 +37,7 @@ import javax.crypto.spec.IvParameterSpec;
 import javax.crypto.spec.SecretKeySpec;
 
 import org.apache.sshd.common.NamedResource;
-import org.apache.sshd.common.config.keys.IdentityResourceLoader;
+import org.apache.sshd.common.config.keys.KeyTypeNamesSupport;
 import org.apache.sshd.common.config.keys.loader.KeyPairResourceParser;
 import org.apache.sshd.common.digest.BuiltinDigests;
 import org.apache.sshd.common.util.GenericUtils;
@@ -98,8 +96,7 @@ import org.bouncycastle.crypto.params.Argon2Parameters;
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
 //CHECKSTYLE:ON
-public interface PuttyKeyPairResourceParser<PUB extends PublicKey, PRV extends PrivateKey>
-        extends IdentityResourceLoader<PUB, PRV>, KeyPairResourceParser {
+public interface PuttyKeyPairResourceParser extends KeyTypeNamesSupport, KeyPairResourceParser {
     String KEY_FILE_HEADER_PREFIX = "PuTTY-User-Key-File-";
     String PUBLIC_LINES_HEADER = "Public-Lines";
     String PRIVATE_LINES_HEADER = "Private-Lines";
diff --git a/sshd-putty/src/main/java/org/apache/sshd/putty/PuttyKeyUtils.java b/sshd-putty/src/main/java/org/apache/sshd/putty/PuttyKeyUtils.java
index 38cdeaa4d..50512bb5d 100644
--- a/sshd-putty/src/main/java/org/apache/sshd/putty/PuttyKeyUtils.java
+++ b/sshd-putty/src/main/java/org/apache/sshd/putty/PuttyKeyUtils.java
@@ -33,22 +33,22 @@ import org.apache.sshd.common.util.security.SecurityUtils;
  * @author <a href="mailto:dev@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;
 
-    public static final NavigableMap<String, PuttyKeyPairResourceParser<?, ?>> BY_KEY_TYPE;
+    public static final NavigableMap<String, PuttyKeyPairResourceParser> BY_KEY_TYPE;
 
     public static final KeyPairResourceParser DEFAULT_INSTANCE;
 
     static {
-        List<PuttyKeyPairResourceParser<?, ?>> parsers = new ArrayList<>();
+        List<PuttyKeyPairResourceParser> parsers = new ArrayList<>();
         parsers.add(RSAPuttyKeyDecoder.INSTANCE);
         parsers.add(DSSPuttyKeyDecoder.INSTANCE);
         parsers.add(ECDSAPuttyKeyDecoder.INSTANCE);
         if (SecurityUtils.isEDDSACurveSupported()) {
             parsers.add(EdDSAPuttyKeyDecoder.INSTANCE);
         }
-        NavigableMap<String, PuttyKeyPairResourceParser<?, ?>> map = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
-        for (PuttyKeyPairResourceParser<?, ?> p : parsers) {
+        NavigableMap<String, PuttyKeyPairResourceParser> map = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
+        for (PuttyKeyPairResourceParser p : parsers) {
             Collection<String> supported = p.getSupportedKeyTypes();
             for (String k : supported) {
                 map.put(k, p);
diff --git a/sshd-putty/src/main/java/org/apache/sshd/putty/RSAPuttyKeyDecoder.java b/sshd-putty/src/main/java/org/apache/sshd/putty/RSAPuttyKeyDecoder.java
index 6950ef2a3..bc687ce2f 100644
--- a/sshd-putty/src/main/java/org/apache/sshd/putty/RSAPuttyKeyDecoder.java
+++ b/sshd-putty/src/main/java/org/apache/sshd/putty/RSAPuttyKeyDecoder.java
@@ -26,8 +26,6 @@ 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;
@@ -43,11 +41,11 @@ import org.apache.sshd.common.util.security.SecurityUtils;
 /**
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
-public class RSAPuttyKeyDecoder extends AbstractPuttyKeyDecoder<RSAPublicKey, RSAPrivateKey> {
+public class RSAPuttyKeyDecoder extends AbstractPuttyKeyDecoder {
     public static final RSAPuttyKeyDecoder INSTANCE = new RSAPuttyKeyDecoder();
 
     public RSAPuttyKeyDecoder() {
-        super(RSAPublicKey.class, RSAPrivateKey.class, Collections.singletonList(KeyPairProvider.SSH_RSA));
+        super(Collections.singletonList(KeyPairProvider.SSH_RSA));
     }
 
     @Override
diff --git a/sshd-putty/src/test/java/org/apache/sshd/putty/AbstractPuttyTestSupport.java b/sshd-putty/src/test/java/org/apache/sshd/putty/AbstractPuttyTestSupport.java
index 56012a7be..ed7a839b5 100644
--- a/sshd-putty/src/test/java/org/apache/sshd/putty/AbstractPuttyTestSupport.java
+++ b/sshd-putty/src/test/java/org/apache/sshd/putty/AbstractPuttyTestSupport.java
@@ -49,13 +49,13 @@ abstract class AbstractPuttyTestSupport extends JUnitTestSupport {
     protected KeyPair testDecodeEncryptedPuttyKeyFile(
             String encryptedFile, boolean okIfMissing, String password, String keyType)
             throws IOException, GeneralSecurityException {
-        PuttyKeyPairResourceParser<?, ?> parser = PuttyKeyUtils.BY_KEY_TYPE.get(keyType);
+        PuttyKeyPairResourceParser parser = PuttyKeyUtils.BY_KEY_TYPE.get(keyType);
         assertNotNull(parser, "No parser found for key type=" + keyType);
         return testDecodeEncryptedPuttyKeyFile(encryptedFile, okIfMissing, password, parser, keyType);
     }
 
     protected KeyPair testDecodeEncryptedPuttyKeyFile(
-            String encryptedFile, boolean okIfMissing, String password, PuttyKeyPairResourceParser<?, ?> parser, String keyType)
+            String encryptedFile, boolean okIfMissing, String password, PuttyKeyPairResourceParser parser, String keyType)
             throws IOException, GeneralSecurityException {
         assumeTrue(BuiltinCiphers.aes256cbc.isSupported(), BuiltinCiphers.aes256cbc.getTransformation() + " N/A");
 
diff --git a/sshd-putty/src/test/java/org/apache/sshd/putty/PuttyKeyUtilsTest.java b/sshd-putty/src/test/java/org/apache/sshd/putty/PuttyKeyUtilsTest.java
index ca95735d3..8fae67ccc 100644
--- a/sshd-putty/src/test/java/org/apache/sshd/putty/PuttyKeyUtilsTest.java
+++ b/sshd-putty/src/test/java/org/apache/sshd/putty/PuttyKeyUtilsTest.java
@@ -54,7 +54,7 @@ class PuttyKeyUtilsTest extends AbstractPuttyTestSupport {
     private String keyType;
     private String regularFile;
     private String encryptedFile;
-    private PuttyKeyPairResourceParser<?, ?> parser;
+    private PuttyKeyPairResourceParser parser;
 
     void initPuttyKeyUtilsTest(String keyType) {
         this.keyType = keyType;
@@ -90,7 +90,7 @@ class PuttyKeyUtilsTest extends AbstractPuttyTestSupport {
             NamedResource resourceKey = NamedResource.ofName(resource);
             assertTrue(parser.canExtractKeyPairs(resourceKey, lines), resource + " - can extract key pair");
 
-            for (PuttyKeyPairResourceParser<?, ?> other : PuttyKeyUtils.BY_KEY_TYPE.values()) {
+            for (PuttyKeyPairResourceParser other : PuttyKeyUtils.BY_KEY_TYPE.values()) {
                 if (parser == other) {
                     continue;
                 }