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 1b2021fe893f62625376fb9170e80a05cc5fef44 Author: Thomas Wolf <[email protected]> AuthorDate: Fri Sep 5 01:05:42 2025 +0200 Simplify ed25519 handling A lot of ed25519 operations can actually be done in a way that does not depend on the concrete implementation (Bouncy Castle or net.i2p or even Java built-in). Public keys are encoded as X.509 and private keys as PKCS#8, and both encodings do contain the raw key bytes. Parsing these formats and extracting the key bytes is simple, so we can write keys to files or buffers easily. We can also reconstruct keys from the raw bytes by creating valid X.509 or PKCS#8 KeySpecs. The only minor hiccup is that the net.i2p provider uses non-standard algorithm names for keys and signatures. So refactor this to generally use the standard names, and let the SecurityProviderRegistrar create the SecurityEntityFactory. The EdDSASecurityProviderRegistrar can then create factories for net.i2p that replace the standard names by the net.i2p-specific algorithm names. --- .../org/apache/sshd/cli/client/SshKeyScanMain.java | 2 +- .../sshd/cli/server/SshServerCliSupport.java | 2 +- .../sshd/common/config/keys/BuiltinIdentities.java | 2 +- .../apache/sshd/common/config/keys/KeyUtils.java | 11 +- .../keys/impl/SkED25519PublicKeyEntryDecoder.java | 9 +- .../sshd/common/signature/BuiltinSignatures.java | 5 +- .../sshd/common/signature/SignatureFactory.java | 3 +- .../sshd/common/signature/SignatureSkED25519.java | 4 +- .../org/apache/sshd/common/util/buffer/Buffer.java | 22 +- .../buffer/keys/ED25519BufferPublicKeyParser.java | 4 +- .../util/security/SecurityEntityFactory.java | 10 +- .../util/security/SecurityProviderChoice.java | 7 + .../sshd/common/util/security/SecurityUtils.java | 89 ++----- .../BouncyCastleSecurityProviderRegistrar.java | 5 +- .../eddsa/Ed25519PEMResourceKeyParser.java | 4 +- .../eddsa/EdDSASecurityProviderRegistrar.java | 65 ++++- .../security/eddsa/EdDSASecurityProviderUtils.java | 41 +--- .../security/eddsa/NetI2pCryptoEdDSASupport.java | 50 ---- .../util/security/eddsa/SignatureEd25519.java | 29 ++- .../bouncycastle/BouncyCastleEdDSASupport.java | 75 ------ .../util/security/eddsa/generic/EdDSASupport.java | 92 +------ .../util/security/eddsa/generic/EdDSAUtils.java | 111 +++++++-- .../GenericEd25519PEMResourceKeyParser.java | 2 +- .../generic/GenericEd25519PublicKeyDecoder.java | 9 +- ...enericOpenSSHEd25519PrivateKeyEntryDecoder.java | 32 ++- .../eddsa/generic/GenericSignatureEd25519.java | 51 ---- .../sshd/common/config/keys/KeyRandomArtTest.java | 9 +- .../pem/PKCS8PEMResourceKeyPairParserTest.java | 4 +- .../BouncyCastleGeneratorHostKeyProviderTest.java | 4 +- .../util/security/eddsa/EDDSAProviderTest.java | 13 +- .../util/security/eddsa/Ed25519VectorsTest.java | 264 ++++++++++----------- .../eddsa/EdDSASecurityProviderRegistrarTest.java | 4 +- .../SimpleGeneratorHostKeyProviderTest.java | 2 +- .../pem/{pkcs8-eddsa.enc => pkcs8-ed25519.enc} | 0 .../pem/{pkcs8-eddsa.enc2 => pkcs8-ed25519.enc2} | 0 .../pem/{pkcs8-eddsa.pem => pkcs8-ed25519.pem} | 0 .../apache/sshd/putty/EdDSAPuttyKeyDecoder.java | 5 +- 37 files changed, 415 insertions(+), 626 deletions(-) diff --git a/sshd-cli/src/main/java/org/apache/sshd/cli/client/SshKeyScanMain.java b/sshd-cli/src/main/java/org/apache/sshd/cli/client/SshKeyScanMain.java index 0eacd4b6d..71302e2a9 100644 --- a/sshd-cli/src/main/java/org/apache/sshd/cli/client/SshKeyScanMain.java +++ b/sshd-cli/src/main/java/org/apache/sshd/cli/client/SshKeyScanMain.java @@ -574,7 +574,7 @@ public class SshKeyScanMain implements Channel, Callable<Void>, ServerKeyVerifie throw new NoSuchAlgorithmException("EDDSA curves not supported: " + keyType); } - KeyPairGenerator g = SecurityUtils.getKeyPairGenerator(SecurityUtils.EDDSA); + KeyPairGenerator g = SecurityUtils.getKeyPairGenerator(SecurityUtils.ED25519); return Collections.singletonList(g.generateKeyPair()); } else { throw new InvalidKeySpecException("Unknown key type: " + keyType); diff --git a/sshd-cli/src/main/java/org/apache/sshd/cli/server/SshServerCliSupport.java b/sshd-cli/src/main/java/org/apache/sshd/cli/server/SshServerCliSupport.java index cbd01e013..e40f44e29 100644 --- a/sshd-cli/src/main/java/org/apache/sshd/cli/server/SshServerCliSupport.java +++ b/sshd-cli/src/main/java/org/apache/sshd/cli/server/SshServerCliSupport.java @@ -110,7 +110,7 @@ public abstract class SshServerCliSupport extends CliSupport { if (BuiltinIdentities.Constants.ECDSA.equalsIgnoreCase(keyAlgorithm)) { keyAlgorithm = KeyUtils.EC_ALGORITHM; } else if (BuiltinIdentities.Constants.ED25519.equals(keyAlgorithm)) { - keyAlgorithm = SecurityUtils.EDDSA; + keyAlgorithm = SecurityUtils.ED25519; } // force re-generation of host key if not same algorithm 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 8c9afcf45..f4afc957f 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 @@ -44,7 +44,7 @@ public enum BuiltinIdentities implements Identity { 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, KeyPairProvider.SSH_ED25519) { + ED25119(Constants.ED25519, SecurityUtils.ED25519, KeyPairProvider.SSH_ED25519) { @Override public boolean isSupported() { return SecurityUtils.isEDDSACurveSupported(); 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 4ff385c73..059b3a4c3 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 @@ -807,8 +807,9 @@ public final class KeyUtils { if (curve != null) { return curve.getKeySize(); } - } else if (SecurityUtils.EDDSA.equalsIgnoreCase(key.getAlgorithm())) { - return SecurityUtils.getEDDSAKeySize(key); + } else if (SecurityUtils.EDDSA.equalsIgnoreCase(key.getAlgorithm()) + || SecurityUtils.ED25519.equalsIgnoreCase(key.getAlgorithm())) { + return 256; } return -1; @@ -886,7 +887,8 @@ public final class KeyUtils { return recoverRSAPublicKey((RSAPrivateKey) key); } else if (key instanceof DSAPrivateKey) { return recoverDSAPublicKey((DSAPrivateKey) key); - } else if ((key != null) && SecurityUtils.EDDSA.equalsIgnoreCase(key.getAlgorithm())) { + } else if ((key != null) && (SecurityUtils.EDDSA.equalsIgnoreCase(key.getAlgorithm()) + || SecurityUtils.ED25519.equalsIgnoreCase(key.getAlgorithm()))) { return SecurityUtils.recoverEDDSAPublicKey(key); } return null; @@ -902,6 +904,9 @@ public final class KeyUtils { } else if ((k1 != null) && SecurityUtils.EDDSA.equalsIgnoreCase(k1.getAlgorithm()) && (k2 != null) && SecurityUtils.EDDSA.equalsIgnoreCase(k2.getAlgorithm())) { return SecurityUtils.compareEDDSAPrivateKeys(k1, k2); + } else if ((k1 != null) && SecurityUtils.ED25519.equalsIgnoreCase(k1.getAlgorithm()) && (k2 != null) + && SecurityUtils.ED25519.equalsIgnoreCase(k2.getAlgorithm())) { + return SecurityUtils.compareEDDSAPrivateKeys(k1, k2); } return false; // either key is null or not of same class } 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 b80d644d2..2a2e90b15 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 @@ -23,7 +23,6 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.security.GeneralSecurityException; -import java.security.InvalidKeyException; import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; @@ -77,12 +76,8 @@ public class SkED25519PublicKeyEntryDecoder extends AbstractPublicKeyEntryDecode SkED25519PublicKey key = ValidateUtils.checkInstanceOf(k, SkED25519PublicKey.class, "Key must be an SkED25519PublicKey"); KeyEntryResolver.encodeString(s, KEY_TYPE); - try { - byte[] keyData = EdDSAUtils.getBytes(key.getDelegatePublicKey()); - KeyEntryResolver.writeRLEBytes(s, keyData); - } catch (InvalidKeyException e) { - throw new IOException(e.getMessage(), e); - } + byte[] keyData = EdDSAUtils.getBytes(key.getDelegatePublicKey()); + KeyEntryResolver.writeRLEBytes(s, keyData); KeyEntryResolver.encodeString(s, key.getAppName()); return KEY_TYPE; } diff --git a/sshd-common/src/main/java/org/apache/sshd/common/signature/BuiltinSignatures.java b/sshd-common/src/main/java/org/apache/sshd/common/signature/BuiltinSignatures.java index 54aea9533..bb3444351 100644 --- a/sshd-common/src/main/java/org/apache/sshd/common/signature/BuiltinSignatures.java +++ b/sshd-common/src/main/java/org/apache/sshd/common/signature/BuiltinSignatures.java @@ -44,6 +44,7 @@ import org.apache.sshd.common.keyprovider.KeyPairProvider; import org.apache.sshd.common.util.GenericUtils; import org.apache.sshd.common.util.ValidateUtils; import org.apache.sshd.common.util.security.SecurityUtils; +import org.apache.sshd.common.util.security.eddsa.SignatureEd25519; /** * Provides easy access to the currently implemented signatures @@ -197,7 +198,7 @@ public enum BuiltinSignatures implements SignatureFactory { ed25519(KeyPairProvider.SSH_ED25519) { @Override public Signature create() { - return SecurityUtils.getEDDSASigner(); + return new SignatureEd25519(); } @Override @@ -208,7 +209,7 @@ public enum BuiltinSignatures implements SignatureFactory { ed25519_cert(KeyPairProvider.SSH_ED25519_CERT) { @Override public Signature create() { - return SecurityUtils.getEDDSASigner(); + return new SignatureEd25519(); } @Override diff --git a/sshd-common/src/main/java/org/apache/sshd/common/signature/SignatureFactory.java b/sshd-common/src/main/java/org/apache/sshd/common/signature/SignatureFactory.java index 6876856e5..e2a1bf681 100644 --- a/sshd-common/src/main/java/org/apache/sshd/common/signature/SignatureFactory.java +++ b/sshd-common/src/main/java/org/apache/sshd/common/signature/SignatureFactory.java @@ -236,7 +236,8 @@ public interface SignatureFactory extends BuiltinFactory<Signature> { } else if (algo.contains("rsa")) { factory = BuiltinSignatures.fromFactoryName(algo); } - } else if (SecurityUtils.EDDSA.equalsIgnoreCase(pubKey.getAlgorithm())) { + } else if (SecurityUtils.EDDSA.equalsIgnoreCase(pubKey.getAlgorithm()) + || SecurityUtils.ED25519.equalsIgnoreCase(pubKey.getAlgorithm())) { factory = BuiltinSignatures.ed25519; } diff --git a/sshd-common/src/main/java/org/apache/sshd/common/signature/SignatureSkED25519.java b/sshd-common/src/main/java/org/apache/sshd/common/signature/SignatureSkED25519.java index 8fc0eec79..9c43ab64d 100644 --- a/sshd-common/src/main/java/org/apache/sshd/common/signature/SignatureSkED25519.java +++ b/sshd-common/src/main/java/org/apache/sshd/common/signature/SignatureSkED25519.java @@ -20,7 +20,7 @@ package org.apache.sshd.common.signature; import org.apache.sshd.common.config.keys.impl.SkED25519PublicKeyEntryDecoder; import org.apache.sshd.common.keyprovider.KeyPairProvider; -import org.apache.sshd.common.util.security.SecurityUtils; +import org.apache.sshd.common.util.security.eddsa.SignatureEd25519; public class SignatureSkED25519 extends AbstractSecurityKeySignature { @@ -42,6 +42,6 @@ public class SignatureSkED25519 extends AbstractSecurityKeySignature { @Override protected Signature getDelegateSignature() { - return SecurityUtils.getEDDSASigner(); + return new SignatureEd25519(); } } diff --git a/sshd-common/src/main/java/org/apache/sshd/common/util/buffer/Buffer.java b/sshd-common/src/main/java/org/apache/sshd/common/util/buffer/Buffer.java index ee857d6b4..de59280d7 100644 --- a/sshd-common/src/main/java/org/apache/sshd/common/util/buffer/Buffer.java +++ b/sshd-common/src/main/java/org/apache/sshd/common/util/buffer/Buffer.java @@ -72,6 +72,7 @@ import org.apache.sshd.common.util.Readable; import org.apache.sshd.common.util.buffer.keys.BufferPublicKeyParser; import org.apache.sshd.common.util.logging.SimplifiedLog; import org.apache.sshd.common.util.security.SecurityUtils; +import org.apache.sshd.common.util.security.eddsa.generic.EdDSAUtils; /** * Provides an abstract message buffer for encoding SSH messages @@ -1042,8 +1043,8 @@ public abstract class Buffer implements Readable { byte[] ecPoint = ECCurves.encodeECPoint(ecKey.getW(), ecParams); putString(curve.getName()); putBytes(ecPoint); - } else if (SecurityUtils.EDDSA.equals(key.getAlgorithm()) || SecurityUtils.ED25519.equals(key.getAlgorithm())) { - SecurityUtils.putRawEDDSAPublicKey(this, key); + } else if (KeyPairProvider.SSH_ED25519.equals(KeyUtils.getKeyType(key))) { + putBytes(EdDSAUtils.getBytes(key)); } else if (key instanceof SecurityKeyPublicKey) { putRawPublicKeyBytes(((SecurityKeyPublicKey<?>) key).getDelegatePublicKey()); putString(((SecurityKeyPublicKey<?>) key).getAppName()); @@ -1122,8 +1123,21 @@ public abstract class Buffer implements Readable { putString(curve.getName()); putBytes(ecPoint); putMPInt(ecPriv.getS()); - } else if (SecurityUtils.EDDSA.equals(pubKey.getAlgorithm())) { - SecurityUtils.putEDDSAKeyPair(this, pubKey, prvKey); + } else if (KeyPairProvider.SSH_ED25519.equals(KeyUtils.getKeyType(pubKey))) { + putString(KeyPairProvider.SSH_ED25519); + byte[] skData = null; + try { + byte[] pkData = EdDSAUtils.getBytes(pubKey); + putBytes(pkData); + skData = EdDSAUtils.getBytes(prvKey); + putUInt(pkData.length + skData.length); + putRawBytes(skData); + putRawBytes(pkData); + } finally { + if (skData != null) { + Arrays.fill(skData, (byte) 0); + } + } } else { throw new BufferException("Unsupported key pair algorithm: " + pubKey.getAlgorithm()); } diff --git a/sshd-common/src/main/java/org/apache/sshd/common/util/buffer/keys/ED25519BufferPublicKeyParser.java b/sshd-common/src/main/java/org/apache/sshd/common/util/buffer/keys/ED25519BufferPublicKeyParser.java index 5ca57cd5c..393731c30 100644 --- a/sshd-common/src/main/java/org/apache/sshd/common/util/buffer/keys/ED25519BufferPublicKeyParser.java +++ b/sshd-common/src/main/java/org/apache/sshd/common/util/buffer/keys/ED25519BufferPublicKeyParser.java @@ -25,7 +25,7 @@ import java.security.PublicKey; import org.apache.sshd.common.keyprovider.KeyPairProvider; import org.apache.sshd.common.util.ValidateUtils; 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.EdDSAUtils; /** * TODO complete this when SSHD-440 is done @@ -43,6 +43,6 @@ public class ED25519BufferPublicKeyParser extends AbstractBufferPublicKeyParser< public PublicKey getRawPublicKey(String keyType, Buffer buffer) throws GeneralSecurityException { ValidateUtils.checkTrue(isKeyTypeSupported(keyType), "Unsupported key type: %s", keyType); byte[] seed = buffer.getBytes(); - return SecurityUtils.generateEDDSAPublicKey(keyType, seed); + return EdDSAUtils.getPublicKey(seed); } } diff --git a/sshd-common/src/main/java/org/apache/sshd/common/util/security/SecurityEntityFactory.java b/sshd-common/src/main/java/org/apache/sshd/common/util/security/SecurityEntityFactory.java index badd54166..d8648cb83 100644 --- a/sshd-common/src/main/java/org/apache/sshd/common/util/security/SecurityEntityFactory.java +++ b/sshd-common/src/main/java/org/apache/sshd/common/util/security/SecurityEntityFactory.java @@ -59,16 +59,10 @@ public interface SecurityEntityFactory<T> { if (registrar == null) { if ((defaultProvider == null) || (defaultProvider == SecurityProviderChoice.EMPTY)) { return toDefaultFactory(entityType); - } else if (defaultProvider.isNamedProviderUsed()) { - return toNamedProviderFactory(entityType, defaultProvider.getProviderName()); - } else { - return toProviderInstanceFactory(entityType, defaultProvider.getSecurityProvider()); } - } else if (registrar.isNamedProviderUsed()) { - return toNamedProviderFactory(entityType, registrar.getProviderName()); - } else { - return toProviderInstanceFactory(entityType, registrar.getSecurityProvider()); + return defaultProvider.getFactory(entityType); } + return registrar.getFactory(entityType); } static <F> SecurityEntityFactory<F> toDefaultFactory(Class<F> entityType) diff --git a/sshd-common/src/main/java/org/apache/sshd/common/util/security/SecurityProviderChoice.java b/sshd-common/src/main/java/org/apache/sshd/common/util/security/SecurityProviderChoice.java index 326873b1d..1da7e6017 100644 --- a/sshd-common/src/main/java/org/apache/sshd/common/util/security/SecurityProviderChoice.java +++ b/sshd-common/src/main/java/org/apache/sshd/common/util/security/SecurityProviderChoice.java @@ -71,6 +71,13 @@ public interface SecurityProviderChoice extends NamedResource { return getName(); } + default <F> SecurityEntityFactory<F> getFactory(Class<F> entityType) throws ReflectiveOperationException { + if (isNamedProviderUsed()) { + return SecurityEntityFactory.toNamedProviderFactory(entityType, getProviderName()); + } + return SecurityEntityFactory.toProviderInstanceFactory(entityType, getSecurityProvider()); + } + /** * @return The security {@link Provider} to use in case {@link #isNamedProviderUsed()} is {@code false}. Can be * {@code null} if {@link #isNamedProviderUsed()} is {@code true}, but not recommended. 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 21fa16215..dcfb98101 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 @@ -24,7 +24,6 @@ import java.math.BigInteger; import java.nio.file.Path; import java.security.GeneralSecurityException; import java.security.InvalidKeyException; -import java.security.Key; import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; @@ -78,6 +77,7 @@ import org.apache.sshd.common.util.security.bouncycastle.BouncyCastleGeneratorHo import org.apache.sshd.common.util.security.bouncycastle.BouncyCastleKeyPairResourceParser; import org.apache.sshd.common.util.security.bouncycastle.BouncyCastleRandomFactory; import org.apache.sshd.common.util.security.eddsa.generic.EdDSASupport; +import org.apache.sshd.common.util.security.eddsa.generic.EdDSAUtils; import org.apache.sshd.common.util.threads.ThreadUtils; import org.apache.sshd.server.keyprovider.AbstractGeneratorHostKeyProvider; import org.slf4j.Logger; @@ -95,14 +95,13 @@ public final class SecurityUtils { public static final String BOUNCY_CASTLE = "BC"; /** - * EDDSA support - should match {@code EdDSAKey.KEY_ALGORITHM} + * EDDSA (net.i2p) {@link SecurityProviderRegistrar} name. */ public static final String EDDSA = "EdDSA"; - // A copy-paste from the original, but we don't want to drag the classes into the classpath - // See EdDSAEngine.SIGNATURE_ALGORITHM - public static final String CURVE_ED25519_SHA512 = "NONEwithEdDSA"; - + /** + * Key and signature algorithm name for ed25519. + */ public static final String ED25519 = "Ed25519"; /** @@ -611,28 +610,18 @@ public final class SecurityUtils { return support.get().getOpenSSHEDDSAPrivateKeyEntryDecoder(); } - public static org.apache.sshd.common.signature.Signature getEDDSASigner() { - Optional<EdDSASupport> support = getEdDSASupport(); - if (support.isPresent()) { - return support.get().getEDDSASigner(); - } - - throw new UnsupportedOperationException(EDDSA + " Signer not available"); - } - - public static int getEDDSAKeySize(Key key) { - Optional<EdDSASupport> support = getEdDSASupport(); - return support.map(edDSASupport -> edDSASupport.getEDDSAKeySize(key)).orElse(-1); - } - public static boolean compareEDDSAPPublicKeys(PublicKey k1, PublicKey k2) { - Optional<EdDSASupport> support = getEdDSASupport(); - return support.map(edDSASupport -> edDSASupport.compareEDDSAPPublicKeys(k1, k2)).orElse(false); + if (k1 == null && k2 == null) { + return true; + } + return k1 != null && k2 != null && EdDSAUtils.equals(k1, k2); } public static boolean compareEDDSAPrivateKeys(PrivateKey k1, PrivateKey k2) { - Optional<EdDSASupport> support = getEdDSASupport(); - return support.map(edDSASupport -> edDSASupport.compareEDDSAPrivateKeys(k1, k2)).orElse(false); + if (k1 == null && k2 == null) { + return true; + } + return k1 != null && k2 != null && EdDSAUtils.equals(k1, k2); } public static PublicKey recoverEDDSAPublicKey(PrivateKey key) throws GeneralSecurityException { @@ -644,54 +633,6 @@ public final class SecurityUtils { return support.get().recoverEDDSAPublicKey(key); } - public static PublicKey generateEDDSAPublicKey(String keyType, byte[] seed) throws GeneralSecurityException { - if (!KeyPairProvider.SSH_ED25519.equals(keyType)) { - throw new InvalidKeyException("Unsupported key type: " + keyType); - } - - Optional<EdDSASupport> support = getEdDSASupport(); - if (!support.isPresent()) { - throw new NoSuchAlgorithmException(EDDSA + " provider not supported"); - } - - return support.get().generateEDDSAPublicKey(seed); - } - - public static PrivateKey generateEDDSAPrivateKey(String keyType, byte[] seed) throws GeneralSecurityException, IOException { - if (!KeyPairProvider.SSH_ED25519.equals(keyType)) { - throw new InvalidKeyException("Unsupported key type: " + keyType); - } - - Optional<EdDSASupport> support = getEdDSASupport(); - if (!support.isPresent()) { - throw new NoSuchAlgorithmException(EDDSA + " provider not supported"); - } - - return support.get().generateEDDSAPrivateKey(seed); - } - - public static <B extends Buffer> B putRawEDDSAPublicKey(B buffer, PublicKey key) { - Optional<EdDSASupport> support = getEdDSASupport(); - if (!support.isPresent()) { - throw new UnsupportedOperationException(EDDSA + " provider not supported"); - } - - return support.get().putRawEDDSAPublicKey(buffer, key); - } - - public static <B extends Buffer> B putEDDSAKeyPair(B buffer, KeyPair kp) { - return putEDDSAKeyPair(buffer, Objects.requireNonNull(kp, "No key pair").getPublic(), kp.getPrivate()); - } - - public static <B extends Buffer> B putEDDSAKeyPair(B buffer, PublicKey pubKey, PrivateKey prvKey) { - Optional<EdDSASupport> support = getEdDSASupport(); - if (!support.isPresent()) { - throw new UnsupportedOperationException(EDDSA + " provider not supported"); - } - - return support.get().putEDDSAKeyPair(buffer, pubKey, prvKey); - } - public static KeyPair extractEDDSAKeyPair(Buffer buffer, String keyType) throws GeneralSecurityException { if (!KeyPairProvider.SSH_ED25519.equals(keyType)) { throw new InvalidKeyException("Unsupported key type: " + keyType); @@ -779,8 +720,8 @@ public final class SecurityUtils { } public static KeyFactory getKeyFactory(String algorithm) throws GeneralSecurityException { - SecurityEntityFactory<KeyFactory> factory - = resolveSecurityEntityFactory(KeyFactory.class, algorithm, r -> r.isKeyFactorySupported(algorithm)); + SecurityEntityFactory<KeyFactory> factory = resolveSecurityEntityFactory(KeyFactory.class, algorithm, + r -> r.isKeyFactorySupported(algorithm)); return factory.getInstance(algorithm); } 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 a5f177066..206a1e95a 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 @@ -24,7 +24,6 @@ import java.security.KeyPairGenerator; import java.security.Provider; import java.security.Security; import java.security.Signature; -import java.util.Objects; import java.util.Optional; import java.util.concurrent.atomic.AtomicReference; @@ -105,12 +104,12 @@ public class BouncyCastleSecurityProviderRegistrar extends AbstractSecurityProvi if (KeyPairGenerator.class.isAssignableFrom(entityType) || KeyFactory.class.isAssignableFrom(entityType)) { - if (Objects.compare(name, SecurityUtils.EDDSA, String.CASE_INSENSITIVE_ORDER) == 0 + if (SecurityUtils.ED25519.equalsIgnoreCase(name) && SecurityUtils.isNetI2pCryptoEdDSARegistered()) { return false; } } else if (Signature.class.isAssignableFrom(entityType)) { - if (Objects.compare(name, SecurityUtils.CURVE_ED25519_SHA512, String.CASE_INSENSITIVE_ORDER) == 0 + if (SecurityUtils.ED25519.equalsIgnoreCase(name) && SecurityUtils.isNetI2pCryptoEdDSARegistered()) { return false; } diff --git a/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/Ed25519PEMResourceKeyParser.java b/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/Ed25519PEMResourceKeyParser.java index ab64ea720..63ddddac3 100644 --- a/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/Ed25519PEMResourceKeyParser.java +++ b/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/Ed25519PEMResourceKeyParser.java @@ -55,9 +55,9 @@ public class Ed25519PEMResourceKeyParser extends GenericEd25519PEMResourceKeyPar throw new NoSuchAlgorithmException(SecurityUtils.EDDSA + " provider not supported"); } - EdDSAParameterSpec params = EdDSANamedCurveTable.getByName(EdDSASecurityProviderUtils.CURVE_ED25519_SHA512); + EdDSAParameterSpec params = EdDSANamedCurveTable.getByName(SecurityUtils.ED25519); EdDSAPrivateKeySpec keySpec = new EdDSAPrivateKeySpec(seed, params); - KeyFactory factory = SecurityUtils.getKeyFactory(SecurityUtils.EDDSA); + KeyFactory factory = SecurityUtils.getKeyFactory(SecurityUtils.ED25519); return EdDSAPrivateKey.class.cast(factory.generatePrivate(keySpec)); } } 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 7fcffd240..3697bdf24 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 @@ -18,16 +18,17 @@ */ package org.apache.sshd.common.util.security.eddsa; +import java.security.GeneralSecurityException; import java.security.KeyFactory; import java.security.KeyPairGenerator; import java.security.Provider; import java.security.Signature; -import java.util.Objects; import java.util.Optional; import java.util.concurrent.atomic.AtomicReference; import org.apache.sshd.common.util.ExceptionUtils; import org.apache.sshd.common.util.security.AbstractSecurityProviderRegistrar; +import org.apache.sshd.common.util.security.SecurityEntityFactory; import org.apache.sshd.common.util.security.SecurityUtils; import org.apache.sshd.common.util.security.eddsa.generic.EdDSASupport; import org.apache.sshd.common.util.threads.ThreadUtils; @@ -36,6 +37,7 @@ import org.apache.sshd.common.util.threads.ThreadUtils; * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> */ public class EdDSASecurityProviderRegistrar extends AbstractSecurityProviderRegistrar { + public static final String PROVIDER_CLASS = "net.i2p.crypto.eddsa.EdDSASecurityProvider"; // Do not define a static registrar instance to minimize class loading issues private final AtomicReference<Boolean> supportHolder = new AtomicReference<>(null); @@ -73,9 +75,9 @@ public class EdDSASecurityProviderRegistrar extends AbstractSecurityProviderRegi if (KeyPairGenerator.class.isAssignableFrom(entityType) || KeyFactory.class.isAssignableFrom(entityType)) { - return Objects.compare(name, getName(), String.CASE_INSENSITIVE_ORDER) == 0; + return SecurityUtils.ED25519.equalsIgnoreCase(name); } else if (Signature.class.isAssignableFrom(entityType)) { - return Objects.compare(SecurityUtils.CURVE_ED25519_SHA512, name, String.CASE_INSENSITIVE_ORDER) == 0; + return SecurityUtils.ED25519.equalsIgnoreCase(name); } else { return false; } @@ -98,6 +100,36 @@ public class EdDSASecurityProviderRegistrar extends AbstractSecurityProviderRegi return supported.booleanValue(); } + @Override + public <F> SecurityEntityFactory<F> getFactory(Class<F> entityType) throws ReflectiveOperationException { + // Return factories that map the algorithm names to the non-standard ones used by net.i2p. + // That way the rest of our code can work with the standard names. + if (KeyPairGenerator.class.isAssignableFrom(entityType) || KeyFactory.class.isAssignableFrom(entityType)) { + return new DelegatingSecurityEntityFactory<F>(super.getFactory(entityType)) { + + @Override + protected String effectiveAlgorithm(String originalAlgorithm) { + if (SecurityUtils.ED25519.equalsIgnoreCase(originalAlgorithm)) { + return "EdDSA"; + } + return originalAlgorithm; + } + }; + } else if (Signature.class.isAssignableFrom(entityType)) { + return new DelegatingSecurityEntityFactory<F>(super.getFactory(entityType)) { + + @Override + protected String effectiveAlgorithm(String originalAlgorithm) { + if (SecurityUtils.ED25519.equalsIgnoreCase(originalAlgorithm)) { + return "NONEwithEdDSA"; + } + return originalAlgorithm; + } + }; + } + return super.getFactory(entityType); + } + @Override public Optional<EdDSASupport> getEdDSASupport() { if (!isSupported()) { @@ -105,4 +137,31 @@ public class EdDSASecurityProviderRegistrar extends AbstractSecurityProviderRegi } return Optional.of(new NetI2pCryptoEdDSASupport()); } + + private static abstract class DelegatingSecurityEntityFactory<F> implements SecurityEntityFactory<F> { + + private SecurityEntityFactory<F> delegate; + + DelegatingSecurityEntityFactory(SecurityEntityFactory<F> delegate) { + this.delegate = delegate; + } + + @Override + public Class<F> getEntityType() { + return delegate.getEntityType(); + } + + @Override + public F getInstance(String algorithm) throws GeneralSecurityException { + return delegate.getInstance(effectiveAlgorithm(algorithm)); + } + + protected abstract String effectiveAlgorithm(String originalAlgorithm); + + @Override + public String toString() { + return delegate.toString(); + } + } + } 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 0c6501f87..2fe0705c6 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 @@ -32,23 +32,20 @@ import net.i2p.crypto.eddsa.EdDSAEngine; import net.i2p.crypto.eddsa.EdDSAKey; import net.i2p.crypto.eddsa.EdDSAPrivateKey; import net.i2p.crypto.eddsa.EdDSAPublicKey; -import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable; import net.i2p.crypto.eddsa.spec.EdDSAParameterSpec; -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.util.ValidateUtils; -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; +import org.apache.sshd.common.util.security.eddsa.generic.EdDSAUtils; /** * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> */ public final class EdDSASecurityProviderUtils { // See EdDSANamedCurveTable - public static final String CURVE_ED25519_SHA512 = "Ed25519"; public static final int KEY_SIZE = EdDSASupport.KEY_SIZE; private EdDSASecurityProviderUtils() { @@ -94,7 +91,7 @@ public final class EdDSASecurityProviderUtils { EdDSAPrivateKey prvKey = (EdDSAPrivateKey) key; EdDSAPublicKeySpec keySpec = new EdDSAPublicKeySpec(prvKey.getAbyte(), prvKey.getParams()); - KeyFactory factory = SecurityUtils.getKeyFactory(SecurityUtils.EDDSA); + KeyFactory factory = SecurityUtils.getKeyFactory(SecurityUtils.ED25519); return EdDSAPublicKey.class.cast(factory.generatePublic(keySpec)); } @@ -103,14 +100,6 @@ public final class EdDSASecurityProviderUtils { return new SignatureEd25519(); } - public static boolean isEDDSAKeyFactoryAlgorithm(String algorithm) { - return SecurityUtils.EDDSA.equalsIgnoreCase(algorithm); - } - - public static boolean isEDDSAKeyPairGeneratorAlgorithm(String algorithm) { - return SecurityUtils.EDDSA.equalsIgnoreCase(algorithm); - } - public static PublicKeyEntryDecoder getEDDSAPublicKeyEntryDecoder() { ValidateUtils.checkTrue(SecurityUtils.isEDDSACurveSupported(), SecurityUtils.EDDSA + " not supported"); return Ed25519PublicKeyDecoder.INSTANCE; @@ -157,10 +146,7 @@ public final class EdDSASecurityProviderUtils { throw new NoSuchAlgorithmException(SecurityUtils.EDDSA + " not supported"); } - EdDSAParameterSpec params = EdDSANamedCurveTable.getByName(CURVE_ED25519_SHA512); - EdDSAPublicKeySpec keySpec = new EdDSAPublicKeySpec(seed, params); - KeyFactory factory = SecurityUtils.getKeyFactory(SecurityUtils.EDDSA); - return factory.generatePublic(keySpec); + return EdDSAUtils.getPublicKey(seed); } public static PrivateKey generateEDDSAPrivateKey(byte[] seed) throws GeneralSecurityException { @@ -168,25 +154,6 @@ public final class EdDSASecurityProviderUtils { throw new NoSuchAlgorithmException(SecurityUtils.EDDSA + " not supported"); } - EdDSAParameterSpec params = EdDSANamedCurveTable.getByName(CURVE_ED25519_SHA512); - EdDSAPrivateKeySpec keySpec = new EdDSAPrivateKeySpec(seed, params); - KeyFactory factory = SecurityUtils.getKeyFactory(SecurityUtils.EDDSA); - return factory.generatePrivate(keySpec); - } - - public static <B extends Buffer> B putRawEDDSAPublicKey(B buffer, PublicKey key) { - ValidateUtils.checkTrue(SecurityUtils.isEDDSACurveSupported(), SecurityUtils.EDDSA + " not supported"); - EdDSAPublicKey edKey = ValidateUtils.checkInstanceOf(key, EdDSAPublicKey.class, "Not an EDDSA public key: %s", key); - byte[] seed = Ed25519PublicKeyDecoder.getSeedValue(edKey); - ValidateUtils.checkNotNull(seed, "No seed extracted from key: %s", edKey.getA()); - buffer.putBytes(seed); - return buffer; - } - - public static <B extends Buffer> B putEDDSAKeyPair(B buffer, PublicKey pubKey, PrivateKey prvKey) { - ValidateUtils.checkTrue(SecurityUtils.isEDDSACurveSupported(), SecurityUtils.EDDSA + " not supported"); - ValidateUtils.checkInstanceOf(pubKey, EdDSAPublicKey.class, "Not an EDDSA public key: %s", pubKey); - ValidateUtils.checkInstanceOf(prvKey, EdDSAPrivateKey.class, "Not an EDDSA private key: %s", prvKey); - throw new UnsupportedOperationException("Full SSHD-440 implementation N/A"); + return EdDSAUtils.getPrivateKey(seed); } } 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 3e2eae767..da8a64eee 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 @@ -20,17 +20,11 @@ package org.apache.sshd.common.util.security.eddsa; import java.security.GeneralSecurityException; -import java.security.Key; import java.security.PrivateKey; -import java.security.PublicKey; -import net.i2p.crypto.eddsa.EdDSAPrivateKey; import net.i2p.crypto.eddsa.EdDSAPublicKey; import org.apache.sshd.common.config.keys.PrivateKeyEntryDecoder; import org.apache.sshd.common.config.keys.PublicKeyEntryDecoder; -import org.apache.sshd.common.signature.Signature; -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 { @@ -49,53 +43,9 @@ public class NetI2pCryptoEdDSASupport implements EdDSASupport { return OpenSSHEd25519PrivateKeyEntryDecoder.INSTANCE; } - @Override - public Signature getEDDSASigner() { - return EdDSASecurityProviderUtils.getEDDSASignature(); - } - - @Override - public int getEDDSAKeySize(Key key) { - return EdDSASecurityProviderUtils.getEDDSAKeySize(key); - } - - @Override - public boolean compareEDDSAPPublicKeys(PublicKey k1, PublicKey k2) { - return EdDSASecurityProviderUtils.compareEDDSAPPublicKeys(k1, k2); - } - - @Override - public boolean compareEDDSAPrivateKeys(PrivateKey k1, PrivateKey k2) { - return EdDSASecurityProviderUtils.compareEDDSAPrivateKeys(k1, k2); - } - @Override public EdDSAPublicKey recoverEDDSAPublicKey(PrivateKey key) throws GeneralSecurityException { return EdDSASecurityProviderUtils.recoverEDDSAPublicKey(key); } - @Override - public EdDSAPublicKey generateEDDSAPublicKey(byte[] seed) throws GeneralSecurityException { - return (EdDSAPublicKey) EdDSASecurityProviderUtils.generateEDDSAPublicKey(seed); - } - - @Override - public EdDSAPrivateKey generateEDDSAPrivateKey(byte[] seed) throws GeneralSecurityException { - return Ed25519PEMResourceKeyParser.generateEdDSAPrivateKey(seed); - } - - @Override - public <B extends Buffer> B putRawEDDSAPublicKey(B buffer, PublicKey key) { - return EdDSASecurityProviderUtils.putRawEDDSAPublicKey(buffer, key); - } - - @Override - public <B extends Buffer> B putEDDSAKeyPair(B buffer, PublicKey pubKey, PrivateKey prvKey) { - return EdDSASecurityProviderUtils.putEDDSAKeyPair(buffer, pubKey, prvKey); - } - - @Override - public String getKeyFactoryAlgorithm() { - return SecurityUtils.EDDSA; - } } diff --git a/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/SignatureEd25519.java b/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/SignatureEd25519.java index 1c49809ea..7823acc31 100644 --- a/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/SignatureEd25519.java +++ b/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/SignatureEd25519.java @@ -18,16 +18,35 @@ */ package org.apache.sshd.common.util.security.eddsa; -import net.i2p.crypto.eddsa.EdDSAEngine; -import org.apache.sshd.common.util.security.eddsa.generic.GenericSignatureEd25519; +import java.util.Map; + +import org.apache.sshd.common.keyprovider.KeyPairProvider; +import org.apache.sshd.common.session.SessionContext; +import org.apache.sshd.common.signature.AbstractSignature; +import org.apache.sshd.common.util.ValidateUtils; +import org.apache.sshd.common.util.security.SecurityUtils; /** - * An implementation of {@link GenericSignatureEd25519} tied to the {@code net.i2p.crypto} EdDSA security provider. + * An ed25519 signature. * * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> */ -public class SignatureEd25519 extends GenericSignatureEd25519 { +public class SignatureEd25519 extends AbstractSignature { + public SignatureEd25519() { - super(EdDSAEngine.SIGNATURE_ALGORITHM); + super(SecurityUtils.ED25519, KeyPairProvider.SSH_ED25519); + } + + @Override + public boolean verify(SessionContext session, byte[] sig) throws Exception { + byte[] data = sig; + Map.Entry<String, byte[]> encoding = extractEncodedSignature(data, KeyPairProvider.SSH_ED25519::equalsIgnoreCase); + if (encoding != null) { + String keyType = encoding.getKey(); + ValidateUtils.checkTrue(KeyPairProvider.SSH_ED25519.equals(keyType), "Mismatched key type: %s", keyType); + data = encoding.getValue(); + } + + return doVerify(data); } } 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 cd8baa249..ea679e906 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 @@ -19,32 +19,18 @@ package org.apache.sshd.common.util.security.eddsa.bouncycastle; -import java.io.IOException; import java.security.GeneralSecurityException; import java.security.InvalidKeyException; -import java.security.Key; -import java.security.KeyFactory; import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.spec.PKCS8EncodedKeySpec; import org.apache.sshd.common.config.keys.PrivateKeyEntryDecoder; import org.apache.sshd.common.config.keys.PublicKeyEntryDecoder; -import org.apache.sshd.common.signature.Signature; -import org.apache.sshd.common.util.ValidateUtils; -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; import org.apache.sshd.common.util.security.eddsa.generic.GenericEd25519PublicKeyDecoder; import org.apache.sshd.common.util.security.eddsa.generic.GenericOpenSSHEd25519PrivateKeyEntryDecoder; -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.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 { @@ -62,34 +48,6 @@ public class BouncyCastleEdDSASupport implements EdDSASupport { return new GenericOpenSSHEd25519PrivateKeyEntryDecoder(this); } - @Override - public Signature getEDDSASigner() { - return new GenericSignatureEd25519(SecurityUtils.EDDSA); - } - - @Override - public int getEDDSAKeySize(Key key) { - return key instanceof EdDSAKey ? KEY_SIZE : -1; - } - - @Override - public boolean compareEDDSAPPublicKeys(PublicKey k1, PublicKey k2) { - if (!(k1 instanceof EdDSAPublicKey) || !(k2 instanceof EdDSAPublicKey)) { - return false; - } - - return k1.equals(k2); - } - - @Override - public boolean compareEDDSAPrivateKeys(PrivateKey k1, PrivateKey k2) { - if (!(k1 instanceof EdDSAPrivateKey) || !(k2 instanceof EdDSAPrivateKey)) { - return false; - } - - return k1.equals(k2); - } - @Override public EdDSAPublicKey recoverEDDSAPublicKey(PrivateKey key) throws GeneralSecurityException { if (!(key instanceof EdDSAPrivateKey)) { @@ -99,37 +57,4 @@ public class BouncyCastleEdDSASupport implements EdDSASupport { return edDSAKey.getPublicKey(); } - @Override - public EdDSAPublicKey generateEDDSAPublicKey(byte[] seed) throws GeneralSecurityException { - RawEncodedKeySpec keySpec = new RawEncodedKeySpec(seed); - KeyFactory factory = SecurityUtils.getKeyFactory(getKeyFactoryAlgorithm()); - return (EdDSAPublicKey) factory.generatePublic(keySpec); - } - - @Override - public EdDSAPrivateKey generateEDDSAPrivateKey(byte[] seed) throws GeneralSecurityException, IOException { - Ed25519PrivateKeyParameters parameters = new Ed25519PrivateKeyParameters(seed); - PrivateKeyInfo info = PrivateKeyInfoFactory.createPrivateKeyInfo(parameters); - KeyFactory factory = SecurityUtils.getKeyFactory(getKeyFactoryAlgorithm()); - return (EdDSAPrivateKey) factory.generatePrivate(new PKCS8EncodedKeySpec(info.getEncoded())); - } - - @Override - public <B extends Buffer> B putRawEDDSAPublicKey(B buffer, PublicKey key) { - EdDSAPublicKey edKey = ValidateUtils.checkInstanceOf(key, EdDSAPublicKey.class, "Not an EDDSA public key: %s", key); - buffer.putBytes(edKey.getPointEncoding()); - return buffer; - } - - @Override - public <B extends Buffer> B putEDDSAKeyPair(B buffer, PublicKey pubKey, PrivateKey prvKey) { - ValidateUtils.checkInstanceOf(pubKey, EdDSAPublicKey.class, "Not an EDDSA public key: %s", pubKey); - ValidateUtils.checkInstanceOf(prvKey, EdDSAPrivateKey.class, "Not an EDDSA private key: %s", prvKey); - throw new UnsupportedOperationException("Full SSHD-440 implementation N/A"); - } - - @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 1ccbd6b41..02ff2e18c 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,17 +22,12 @@ 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 org.apache.sshd.common.config.keys.PrivateKeyEntryDecoder; import org.apache.sshd.common.config.keys.PublicKeyEntryDecoder; -import org.apache.sshd.common.keyprovider.KeyPairProvider; -import org.apache.sshd.common.signature.Signature; -import org.apache.sshd.common.util.buffer.Buffer; import org.apache.sshd.common.util.io.der.ASN1Object; import org.apache.sshd.common.util.io.der.ASN1Type; import org.apache.sshd.common.util.io.der.DERParser; @@ -78,7 +73,7 @@ public interface EdDSASupport { throw new StreamCorruptedException("Mismatched key data container type: " + objType); } - return SecurityUtils.generateEDDSAPrivateKey(KeyPairProvider.SSH_ED25519, obj.getValue()); + return EdDSAUtils.getPrivateKey(obj.getValue()); } } @@ -92,95 +87,10 @@ public interface EdDSASupport { */ PrivateKeyEntryDecoder getOpenSSHEDDSAPrivateKeyEntryDecoder(); - /** - * @return the signature implementation associated with the security provider. - */ - Signature getEDDSASigner(); - - /** - * @param key the key to get the size of. - * @return the size of the key if it is an EdDSA key, -1 otherwise. - */ - int getEDDSAKeySize(Key key); - - /** - * @param k1 the first key - * @param k2 the second key - * @return {@code true} if both keys are instances of the public key type associated with the security provider - * and they are equal. - */ - boolean compareEDDSAPPublicKeys(PublicKey k1, PublicKey k2); - - /** - * @param k1 the first key - * @param k2 the second key - * @return {@code true} if both keys are instances of the private key type associated with the security provider - * and they are equal. - */ - boolean compareEDDSAPrivateKeys(PrivateKey k1, PrivateKey k2); - /** * @param key the private key * @return the public key associated with the private key. */ PublicKey recoverEDDSAPublicKey(PrivateKey key) throws GeneralSecurityException; - /** - * @param seed the raw public key bytes - * @return the associated public key - */ - PublicKey generateEDDSAPublicKey(byte[] seed) throws GeneralSecurityException; - - /** - * @param seed the raw private key bytes - * @return the associated private key - */ - PrivateKey generateEDDSAPrivateKey(byte[] seed) throws GeneralSecurityException, IOException; - - /** - * @param buffer the buffer to insert the public key into - * @param key the public key to be inserted into the buffer - * @return the buffer that was passed in - * @param <B> type of the buffer - */ - <B extends Buffer> B putRawEDDSAPublicKey(B buffer, PublicKey key); - - /** - * @param buffer the buffer to insert the keys into - * @param pubKey the public key to be inserted into the buffer - * @param prvKey the private key to be inserted into the buffer - * @return the buffer that was passed in - * @param <B> type of the buffer - */ - <B extends Buffer> B putEDDSAKeyPair(B buffer, PublicKey pubKey, PrivateKey prvKey); - - /** - * @param publicKey the public key - * @return the raw public key bytes associated with the key - */ - 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 - */ - 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}. - */ - String getKeyFactoryAlgorithm(); - } 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 5aa82508c..61460c46c 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 @@ -19,7 +19,9 @@ package org.apache.sshd.common.util.security.eddsa.generic; import java.io.IOException; +import java.security.GeneralSecurityException; import java.security.InvalidKeyException; +import java.security.KeyFactory; import java.security.PrivateKey; import java.security.PublicKey; import java.security.spec.KeySpec; @@ -28,10 +30,11 @@ import java.security.spec.X509EncodedKeySpec; import java.util.Arrays; import org.apache.sshd.common.util.io.der.DERParser; +import org.apache.sshd.common.util.security.SecurityUtils; /** - * 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. + * Utilities to extract the raw key bytes from ed25519 or ed448 keys or to construct such keys from the raw key bytes, + * in a manner that is independent of the actual concrete key implementation classes. * * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> */ @@ -103,18 +106,19 @@ public final class EdDSAUtils { /** * Retrieves the raw key bytes from an ed25519 or ed448 {@link PublicKey}. * - * @param key {@link PublicKey} 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 X.509 encoding + * @param key {@link PublicKey} to get the bytes of + * @return the raw key bytes + * @throws IllegalArgumentException if the key is not an ed25519 or ed448 key, or if it doesn't use X.509 encoding */ - public static byte[] getBytes(PublicKey key) throws InvalidKeyException { + public static byte[] getBytes(PublicKey key) throws IllegalArgumentException { // Extract the public key bytes from the X.509 encoding (last n bytes, depending on the OID). if (!"X.509".equalsIgnoreCase(key.getFormat())) { - throw new InvalidKeyException("Cannot extract public key bytes from a non-X.509 encoding"); + throw new IllegalArgumentException("Cannot extract public key bytes from a non-X.509 encoding"); } byte[] encoded = key.getEncoded(); if (encoded == null) { - throw new InvalidKeyException("Public key " + key.getClass().getCanonicalName() + " does not support encoding"); + throw new IllegalArgumentException( + "Public key " + key.getClass().getCanonicalName() + " does not support encoding"); } int n; if (encoded.length == ED25519_LENGTH + ED25519_X509_PREFIX.length && startsWith(encoded, ED25519_X509_PREFIX)) { @@ -122,7 +126,7 @@ public final class EdDSAUtils { } else if (encoded.length == ED448_LENGTH + ED448_X509_PREFIX.length && startsWith(encoded, ED448_X509_PREFIX)) { n = ED448_LENGTH; } else { - throw new InvalidKeyException("Public key is neither ed25519 nor ed448"); + throw new IllegalArgumentException("Public key is neither ed25519 nor ed448"); } return Arrays.copyOfRange(encoded, encoded.length - n, encoded.length); } @@ -130,18 +134,19 @@ public final class EdDSAUtils { /** * 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 + * @param key {@link PrivateKey} to get the bytes of + * @return the raw key bytes + * @throws IllegalArgumentException 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 { + public static byte[] getBytes(PrivateKey key) throws IllegalArgumentException { // 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"); + throw new IllegalArgumentException("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"); + throw new IllegalArgumentException( + "Private key " + key.getClass().getCanonicalName() + " does not support encoding"); } try { return asn1Parse(encoded); @@ -180,13 +185,13 @@ public final class EdDSAUtils { * 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> + * @param encoded encoded private key to extract the private key bytes from + * @return the extracted private key bytes + * @throws IllegalArgumentException 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 { + private static byte[] asn1Parse(byte[] encoded) throws IllegalArgumentException { byte[] privateKey = null; try (DERParser byteParser = new DERParser(encoded); DERParser oneAsymmetricKey = byteParser.readObject().createParser()) { @@ -199,7 +204,7 @@ public final class EdDSAUtils { } else if (arrayEq(ED448_OID, oid)) { n = ED448_LENGTH; } else { - throw new InvalidKeyException("Private key is neither ed25519 nor ed448"); + throw new IllegalArgumentException("Private key is neither ed25519 nor ed448"); } } privateKey = oneAsymmetricKey.readObject().getValue(); @@ -207,7 +212,7 @@ public final class EdDSAUtils { 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); + throw new IllegalArgumentException("Cannot parse EdDSA private key", e); } finally { if (privateKey != null) { Arrays.fill(privateKey, (byte) 0); @@ -287,4 +292,64 @@ public final class EdDSAUtils { throw new InvalidKeyException("Private key data is neither ed25519 nor ed448"); } + /** + * Creates a {@link PublicKey} from the raw key bytes of an ed25519 or ed448 key. + * + * @param keyData the raw key bytes + * @return the {@link PublicKey} + * @throws GeneralSecurityException if the key cannot be created + */ + public static PublicKey getPublicKey(byte[] keyData) throws GeneralSecurityException { + KeyFactory factory = SecurityUtils.getKeyFactory(SecurityUtils.ED25519); + return factory.generatePublic(createPublicKeySpec(keyData)); + } + + /** + * Creates a {@link PrivateKey} from the raw key bytes of an ed25519 or ed448 key. + * + * @param keyData the raw key bytes + * @return the {@link PrivateKey} + * @throws GeneralSecurityException if the key cannot be created + */ + public static PrivateKey getPrivateKey(byte[] keyData) throws GeneralSecurityException { + KeyFactory factory = SecurityUtils.getKeyFactory(SecurityUtils.ED25519); + return factory.generatePrivate(createPrivateKeySpec(keyData)); + } + + /** + * Compares two ed25519 or two ed448 {@link PublicKey}s. + * + * @param k1 first {@link PublicKey} + * @param k2 second {@link PublicKey} + * @return if the two keys are equal + * @throws IllegalArgumentException if one of the keys is neither an ed25519 nor an ed448 key + */ + public static boolean equals(PublicKey k1, PublicKey k2) throws IllegalArgumentException { + return arrayEq(getBytes(k1), getBytes(k2)); + } + + /** + * Compares two ed25519 or two ed448 {@link PrivateKey}s. + * + * @param k1 first {@link PrivateKey} + * @param k2 second {@link PrivateKey} + * @return if the two keys are equal + * @throws IllegalArgumentException if one of the keys is neither an ed25519 nor an ed448 key + */ + public static boolean equals(PrivateKey k1, PrivateKey k2) throws IllegalArgumentException { + byte[] k1Data = null; + byte[] k2Data = null; + try { + k1Data = getBytes(k1); + k2Data = getBytes(k2); + return arrayEq(k1Data, k2Data); + } finally { + if (k1Data != null) { + Arrays.fill(k1Data, (byte) 0); + } + if (k2Data != null) { + Arrays.fill(k2Data, (byte) 0); + } + } + } } diff --git a/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/generic/GenericEd25519PEMResourceKeyParser.java b/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/generic/GenericEd25519PEMResourceKeyParser.java index 9e4c64511..7ee7c47f2 100644 --- a/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/generic/GenericEd25519PEMResourceKeyParser.java +++ b/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/generic/GenericEd25519PEMResourceKeyParser.java @@ -64,7 +64,7 @@ public class GenericEd25519PEMResourceKeyParser extends AbstractPEMResourceKeyPa public static final GenericEd25519PEMResourceKeyParser INSTANCE = new GenericEd25519PEMResourceKeyParser(); public GenericEd25519PEMResourceKeyParser() { - super(SecurityUtils.EDDSA, ED25519_OID, BEGINNERS, ENDERS); + super(SecurityUtils.ED25519, ED25519_OID, BEGINNERS, ENDERS); } @Override 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 f3294821a..084bfe0c9 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 @@ -50,21 +50,20 @@ public class GenericEd25519PublicKeyDecoder extends AbstractPublicKeyEntryDecode @Override public KeyPairGenerator getKeyPairGenerator() throws GeneralSecurityException { - return SecurityUtils.getKeyPairGenerator(SecurityUtils.EDDSA); + return SecurityUtils.getKeyPairGenerator(SecurityUtils.ED25519); } @Override 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); - KeyEntryResolver.writeRLEBytes(s, seed); + KeyEntryResolver.writeRLEBytes(s, EdDSAUtils.getBytes(key)); return KeyPairProvider.SSH_ED25519; } @Override public KeyFactory getKeyFactoryInstance() throws GeneralSecurityException { - return SecurityUtils.getKeyFactory(SecurityUtils.EDDSA); + return SecurityUtils.getKeyFactory(SecurityUtils.ED25519); } @Override @@ -72,7 +71,7 @@ public class GenericEd25519PublicKeyDecoder extends AbstractPublicKeyEntryDecode SessionContext session, String keyType, InputStream keyData, Map<String, String> headers) throws IOException, GeneralSecurityException { byte[] seed = KeyEntryResolver.readRLEBytes(keyData, MAX_ALLOWED_SEED_LEN); - return edDSASupport.generateEDDSAPublicKey(seed); + return EdDSAUtils.getPublicKey(seed); } } 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 62dec443b..e1285fb55 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 @@ -96,10 +96,10 @@ public class GenericOpenSSHEd25519PrivateKeyEntryDecoder extends AbstractPrivate } byte[] sk = Arrays.copyOf(keypair, SK_SIZE); - PrivateKey privateKey = edDSASupport.generateEDDSAPrivateKey(sk); + PrivateKey privateKey = EdDSAUtils.getPrivateKey(sk); // we can now verify the generated pk matches the one we read - if (!Arrays.equals(edDSASupport.getPublicKeyData(recoverPublicKey(privateKey)), pk)) { + if (!Arrays.equals(EdDSAUtils.getBytes(recoverPublicKey(privateKey)), pk)) { throw new InvalidKeyException("The provided pk does NOT match the computed pk for the given sk."); } @@ -120,18 +120,24 @@ public class GenericOpenSSHEd25519PrivateKeyEntryDecoder extends AbstractPrivate // we are expected to write the following arrays (type:size): // [pk:32], [sk:32,pk:32] - byte[] sk = edDSASupport.getPrivateKeyData(key); - byte[] pk = edDSASupport.getPublicKeyData(pubKey); - - Objects.requireNonNull(sk, "No seed"); + byte[] sk = null; + try { + byte[] pk = EdDSAUtils.getBytes(pubKey); + sk = EdDSAUtils.getBytes(key); - byte[] keypair = new byte[KEYPAIR_SIZE]; - System.arraycopy(sk, 0, keypair, 0, SK_SIZE); - System.arraycopy(pk, 0, keypair, SK_SIZE, PK_SIZE); + Objects.requireNonNull(sk, "No seed"); - KeyEntryResolver.writeRLEBytes(s, pk); - KeyEntryResolver.writeRLEBytes(s, keypair); + byte[] keypair = new byte[KEYPAIR_SIZE]; + System.arraycopy(sk, 0, keypair, 0, SK_SIZE); + System.arraycopy(pk, 0, keypair, SK_SIZE, PK_SIZE); + KeyEntryResolver.writeRLEBytes(s, pk); + KeyEntryResolver.writeRLEBytes(s, keypair); + } finally { + if (sk != null) { + Arrays.fill(sk, (byte) 0); + } + } return KeyPairProvider.SSH_ED25519; } @@ -147,11 +153,11 @@ public class GenericOpenSSHEd25519PrivateKeyEntryDecoder extends AbstractPrivate @Override public KeyPairGenerator getKeyPairGenerator() throws GeneralSecurityException { - return SecurityUtils.getKeyPairGenerator(SecurityUtils.EDDSA); + return SecurityUtils.getKeyPairGenerator(SecurityUtils.ED25519); } @Override public KeyFactory getKeyFactoryInstance() throws GeneralSecurityException { - return SecurityUtils.getKeyFactory(SecurityUtils.EDDSA); + return SecurityUtils.getKeyFactory(SecurityUtils.ED25519); } } diff --git a/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/generic/GenericSignatureEd25519.java b/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/generic/GenericSignatureEd25519.java deleted file mode 100644 index 943c473d5..000000000 --- a/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/generic/GenericSignatureEd25519.java +++ /dev/null @@ -1,51 +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.util.security.eddsa.generic; - -import java.util.Map; - -import org.apache.sshd.common.keyprovider.KeyPairProvider; -import org.apache.sshd.common.session.SessionContext; -import org.apache.sshd.common.signature.AbstractSignature; -import org.apache.sshd.common.util.ValidateUtils; - -/** - * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> - */ -public class GenericSignatureEd25519 extends AbstractSignature { - - public GenericSignatureEd25519(String algorithm) { - super(algorithm, KeyPairProvider.SSH_ED25519); - } - - @Override - public boolean verify(SessionContext session, byte[] sig) throws Exception { - byte[] data = sig; - Map.Entry<String, byte[]> encoding - = extractEncodedSignature(data, KeyPairProvider.SSH_ED25519::equalsIgnoreCase); - if (encoding != null) { - String keyType = encoding.getKey(); - ValidateUtils.checkTrue( - KeyPairProvider.SSH_ED25519.equals(keyType), "Mismatched key type: %s", keyType); - data = encoding.getValue(); - } - - return doVerify(data); - } -} diff --git a/sshd-common/src/test/java/org/apache/sshd/common/config/keys/KeyRandomArtTest.java b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/KeyRandomArtTest.java index febcf9e33..761c0a4bc 100644 --- a/sshd-common/src/test/java/org/apache/sshd/common/config/keys/KeyRandomArtTest.java +++ b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/KeyRandomArtTest.java @@ -61,7 +61,7 @@ class KeyRandomArtTest extends JUnitTestSupport { if (SecurityUtils.isEDDSACurveSupported()) { for (int keySize : ED25519_SIZES) { - params.add(new Object[] { SecurityUtils.EDDSA, keySize }); + params.add(new Object[] { SecurityUtils.ED25519, keySize }); } } return params; @@ -78,7 +78,12 @@ class KeyRandomArtTest extends JUnitTestSupport { KeyPair keyPair = CommonTestSupportUtils.generateKeyPair(algorithm, keySize); KEYS.add(keyPair); KeyRandomArt art = new KeyRandomArt(keyPair.getPublic()); - assertEquals(algorithm, art.getAlgorithm(), "Mismatched algorithm"); + if (SecurityUtils.ED25519.equals(algorithm)) { + assertTrue(SecurityUtils.ED25519.equals(art.getAlgorithm()) || SecurityUtils.EDDSA.equals(art.getAlgorithm()), + "Mismatched algorithm"); + } else { + assertEquals(algorithm, art.getAlgorithm(), "Mismatched algorithm"); + } assertEquals(keySize, art.getKeySize(), "Mismatched key size"); String s = art.toString(); diff --git a/sshd-common/src/test/java/org/apache/sshd/common/config/keys/loader/pem/PKCS8PEMResourceKeyPairParserTest.java b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/loader/pem/PKCS8PEMResourceKeyPairParserTest.java index d81e4347b..b162a425a 100644 --- a/sshd-common/src/test/java/org/apache/sshd/common/config/keys/loader/pem/PKCS8PEMResourceKeyPairParserTest.java +++ b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/loader/pem/PKCS8PEMResourceKeyPairParserTest.java @@ -72,7 +72,7 @@ class PKCS8PEMResourceKeyPairParserTest extends JUnitTestSupport { params.add(new Object[] { KeyUtils.EC_ALGORITHM, curve.getKeySize() }); } if (SecurityUtils.isEDDSACurveSupported()) { - params.add(new Object[] { SecurityUtils.EDDSA, 0 }); + params.add(new Object[] { SecurityUtils.ED25519, 0 }); } return params; } @@ -149,7 +149,7 @@ class PKCS8PEMResourceKeyPairParserTest extends JUnitTestSupport { // https://github.com/bcgit/bc-java/issues/1238#issuecomment-1263162809 and has a // different password. Unknown how it was generated; openssl always writes the // RFC 5958 EncryptedPrivateKeyInfo. - String password = "eddsa".equalsIgnoreCase(algorithm) ? "Vjvyhfngz0MCUs$kwOF0" : "test"; + String password = "ed25519".equalsIgnoreCase(algorithm) ? "Vjvyhfngz0MCUs$kwOF0" : "test"; Collection<KeyPair> pairs = PEMResourceParserUtils.PROXY.loadKeyPairs(null, url, (s, r, i) -> password); assertEquals(1, GenericUtils.size(pairs), "Mismatched extract keys count"); validateKeyPairSignable(algorithm + "/" + keySize, GenericUtils.head(pairs)); diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/security/bouncycastle/BouncyCastleGeneratorHostKeyProviderTest.java b/sshd-common/src/test/java/org/apache/sshd/common/util/security/bouncycastle/BouncyCastleGeneratorHostKeyProviderTest.java index dd9cb02a0..58f9aeede 100644 --- a/sshd-common/src/test/java/org/apache/sshd/common/util/security/bouncycastle/BouncyCastleGeneratorHostKeyProviderTest.java +++ b/sshd-common/src/test/java/org/apache/sshd/common/util/security/bouncycastle/BouncyCastleGeneratorHostKeyProviderTest.java @@ -85,7 +85,7 @@ class BouncyCastleGeneratorHostKeyProviderTest extends JUnitTestSupport { assertNotNull(curve, "No curve for key size=" + keySize); expected = KeyUtils.generateKeyPair(curve.getKeyType(), curve.getKeySize()); } else if (BuiltinIdentities.Constants.ED25519.equalsIgnoreCase(keyType)) { - KeyPairGenerator g = SecurityUtils.getKeyPairGenerator(SecurityUtils.EDDSA); + KeyPairGenerator g = SecurityUtils.getKeyPairGenerator(SecurityUtils.ED25519); expected = g.generateKeyPair(); } else { throw new InvalidKeyException("Unsupported key type: " + keyType); @@ -96,7 +96,7 @@ class BouncyCastleGeneratorHostKeyProviderTest extends JUnitTestSupport { if (BuiltinIdentities.Constants.ECDSA.equalsIgnoreCase(keyAlgorithm)) { keyAlgorithm = KeyUtils.EC_ALGORITHM; } else if (BuiltinIdentities.Constants.ED25519.equalsIgnoreCase(keyAlgorithm)) { - keyAlgorithm = SecurityUtils.EDDSA; + keyAlgorithm = SecurityUtils.ED25519; } Path dir = getTempTargetFolder(); diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/security/eddsa/EDDSAProviderTest.java b/sshd-common/src/test/java/org/apache/sshd/common/util/security/eddsa/EDDSAProviderTest.java index 32d51fc6c..572c7ea32 100644 --- a/sshd-common/src/test/java/org/apache/sshd/common/util/security/eddsa/EDDSAProviderTest.java +++ b/sshd-common/src/test/java/org/apache/sshd/common/util/security/eddsa/EDDSAProviderTest.java @@ -27,7 +27,6 @@ import java.security.PrivateKey; import java.security.PublicKey; import java.security.Signature; -import net.i2p.crypto.eddsa.EdDSAEngine; import org.apache.sshd.common.config.keys.AuthorizedKeyEntry; import org.apache.sshd.common.config.keys.KeyUtils; import org.apache.sshd.common.keyprovider.KeyPairProvider; @@ -57,7 +56,7 @@ class EDDSAProviderTest extends JUnitTestSupport { @BeforeAll static void checkProviderSupported() throws GeneralSecurityException { Assumptions.assumeTrue(SecurityUtils.isEDDSACurveSupported(), SecurityUtils.EDDSA + " not supported"); - KeyPairGenerator g = SecurityUtils.getKeyPairGenerator(SecurityUtils.EDDSA); + KeyPairGenerator g = SecurityUtils.getKeyPairGenerator(SecurityUtils.ED25519); assertNotNull(g, "No generator instance"); keyPair = g.generateKeyPair(); @@ -65,7 +64,8 @@ class EDDSAProviderTest extends JUnitTestSupport { PublicKey pubKey = keyPair.getPublic(); assertNotNull(pubKey, "No public key"); - assertEquals(SecurityUtils.EDDSA, pubKey.getAlgorithm(), "Mismatched public key algorithm"); + String algo = pubKey.getAlgorithm(); + assertTrue(SecurityUtils.EDDSA.equals(algo) || SecurityUtils.ED25519.equals(algo), "Mismatched public key algorithm"); assertEquals(KeyPairProvider.SSH_ED25519, KeyUtils.getKeyType(pubKey), "Mismatched public key type"); PrivateKey prvKey = keyPair.getPrivate(); @@ -76,7 +76,7 @@ class EDDSAProviderTest extends JUnitTestSupport { @Test void signature() throws GeneralSecurityException { - Signature s = SecurityUtils.getSignature(EdDSAEngine.SIGNATURE_ALGORITHM); + Signature s = SecurityUtils.getSignature(SecurityUtils.ED25519); assertNotNull(s, "No signature instance"); s.initSign(keyPair.getPrivate()); @@ -84,7 +84,7 @@ class EDDSAProviderTest extends JUnitTestSupport { s.update(data); byte[] signed = s.sign(); - s = SecurityUtils.getSignature(EdDSAEngine.SIGNATURE_ALGORITHM); + s = SecurityUtils.getSignature(SecurityUtils.ED25519); s.initVerify(keyPair.getPublic()); s.update(data); assertTrue(s.verify(signed), "Failed to verify"); @@ -114,7 +114,8 @@ class EDDSAProviderTest extends JUnitTestSupport { private void testPublicKeyRecovery(PublicKey pubKey) throws IOException, GeneralSecurityException { assertNotNull(pubKey, "No public key generated"); - assertEquals(SecurityUtils.EDDSA, pubKey.getAlgorithm(), "Mismatched public key algorithm"); + String algo = pubKey.getAlgorithm(); + assertTrue(SecurityUtils.EDDSA.equals(algo) || SecurityUtils.ED25519.equals(algo), "Mismatched public key algorithm"); ByteArrayBuffer buf = new ByteArrayBuffer(); buf.putRawPublicKey(pubKey); 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 673644668..a7deabcd0 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 @@ -27,14 +27,12 @@ import java.security.PrivateKey; import java.security.PublicKey; import java.security.spec.KeySpec; import java.util.ArrayList; -import java.util.LinkedHashMap; import java.util.List; -import java.util.Map; import org.apache.sshd.common.signature.Signature; import org.apache.sshd.common.util.buffer.BufferUtils; +import org.apache.sshd.common.util.security.SecurityProviderRegistrar; 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; @@ -53,7 +51,7 @@ import org.junit.jupiter.params.provider.MethodSource; */ @TestMethodOrder(MethodName.class) // see https://github.com/junit-team/junit/wiki/Parameterized-tests @Tag("NoIoTestCase") -class Ed25519VectorsTest<PUB extends PublicKey, PRV extends PrivateKey> extends JUnitTestSupport { +class Ed25519VectorsTest extends JUnitTestSupport { private byte[] prvBytes; private PrivateKey privateKey; @@ -66,132 +64,111 @@ class Ed25519VectorsTest<PUB extends PublicKey, PRV extends PrivateKey> extends 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()); + privateKey = EdDSAUtils.getPrivateKey(prvBytes.clone()); pubBytes = BufferUtils.decodeHex(BufferUtils.EMPTY_HEX_SEPARATOR, pubKey); - publicKey = support.generateEDDSAPublicKey(pubBytes.clone()); + publicKey = EdDSAUtils.getPublicKey(pubBytes.clone()); msgBytes = BufferUtils.decodeHex(BufferUtils.EMPTY_HEX_SEPARATOR, msg); expSignature = BufferUtils.decodeHex(BufferUtils.EMPTY_HEX_SEPARATOR, signature); } static List<Object[]> parameters() { List<Object[]> parameters = new ArrayList<>(); - 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()) { - String supportClassName = entry.getValue().getClass().getSimpleName(); - parameters.add(new Object[] { - supportClassName + " TEST1 - empty message", - entry.getValue(), - entry.getKey(), - "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", - "d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a", - "", - "e5564300c360ac729086e2cc806e828a" - + "84877f1eb8e5d974d873e06522490155" - + "5fb8821590a33bacc61e39701cf9b46b" - + "d25bf5f0595bbe24655141438e7a100b" - }); - parameters.add(new Object[] { - supportClassName + " TEST2 - one byte", - entry.getValue(), - entry.getKey(), - "4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb", - "3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c", - "72", - "92a009a9f0d4cab8720e820b5f642540" - + "a2b27b5416503f8fb3762223ebdb69da" - + "085ac1e43e15996e458f3613d0f11d8c" - + "387b2eaeb4302aeeb00d291612bb0c00" - }); - parameters.add(new Object[] { - supportClassName + " TEST3 - 2 bytes", - entry.getValue(), - entry.getKey(), - "c5aa8df43f9f837bedb7442f31dcb7b166d38535076f094b85ce3a2e0b4458f7", - "fc51cd8e6218a1a38da47ed00230f0580816ed13ba3303ac5deb911548908025", - "af82", - "6291d657deec24024827e69c3abe01a3" - + "0ce548a284743a445e3680d7db5ac3ac" - + "18ff9b538d16f290ae67f760984dc659" - + "4a7c15e9716ed28dc027beceea1ec40a" - }); - parameters.add(new Object[] { - supportClassName + " TEST1024 - large message", - entry.getValue(), - entry.getKey(), - "f5e5767cf153319517630f226876b86c8160cc583bc013744c6bf255f5cc0ee5", - "278117fc144c72340f67d0f2316e8386ceffbf2b2428c9c51fef7c597f1d426e", - "08b8b2b733424243760fe426a4b54908" - + "632110a66c2f6591eabd3345e3e4eb98" - + "fa6e264bf09efe12ee50f8f54e9f77b1" - + "e355f6c50544e23fb1433ddf73be84d8" - + "79de7c0046dc4996d9e773f4bc9efe57" - + "38829adb26c81b37c93a1b270b20329d" - + "658675fc6ea534e0810a4432826bf58c" - + "941efb65d57a338bbd2e26640f89ffbc" - + "1a858efcb8550ee3a5e1998bd177e93a" - + "7363c344fe6b199ee5d02e82d522c4fe" - + "ba15452f80288a821a579116ec6dad2b" - + "3b310da903401aa62100ab5d1a36553e" - + "06203b33890cc9b832f79ef80560ccb9" - + "a39ce767967ed628c6ad573cb116dbef" - + "efd75499da96bd68a8a97b928a8bbc10" - + "3b6621fcde2beca1231d206be6cd9ec7" - + "aff6f6c94fcd7204ed3455c68c83f4a4" - + "1da4af2b74ef5c53f1d8ac70bdcb7ed1" - + "85ce81bd84359d44254d95629e9855a9" - + "4a7c1958d1f8ada5d0532ed8a5aa3fb2" - + "d17ba70eb6248e594e1a2297acbbb39d" - + "502f1a8c6eb6f1ce22b3de1a1f40cc24" - + "554119a831a9aad6079cad88425de6bd" - + "e1a9187ebb6092cf67bf2b13fd65f270" - + "88d78b7e883c8759d2c4f5c65adb7553" - + "878ad575f9fad878e80a0c9ba63bcbcc" - + "2732e69485bbc9c90bfbd62481d9089b" - + "eccf80cfe2df16a2cf65bd92dd597b07" - + "07e0917af48bbb75fed413d238f5555a" - + "7a569d80c3414a8d0859dc65a46128ba" - + "b27af87a71314f318c782b23ebfe808b" - + "82b0ce26401d2e22f04d83d1255dc51a" - + "ddd3b75a2b1ae0784504df543af8969b" - + "e3ea7082ff7fc9888c144da2af58429e" - + "c96031dbcad3dad9af0dcbaaaf268cb8" - + "fcffead94f3c7ca495e056a9b47acdb7" - + "51fb73e666c6c655ade8297297d07ad1" - + "ba5e43f1bca32301651339e22904cc8c" - + "42f58c30c04aafdb038dda0847dd988d" - + "cda6f3bfd15c4b4c4525004aa06eeff8" - + "ca61783aacec57fb3d1f92b0fe2fd1a8" - + "5f6724517b65e614ad6808d6f6ee34df" - + "f7310fdc82aebfd904b01e1dc54b2927" - + "094b2db68d6f903b68401adebf5a7e08" - + "d78ff4ef5d63653a65040cf9bfd4aca7" - + "984a74d37145986780fc0b16ac451649" - + "de6188a7dbdf191f64b5fc5e2ab47b57" - + "f7f7276cd419c17a3ca8e1b939ae49e4" - + "88acba6b965610b5480109c8b17b80e1" - + "b7b750dfc7598d5d5011fd2dcc5600a3" - + "2ef5b52a1ecc820e308aa342721aac09" - + "43bf6686b64b2579376504ccc493d97e" - + "6aed3fb0f9cd71a43dd497f01f17c0e2" - + "cb3797aa2a2f256656168e6c496afc5f" - + "b93246f6b1116398a346f1a641f3b041" - + "e989f7914f90cc2c7fff357876e506b5" - + "0d334ba77c225bc307ba537152f3f161" - + "0e4eafe595f6d9d90d11faa933a15ef1" - + "369546868a7f3a45a96768d40fd9d034" - + "12c091c6315cf4fde7cb68606937380d" - + "b2eaaa707b4c4185c32eddcdd306705e" - + "4dc1ffc872eeee475a64dfac86aba41c" - + "0618983f8741c5ef68d3a101e8a3b8ca" - + "c60c905c15fc910840b94c00a0b9d0", - "0aab4c900501b3e24d7cdf4663326a3a" - + "87df5e4843b2cbdb67cbf6e460fec350" - + "aa5371b1508f9f4528ecea23c436d94b" - + "5e8fcd4f681e30a6ac00a9704a188a03" - }); + SecurityProviderRegistrar registrar = SecurityUtils.getRegisteredProvider(SecurityUtils.EDDSA); + if (registrar == null) { + registrar = SecurityUtils.getRegisteredProvider(SecurityUtils.BOUNCY_CASTLE); } + if (registrar == null) { + throw new IllegalStateException("Neither net.i2p nor BC registered"); + } + EdDSASupport support = registrar.getEdDSASupport().orElseThrow(() -> new IllegalStateException("No EdDSA support")); + String supportClassName = support.getClass().getSimpleName(); + parameters.add(new Object[] { + supportClassName + " TEST1 - empty message", support, + "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", + "d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a", "", + "e5564300c360ac729086e2cc806e828a" + "84877f1eb8e5d974d873e06522490155" + "5fb8821590a33bacc61e39701cf9b46b" + + "d25bf5f0595bbe24655141438e7a100b" }); + parameters.add(new Object[] { + supportClassName + " TEST2 - one byte", support, + "4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb", + "3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c", "72", + "92a009a9f0d4cab8720e820b5f642540" + "a2b27b5416503f8fb3762223ebdb69da" + "085ac1e43e15996e458f3613d0f11d8c" + + "387b2eaeb4302aeeb00d291612bb0c00" }); + parameters.add(new Object[] { + supportClassName + " TEST3 - 2 bytes", support, + "c5aa8df43f9f837bedb7442f31dcb7b166d38535076f094b85ce3a2e0b4458f7", + "fc51cd8e6218a1a38da47ed00230f0580816ed13ba3303ac5deb911548908025", "af82", + "6291d657deec24024827e69c3abe01a3" + "0ce548a284743a445e3680d7db5ac3ac" + "18ff9b538d16f290ae67f760984dc659" + + "4a7c15e9716ed28dc027beceea1ec40a" }); + parameters.add(new Object[] { + supportClassName + " TEST1024 - large message", support, + "f5e5767cf153319517630f226876b86c8160cc583bc013744c6bf255f5cc0ee5", + "278117fc144c72340f67d0f2316e8386ceffbf2b2428c9c51fef7c597f1d426e", + "08b8b2b733424243760fe426a4b54908" + "632110a66c2f6591eabd3345e3e4eb98" + "fa6e264bf09efe12ee50f8f54e9f77b1" + + "e355f6c50544e23fb1433ddf73be84d8" + + "79de7c0046dc4996d9e773f4bc9efe57" + + "38829adb26c81b37c93a1b270b20329d" + + "658675fc6ea534e0810a4432826bf58c" + + "941efb65d57a338bbd2e26640f89ffbc" + + "1a858efcb8550ee3a5e1998bd177e93a" + + "7363c344fe6b199ee5d02e82d522c4fe" + + "ba15452f80288a821a579116ec6dad2b" + + "3b310da903401aa62100ab5d1a36553e" + + "06203b33890cc9b832f79ef80560ccb9" + + "a39ce767967ed628c6ad573cb116dbef" + + "efd75499da96bd68a8a97b928a8bbc10" + + "3b6621fcde2beca1231d206be6cd9ec7" + + "aff6f6c94fcd7204ed3455c68c83f4a4" + + "1da4af2b74ef5c53f1d8ac70bdcb7ed1" + + "85ce81bd84359d44254d95629e9855a9" + + "4a7c1958d1f8ada5d0532ed8a5aa3fb2" + + "d17ba70eb6248e594e1a2297acbbb39d" + + "502f1a8c6eb6f1ce22b3de1a1f40cc24" + + "554119a831a9aad6079cad88425de6bd" + + "e1a9187ebb6092cf67bf2b13fd65f270" + + "88d78b7e883c8759d2c4f5c65adb7553" + + "878ad575f9fad878e80a0c9ba63bcbcc" + + "2732e69485bbc9c90bfbd62481d9089b" + + "eccf80cfe2df16a2cf65bd92dd597b07" + + "07e0917af48bbb75fed413d238f5555a" + + "7a569d80c3414a8d0859dc65a46128ba" + + "b27af87a71314f318c782b23ebfe808b" + + "82b0ce26401d2e22f04d83d1255dc51a" + + "ddd3b75a2b1ae0784504df543af8969b" + + "e3ea7082ff7fc9888c144da2af58429e" + + "c96031dbcad3dad9af0dcbaaaf268cb8" + + "fcffead94f3c7ca495e056a9b47acdb7" + + "51fb73e666c6c655ade8297297d07ad1" + + "ba5e43f1bca32301651339e22904cc8c" + + "42f58c30c04aafdb038dda0847dd988d" + + "cda6f3bfd15c4b4c4525004aa06eeff8" + + "ca61783aacec57fb3d1f92b0fe2fd1a8" + + "5f6724517b65e614ad6808d6f6ee34df" + + "f7310fdc82aebfd904b01e1dc54b2927" + + "094b2db68d6f903b68401adebf5a7e08" + + "d78ff4ef5d63653a65040cf9bfd4aca7" + + "984a74d37145986780fc0b16ac451649" + + "de6188a7dbdf191f64b5fc5e2ab47b57" + + "f7f7276cd419c17a3ca8e1b939ae49e4" + + "88acba6b965610b5480109c8b17b80e1" + + "b7b750dfc7598d5d5011fd2dcc5600a3" + + "2ef5b52a1ecc820e308aa342721aac09" + + "43bf6686b64b2579376504ccc493d97e" + + "6aed3fb0f9cd71a43dd497f01f17c0e2" + + "cb3797aa2a2f256656168e6c496afc5f" + + "b93246f6b1116398a346f1a641f3b041" + + "e989f7914f90cc2c7fff357876e506b5" + + "0d334ba77c225bc307ba537152f3f161" + + "0e4eafe595f6d9d90d11faa933a15ef1" + + "369546868a7f3a45a96768d40fd9d034" + + "12c091c6315cf4fde7cb68606937380d" + + "b2eaaa707b4c4185c32eddcdd306705e" + + "4dc1ffc872eeee475a64dfac86aba41c" + + "0618983f8741c5ef68d3a101e8a3b8ca" + + "c60c905c15fc910840b94c00a0b9d0", + "0aab4c900501b3e24d7cdf4663326a3a" + "87df5e4843b2cbdb67cbf6e460fec350" + "aa5371b1508f9f4528ecea23c436d94b" + + "5e8fcd4f681e30a6ac00a9704a188a03" + }); return parameters; } @@ -203,37 +180,37 @@ class Ed25519VectorsTest<PUB extends PublicKey, PRV extends PrivateKey> extends @MethodSource("parameters") @ParameterizedTest(name = "{0}") void publicKeyBytes( - String name, EdDSASupport support, String provider, String prvKey, String pubKey, String msg, + String name, EdDSASupport support, String prvKey, String pubKey, String msg, String signature) throws Exception { initEd25519VectorsTest(name, support, prvKey, pubKey, msg, signature); - byte[] publicSeed = support.getPublicKeyData(publicKey); + byte[] publicSeed = EdDSAUtils.getBytes(publicKey); assertArrayEquals(pubBytes, publicSeed, "Mismatched public seed value"); } @MethodSource("parameters") @ParameterizedTest(name = "{0}") void privateKeyBytes( - String name, EdDSASupport support, String provider, String prvKey, String pubKey, String msg, + String name, EdDSASupport support, String prvKey, String pubKey, String msg, String signature) throws Exception { initEd25519VectorsTest(name, support, prvKey, pubKey, msg, signature); - byte[] privateSeed = support.getPrivateKeyData(privateKey); + byte[] privateSeed = EdDSAUtils.getBytes(privateKey); assertArrayEquals(prvBytes, privateSeed, "Mismatched private seed value"); } @MethodSource("parameters") @ParameterizedTest(name = "{0}") void signature( - String name, EdDSASupport support, String provider, String prvKey, String pubKey, String msg, + String name, EdDSASupport support, String prvKey, String pubKey, String msg, String signature) throws Exception { initEd25519VectorsTest(name, support, prvKey, pubKey, msg, signature); - Signature signer = support.getEDDSASigner(); + Signature signer = new SignatureEd25519(); signer.initSigner(null, privateKey); signer.update(null, msgBytes.clone()); byte[] actSignature = signer.sign(null); assertArrayEquals(expSignature, actSignature, "Mismatched signature"); - Signature verifier = support.getEDDSASigner(); + Signature verifier = new SignatureEd25519(); verifier.initVerifier(null, publicKey); verifier.update(null, msgBytes.clone()); assertTrue(verifier.verify(null, expSignature), "Verification failed"); @@ -242,7 +219,7 @@ class Ed25519VectorsTest<PUB extends PublicKey, PRV extends PrivateKey> extends @MethodSource("parameters") @ParameterizedTest(name = "{0}") void partialBufferSignature( - String name, EdDSASupport support, String provider, String prvKey, String pubKey, String msg, + String name, EdDSASupport support, String prvKey, String pubKey, String msg, String signature) throws Exception { initEd25519VectorsTest(name, support, prvKey, pubKey, msg, signature); @@ -253,14 +230,14 @@ class Ed25519VectorsTest<PUB extends PublicKey, PRV extends PrivateKey> extends System.arraycopy(msgBytes, 0, dataBuf, offset, msgBytes.length); System.arraycopy(extraData, offset, dataBuf, offset + msgBytes.length, extraData.length - offset); - Signature signer = support.getEDDSASigner(); + Signature signer = new SignatureEd25519(); signer.initSigner(null, privateKey); signer.update(null, dataBuf.clone(), offset, msgBytes.length); byte[] actSignature = signer.sign(null); assertArrayEquals(expSignature, actSignature, "Mismatched signature"); - Signature verifier = support.getEDDSASigner(); + Signature verifier = new SignatureEd25519(); verifier.initVerifier(null, publicKey); verifier.update(null, dataBuf.clone(), offset, msgBytes.length); assertTrue(verifier.verify(null, expSignature), "Verification failed"); @@ -269,41 +246,40 @@ class Ed25519VectorsTest<PUB extends PublicKey, PRV extends PrivateKey> extends @MethodSource("parameters") @ParameterizedTest(name = "{0}") void recoverEDDSAPublicKey( - String name, EdDSASupport support, String provider, String prvKey, String pubKey, String msg, + String name, EdDSASupport support, String prvKey, String pubKey, String msg, String signature) throws Exception { initEd25519VectorsTest(name, support, prvKey, pubKey, msg, signature); PublicKey recoveredKey = support.recoverEDDSAPublicKey(privateKey); - assertTrue(support.compareEDDSAPPublicKeys(publicKey, recoveredKey), "Recovered key is not equal"); - byte[] recoveredBytes = support.getPublicKeyData(recoveredKey); + assertTrue(SecurityUtils.compareEDDSAPPublicKeys(publicKey, recoveredKey), "Recovered key is not equal"); + byte[] recoveredBytes = EdDSAUtils.getBytes(recoveredKey); assertArrayEquals(pubBytes, recoveredBytes, "Mismatched public seed value"); } @MethodSource("parameters") @ParameterizedTest(name = "{0}") void createPublicKeySpec( - String name, EdDSASupport support, String provider, String prvKey, String pubKey, String msg, + String name, EdDSASupport support, String prvKey, String pubKey, String msg, String signature) throws Exception { initEd25519VectorsTest(name, support, prvKey, pubKey, msg, signature); KeySpec keySpec = EdDSAUtils.createKeySpec(publicKey); - KeyFactory keyFactory = KeyFactory.getInstance(support.getKeyFactoryAlgorithm(), provider); + KeyFactory keyFactory = SecurityUtils.getKeyFactory(SecurityUtils.ED25519); PublicKey generatedKey = keyFactory.generatePublic(keySpec); - assertTrue(support.compareEDDSAPPublicKeys(publicKey, generatedKey), "Generated key is not equal"); - byte[] generatedBytes = support.getPublicKeyData(generatedKey); + assertTrue(SecurityUtils.compareEDDSAPPublicKeys(publicKey, generatedKey), "Generated key is not equal"); + byte[] generatedBytes = EdDSAUtils.getBytes(generatedKey); assertArrayEquals(pubBytes, generatedBytes, "Mismatched public seed value"); } @MethodSource("parameters") @ParameterizedTest(name = "{0}") void createPrivateKeySpec( - String name, EdDSASupport support, String provider, String prvKey, String pubKey, String msg, + String name, EdDSASupport support, String prvKey, String pubKey, String msg, String signature) throws Exception { initEd25519VectorsTest(name, support, prvKey, pubKey, msg, signature); KeySpec keySpec = EdDSAUtils.createKeySpec(privateKey); - KeyFactory keyFactory = KeyFactory.getInstance(support.getKeyFactoryAlgorithm(), provider); + KeyFactory keyFactory = SecurityUtils.getKeyFactory(SecurityUtils.ED25519); PrivateKey generatedKey = keyFactory.generatePrivate(keySpec); - assertTrue(support.compareEDDSAPrivateKeys(privateKey, generatedKey), "Generated key is not equal"); - byte[] generatedBytes = support.getPrivateKeyData(generatedKey); + assertTrue(SecurityUtils.compareEDDSAPrivateKeys(privateKey, generatedKey), "Generated key is not equal"); + byte[] generatedBytes = EdDSAUtils.getBytes(generatedKey); assertArrayEquals(prvBytes, generatedBytes, "Mismatched private seed value"); } - } diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/security/eddsa/EdDSASecurityProviderRegistrarTest.java b/sshd-common/src/test/java/org/apache/sshd/common/util/security/eddsa/EdDSASecurityProviderRegistrarTest.java index 9e0f5b3e0..6e187708f 100644 --- a/sshd-common/src/test/java/org/apache/sshd/common/util/security/eddsa/EdDSASecurityProviderRegistrarTest.java +++ b/sshd-common/src/test/java/org/apache/sshd/common/util/security/eddsa/EdDSASecurityProviderRegistrarTest.java @@ -58,10 +58,10 @@ class EdDSASecurityProviderRegistrarTest extends SecurityProviderRegistrarTestSu @Test void supportedSecurityEntities() { - assertSecurityEntitySupportState(getCurrentTestName(), registrarInstance, true, registrarInstance.getName(), + assertSecurityEntitySupportState(getCurrentTestName(), registrarInstance, true, SecurityUtils.ED25519, KeyPairGenerator.class, KeyFactory.class); assertSecurityEntitySupportState(getCurrentTestName(), registrarInstance, true, - SecurityUtils.CURVE_ED25519_SHA512, Signature.class); + SecurityUtils.ED25519, Signature.class); Collection<Class<?>> supported = new HashSet<>(Arrays.asList(KeyPairGenerator.class, KeyFactory.class, Signature.class)); diff --git a/sshd-common/src/test/java/org/apache/sshd/server/keyprovider/SimpleGeneratorHostKeyProviderTest.java b/sshd-common/src/test/java/org/apache/sshd/server/keyprovider/SimpleGeneratorHostKeyProviderTest.java index 8712fa4b7..2c356117d 100644 --- a/sshd-common/src/test/java/org/apache/sshd/server/keyprovider/SimpleGeneratorHostKeyProviderTest.java +++ b/sshd-common/src/test/java/org/apache/sshd/server/keyprovider/SimpleGeneratorHostKeyProviderTest.java @@ -85,7 +85,7 @@ class SimpleGeneratorHostKeyProviderTest extends JUnitTestSupport { @Test void edDSA() throws IOException, GeneralSecurityException { Assumptions.assumeTrue(SecurityUtils.isEDDSACurveSupported(), "EdDSA not supported"); - testSimpleGeneratorHostKeyProvider(SecurityUtils.EDDSA, KeyPairProvider.SSH_ED25519, -1, null); + testSimpleGeneratorHostKeyProvider(SecurityUtils.ED25519, KeyPairProvider.SSH_ED25519, -1, null); } private void testSimpleGeneratorHostKeyProvider( diff --git a/sshd-common/src/test/resources/org/apache/sshd/common/config/keys/loader/pem/pkcs8-eddsa.enc b/sshd-common/src/test/resources/org/apache/sshd/common/config/keys/loader/pem/pkcs8-ed25519.enc similarity index 100% rename from sshd-common/src/test/resources/org/apache/sshd/common/config/keys/loader/pem/pkcs8-eddsa.enc rename to sshd-common/src/test/resources/org/apache/sshd/common/config/keys/loader/pem/pkcs8-ed25519.enc diff --git a/sshd-common/src/test/resources/org/apache/sshd/common/config/keys/loader/pem/pkcs8-eddsa.enc2 b/sshd-common/src/test/resources/org/apache/sshd/common/config/keys/loader/pem/pkcs8-ed25519.enc2 similarity index 100% rename from sshd-common/src/test/resources/org/apache/sshd/common/config/keys/loader/pem/pkcs8-eddsa.enc2 rename to sshd-common/src/test/resources/org/apache/sshd/common/config/keys/loader/pem/pkcs8-ed25519.enc2 diff --git a/sshd-common/src/test/resources/org/apache/sshd/common/config/keys/loader/pem/pkcs8-eddsa.pem b/sshd-common/src/test/resources/org/apache/sshd/common/config/keys/loader/pem/pkcs8-ed25519.pem similarity index 100% rename from sshd-common/src/test/resources/org/apache/sshd/common/config/keys/loader/pem/pkcs8-eddsa.pem rename to sshd-common/src/test/resources/org/apache/sshd/common/config/keys/loader/pem/pkcs8-ed25519.pem 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 b9c6db621..de68ca37c 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 @@ -32,6 +32,7 @@ import java.util.Map; import org.apache.sshd.common.NamedResource; import org.apache.sshd.common.keyprovider.KeyPairProvider; import org.apache.sshd.common.util.security.SecurityUtils; +import org.apache.sshd.common.util.security.eddsa.generic.EdDSAUtils; /** * TODO Add javadoc @@ -60,9 +61,9 @@ public class EdDSAPuttyKeyDecoder extends AbstractPuttyKeyDecoder { } byte[] seed = pubReader.read(Short.MAX_VALUE); // reasonable max. allowed size - PublicKey pubKey = SecurityUtils.getEdDSASupport().get().generateEDDSAPublicKey(seed); + PublicKey pubKey = EdDSAUtils.getPublicKey(seed); seed = prvReader.read(Short.MAX_VALUE); // reasonable max. allowed size - PrivateKey prvKey = SecurityUtils.getEdDSASupport().get().generateEDDSAPrivateKey(seed); + PrivateKey prvKey = EdDSAUtils.getPrivateKey(seed); return Collections.singletonList(new KeyPair(pubKey, prvKey)); } }
