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 bb9ac2069ea78661e9013992c1b23d06d09c8a18 Author: Thomas Wolf <[email protected]> AuthorDate: Sun Sep 7 21:18:03 2025 +0200 Further edDSA clean-up Remove unused things, and give the EdDSASecurityProviderRegistrar a PublicKeyFactory. --- .../bouncycastle/BouncyCastlePublicKeyFactory.java | 6 +- .../BouncyCastleSecurityProviderRegistrar.java | 2 +- .../util/security/eddsa/EdDSAPublicKeyFactory.java | 61 ++++++++ .../eddsa/EdDSASecurityProviderRegistrar.java | 6 +- .../security/eddsa/EdDSASecurityProviderUtils.java | 154 --------------------- .../common/signature/SignaturesDevelopment.java | 83 ----------- 6 files changed, 67 insertions(+), 245 deletions(-) diff --git a/sshd-common/src/main/java/org/apache/sshd/common/util/security/bouncycastle/BouncyCastlePublicKeyFactory.java b/sshd-common/src/main/java/org/apache/sshd/common/util/security/bouncycastle/BouncyCastlePublicKeyFactory.java index 70a1a0aaa..4eeb036f0 100644 --- a/sshd-common/src/main/java/org/apache/sshd/common/util/security/bouncycastle/BouncyCastlePublicKeyFactory.java +++ b/sshd-common/src/main/java/org/apache/sshd/common/util/security/bouncycastle/BouncyCastlePublicKeyFactory.java @@ -25,9 +25,11 @@ import org.apache.sshd.common.util.security.PublicKeyFactory; import org.apache.sshd.common.util.security.SecurityUtils; import org.bouncycastle.jcajce.interfaces.EdDSAPrivateKey; -public class BouncyCastlePublicKeyFactory implements PublicKeyFactory { +public final class BouncyCastlePublicKeyFactory implements PublicKeyFactory { - public BouncyCastlePublicKeyFactory() { + public static final PublicKeyFactory INSTANCE = new BouncyCastlePublicKeyFactory(); + + private BouncyCastlePublicKeyFactory() { super(); } 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 fbd1de662..8c886e83f 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 @@ -172,7 +172,7 @@ public class BouncyCastleSecurityProviderRegistrar extends AbstractSecurityProvi @Override public PublicKey getPublicKey(PrivateKey key) { if (isEnabled() && isEdDSASupported() && key.getClass().getPackage().getName().startsWith("org.bouncycastle.")) { - return new BouncyCastlePublicKeyFactory().getPublicKey(key); + return BouncyCastlePublicKeyFactory.INSTANCE.getPublicKey(key); } return super.getPublicKey(key); } diff --git a/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/EdDSAPublicKeyFactory.java b/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/EdDSAPublicKeyFactory.java new file mode 100644 index 000000000..92e4d29c0 --- /dev/null +++ b/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/EdDSAPublicKeyFactory.java @@ -0,0 +1,61 @@ +/* + * 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; + +import java.security.GeneralSecurityException; +import java.security.KeyFactory; +import java.security.PrivateKey; +import java.security.PublicKey; + +import net.i2p.crypto.eddsa.EdDSAPrivateKey; +import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec; +import org.apache.sshd.common.util.ValidateUtils; +import org.apache.sshd.common.util.security.PublicKeyFactory; +import org.apache.sshd.common.util.security.SecurityUtils; + +/** + * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> + */ +public final class EdDSAPublicKeyFactory implements PublicKeyFactory { + + public static final PublicKeyFactory INSTANCE = new EdDSAPublicKeyFactory(); + + private EdDSAPublicKeyFactory() { + super(); + } + + @Override + public PublicKey getPublicKey(PrivateKey key) { + ValidateUtils.checkTrue(SecurityUtils.isEDDSACurveSupported(), SecurityUtils.EDDSA + " not supported"); + if (!(key instanceof EdDSAPrivateKey)) { + return null; + } + + EdDSAPrivateKey prvKey = (EdDSAPrivateKey) key; + EdDSAPublicKeySpec keySpec = new EdDSAPublicKeySpec(prvKey.getAbyte(), prvKey.getParams()); + KeyFactory factory; + try { + factory = SecurityUtils.getKeyFactory(SecurityUtils.ED25519); + return factory.generatePublic(keySpec); + } catch (GeneralSecurityException e) { + return null; + } + } + +} 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 b351153ca..52fed9fc1 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 @@ -134,11 +134,7 @@ public class EdDSASecurityProviderRegistrar extends AbstractSecurityProviderRegi public PublicKey getPublicKey(PrivateKey key) { if (isEnabled() && isSupported() && "EdDSA".equals(key.getAlgorithm()) && key.getClass().getPackage().getName().startsWith("net.i2p.")) { - try { - return EdDSASecurityProviderUtils.recoverEDDSAPublicKey(key); - } catch (GeneralSecurityException e) { - return null; - } + return EdDSAPublicKeyFactory.INSTANCE.getPublicKey(key); } return super.getPublicKey(key); } 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 deleted file mode 100644 index e6d0c9f9f..000000000 --- a/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/EdDSASecurityProviderUtils.java +++ /dev/null @@ -1,154 +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; - -import java.security.GeneralSecurityException; -import java.security.InvalidKeyException; -import java.security.Key; -import java.security.KeyFactory; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.util.Arrays; -import java.util.Objects; - -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.EdDSAParameterSpec; -import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec; -import org.apache.sshd.common.config.keys.PublicKeyEntryDecoder; -import org.apache.sshd.common.util.ValidateUtils; -import org.apache.sshd.common.util.security.SecurityUtils; -import org.apache.sshd.common.util.security.eddsa.generic.Ed25519PublicKeyDecoder; -import org.apache.sshd.common.util.security.eddsa.generic.EdDSAUtils; -import org.apache.sshd.common.util.security.eddsa.generic.SignatureEd25519; - -/** - * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> - */ -public final class EdDSASecurityProviderUtils { - // See EdDSANamedCurveTable - public static final int KEY_SIZE = EdDSAUtils.ED25519_LENGTH * Byte.SIZE; - - private EdDSASecurityProviderUtils() { - throw new UnsupportedOperationException("No instance"); - } - - public static boolean isEDDSAKey(Key key) { - return getEDDSAKeySize(key) == KEY_SIZE; - } - - public static int getEDDSAKeySize(Key key) { - return (SecurityUtils.isEDDSACurveSupported() && (key instanceof EdDSAKey)) ? KEY_SIZE : -1; - } - - public static boolean compareEDDSAPPublicKeys(PublicKey k1, PublicKey k2) { - if (!SecurityUtils.isEDDSACurveSupported()) { - return false; - } - - if ((k1 instanceof EdDSAPublicKey) && (k2 instanceof EdDSAPublicKey)) { - if (k1.equals(k2)) { - return true; - } - - EdDSAPublicKey ed1 = (EdDSAPublicKey) k1; - EdDSAPublicKey ed2 = (EdDSAPublicKey) k2; - return Arrays.equals(ed1.getAbyte(), ed2.getAbyte()) - && compareEDDSAKeyParams(ed1.getParams(), ed2.getParams()); - } - - return false; - } - - public static boolean isEDDSASignatureAlgorithm(String algorithm) { - return EdDSAEngine.SIGNATURE_ALGORITHM.equalsIgnoreCase(algorithm); - } - - public static EdDSAPublicKey recoverEDDSAPublicKey(PrivateKey key) throws GeneralSecurityException { - ValidateUtils.checkTrue(SecurityUtils.isEDDSACurveSupported(), SecurityUtils.EDDSA + " not supported"); - if (!(key instanceof EdDSAPrivateKey)) { - throw new InvalidKeyException("Private key is not " + SecurityUtils.EDDSA); - } - - EdDSAPrivateKey prvKey = (EdDSAPrivateKey) key; - EdDSAPublicKeySpec keySpec = new EdDSAPublicKeySpec(prvKey.getAbyte(), prvKey.getParams()); - KeyFactory factory = SecurityUtils.getKeyFactory(SecurityUtils.ED25519); - return EdDSAPublicKey.class.cast(factory.generatePublic(keySpec)); - } - - public static org.apache.sshd.common.signature.Signature getEDDSASignature() { - ValidateUtils.checkTrue(SecurityUtils.isEDDSACurveSupported(), SecurityUtils.EDDSA + " not supported"); - return new SignatureEd25519(); - } - - public static PublicKeyEntryDecoder getEDDSAPublicKeyEntryDecoder() { - ValidateUtils.checkTrue(SecurityUtils.isEDDSACurveSupported(), SecurityUtils.EDDSA + " not supported"); - return Ed25519PublicKeyDecoder.INSTANCE; - } - - public static boolean compareEDDSAPrivateKeys(PrivateKey k1, PrivateKey k2) { - if (!SecurityUtils.isEDDSACurveSupported()) { - return false; - } - - if ((k1 instanceof EdDSAPrivateKey) && (k2 instanceof EdDSAPrivateKey)) { - if (k1.equals(k2)) { - return true; - } - - EdDSAPrivateKey ed1 = (EdDSAPrivateKey) k1; - EdDSAPrivateKey ed2 = (EdDSAPrivateKey) k2; - return Arrays.equals(ed1.getSeed(), ed2.getSeed()) - && compareEDDSAKeyParams(ed1.getParams(), ed2.getParams()); - } - - return false; - } - - public static boolean compareEDDSAKeyParams(EdDSAParameterSpec s1, EdDSAParameterSpec s2) { - if (Objects.equals(s1, s2)) { - return true; - } else if (s1 == null || s2 == null) { - return false; // both null is covered by Objects#equals - } else { - return Objects.equals(s1.getHashAlgorithm(), s2.getHashAlgorithm()) - && Objects.equals(s1.getCurve(), s2.getCurve()) - && Objects.equals(s1.getB(), s2.getB()); - } - } - - public static PublicKey generateEDDSAPublicKey(byte[] seed) throws GeneralSecurityException { - if (!SecurityUtils.isEDDSACurveSupported()) { - throw new NoSuchAlgorithmException(SecurityUtils.EDDSA + " not supported"); - } - - return EdDSAUtils.getPublicKey(seed); - } - - public static PrivateKey generateEDDSAPrivateKey(byte[] seed) throws GeneralSecurityException { - if (!SecurityUtils.isEDDSACurveSupported()) { - throw new NoSuchAlgorithmException(SecurityUtils.EDDSA + " not supported"); - } - - return EdDSAUtils.getPrivateKey(seed); - } -} diff --git a/sshd-common/src/test/java/org/apache/sshd/common/signature/SignaturesDevelopment.java b/sshd-common/src/test/java/org/apache/sshd/common/signature/SignaturesDevelopment.java deleted file mode 100644 index a741144ca..000000000 --- a/sshd-common/src/test/java/org/apache/sshd/common/signature/SignaturesDevelopment.java +++ /dev/null @@ -1,83 +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.signature; - -import java.security.KeyPair; -import java.security.PrivateKey; -import java.security.PublicKey; - -import org.apache.sshd.common.util.GenericUtils; -import org.apache.sshd.common.util.buffer.BufferUtils; -import org.apache.sshd.common.util.security.eddsa.EdDSASecurityProviderUtils; -import org.apache.sshd.util.test.JUnitTestSupport; -import org.junit.jupiter.api.Disabled; - -/** - * A "scratch-pad" class for testing signatures related code during development - * - * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> - */ -@Disabled("Used only for development") -public class SignaturesDevelopment extends JUnitTestSupport { - public SignaturesDevelopment() { - super(); - } - - public static void testSignatureFactory( - SignatureFactory factory, KeyPair kp, byte[] data, boolean generateSignature, byte[] signature) - throws Exception { - Signature signer = factory.create(); - if (generateSignature) { - signer.initSigner(null, kp.getPrivate()); - signer.update(null, data); - signature = signer.sign(null); - System.out.append('\t').append("Signature: ").println(BufferUtils.toHex(':', signature)); - } else { - signer.initVerifier(null, kp.getPublic()); - signer.update(null, data); - if (signer.verify(null, signature)) { - System.out.append('\t').println("Valid signature"); - } else { - System.err.append('\t').println("Invalid signature"); - } - } - } - - ////////////////////////////////////////////////////////////////////////// - - // args[0]=signatureName, args[1]=publicKey, args[2]=privateKey, args[3]=sign/verify, args[4]=data, - // args[5]=signature(if verify required) - public static void main(String[] args) throws Exception { - SignatureFactory factory = BuiltinSignatures.resolveFactory(args[0]); - // TODO recover public/private keys according to factory name - byte[] publicKey = BufferUtils.decodeHex(':', args[1]); - PublicKey pubKey = EdDSASecurityProviderUtils.generateEDDSAPublicKey(publicKey); - byte[] privateKey = BufferUtils.decodeHex(':', args[2]); - PrivateKey prvKey = EdDSASecurityProviderUtils.generateEDDSAPrivateKey(privateKey); - String op = args[3]; - byte[] data = BufferUtils.decodeHex(':', args[4]); - byte[] signature = GenericUtils.EMPTY_BYTE_ARRAY; - if ("verify".equalsIgnoreCase(op)) { - signature = BufferUtils.decodeHex(':', args[5]); - } - - testSignatureFactory(factory, new KeyPair(pubKey, prvKey), data, "sign".equalsIgnoreCase(op), signature); - } -}
