You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by tw...@apache.org on 2025/10/09 06:03:50 UTC
(mina-sshd) branch dev_3.0 updated (c975a971e -> 1152a651a)
This is an automated email from the ASF dual-hosted git repository.
twolf pushed a change to branch dev_3.0
in repository https://gitbox.apache.org/repos/asf/mina-sshd.git
from c975a971e Changes.md: fix typos.
add ce71789cc Update dead links to OpenSSH PROTOCOL.certkeys
add fc3412ed1 Bump jgit.version from 5.13.3.202401111512-r to 5.13.5.202508271544-r (#831)
add 74be99e8d Bump org.codehaus.plexus:plexus-archiver from 4.10.1 to 4.10.2 (#829)
add 8f0c296a2 GH-830: Get EC curve parameters from the security provider
new 1152a651a Merge branch 'master' into 3.0.0
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
docs/server-setup.md | 2 +-
docs/standards.md | 2 +-
pom.xml | 4 +-
.../org/apache/sshd/common/cipher/ECCurves.java | 124 ++++++++-------------
.../util/security/SecurityEntityFactory.java | 20 ++++
.../sshd/common/util/security/SecurityUtils.java | 8 ++
.../common/util/security/SecurityUtilsTest.java | 16 +++
7 files changed, 92 insertions(+), 84 deletions(-)
(mina-sshd) 01/01: Merge branch 'master' into 3.0.0
Posted by tw...@apache.org.
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 1152a651a04391c9bb83ecf4e07a339b6ad81169
Merge: c975a971e 8f0c296a2
Author: Thomas Wolf <tw...@apache.org>
AuthorDate: Wed Oct 8 23:41:02 2025 +0200
Merge branch 'master' into 3.0.0
docs/server-setup.md | 2 +-
docs/standards.md | 2 +-
pom.xml | 4 +-
.../org/apache/sshd/common/cipher/ECCurves.java | 124 ++++++++-------------
.../util/security/SecurityEntityFactory.java | 20 ++++
.../sshd/common/util/security/SecurityUtils.java | 8 ++
.../common/util/security/SecurityUtilsTest.java | 16 +++
7 files changed, 92 insertions(+), 84 deletions(-)
diff --cc pom.xml
index 729168748,d15fb01a0..b8d3567e8
--- a/pom.xml
+++ b/pom.xml
@@@ -110,10 -115,10 +110,10 @@@
<grpc.version>1.75.0</grpc.version> <!-- Used only in tests -->
<maven.archiver.version>3.6.4</maven.archiver.version>
- <plexus.archiver.version>4.10.1</plexus.archiver.version>
+ <plexus.archiver.version>4.10.2</plexus.archiver.version>
<!-- See https://pmd.github.io/ for available latest version -->
<pmd.version>7.17.0</pmd.version>
-
+ <japicmp.version>0.23.1</japicmp.version>
<sshd.tests.timeout.factor>1.0</sshd.tests.timeout.factor>
<sshd.tests.rerun.count>2</sshd.tests.rerun.count>
diff --cc sshd-common/src/main/java/org/apache/sshd/common/cipher/ECCurves.java
index 6db662ed7,5967b079d..a53bd36fd
--- a/sshd-common/src/main/java/org/apache/sshd/common/cipher/ECCurves.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/cipher/ECCurves.java
@@@ -162,13 -100,14 +100,15 @@@ public enum ECCurves implements KeyType
private final String keyType;
private final String oidString;
private final List<Integer> oidValue;
- private final ECParameterSpec params;
- private final int keySize;
- private ECParameterSpec params;
- private volatile int keySize = -1;
private final int numOctets;
private final DigestFactory digestFactory;
- ECCurves(String name, int[] oid, ECParameterSpec params, int numOctets, DigestFactory digestFactory) {
++ private ECParameterSpec params;
++ private volatile int keySize = -1;
++
+ ECCurves(String name, String secName, int[] oid, int numOctets, DigestFactory digestFactory) {
this.name = ValidateUtils.checkNotNullAndNotEmpty(name, "No curve name");
+ this.secName = ValidateUtils.checkNotNullAndNotEmpty(secName, "No SEC curve name");
this.oidString = NumberUtils.join('.', ValidateUtils.checkNotNullAndNotEmpty(oid, "No OID"));
this.oidValue = Collections.unmodifiableList(NumberUtils.asList(oid));
this.keyType = Constants.ECDSA_SHA2_PREFIX + name;
diff --cc sshd-common/src/main/java/org/apache/sshd/common/util/security/SecurityEntityFactory.java
index 569abb345,badd54166..00a17f1aa
--- 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
@@@ -19,227 -19,175 +19,247 @@@
package org.apache.sshd.common.util.security;
-import java.lang.reflect.Method;
++import java.security.AlgorithmParameters;
import java.security.GeneralSecurityException;
+import java.security.KeyFactory;
+import java.security.KeyPairGenerator;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
import java.security.Provider;
-import java.util.Objects;
+import java.security.SecureRandom;
+import java.security.Signature;
+import java.security.cert.CertificateFactory;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyAgreement;
+import javax.crypto.Mac;
-import org.apache.sshd.common.util.ExceptionUtils;
import org.apache.sshd.common.util.ValidateUtils;
/**
- * @param <T> Type of security entity being generated by this factory
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
-public interface SecurityEntityFactory<T> {
- Class<T> getEntityType();
-
- T getInstance(String algorithm) throws GeneralSecurityException;
-
- /**
- * Uses reflection in order to wrap the {@code getInstance} method(s) as a security entity factory.
- *
- * @param <F> Type of entity being generated by the factor
- * @param entityType The entity type class
- * @param registrar The {@code SecurityProviderRegistrar} to use - if {@code null} then default
- * provider is used (if specified).
- * @param defaultProvider Default provider choice to use if no registrar provided. If
- * {@code null}/empty then JCE default is used
- * @return The {@link SecurityEntityFactory} for the entity
- * @throws ReflectiveOperationException If failed to create the factory
- * @see #toDefaultFactory(Class)
- * @see #toNamedProviderFactory(Class, String)
- * @see #toProviderInstanceFactory(Class, Provider)
- * @see SecurityProviderChoice#isNamedProviderUsed()
- * @see SecurityProviderChoice#getSecurityProvider()
- */
- static <F> SecurityEntityFactory<F> toFactory(
- Class<F> entityType, SecurityProviderChoice registrar, SecurityProviderChoice defaultProvider)
- throws ReflectiveOperationException {
- 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());
- }
+public interface SecurityEntityFactory {
+
++ default AlgorithmParameters createAlgorithmParameters(String algorithm) throws GeneralSecurityException {
++ throw new NoSuchAlgorithmException("Algorithm '" + algorithm + "' not supported (default)");
++ }
++
+ default CertificateFactory createCertificateFactory(String algorithm) throws GeneralSecurityException {
+ throw new NoSuchAlgorithmException("Algorithm '" + algorithm + "' not supported (default)");
+ }
+
+ default Cipher createCipher(String algorithm) throws GeneralSecurityException {
+ throw new NoSuchAlgorithmException("Algorithm '" + algorithm + "' not supported (default)");
+ }
+
+ default KeyAgreement createKeyAgreement(String algorithm) throws GeneralSecurityException {
+ throw new NoSuchAlgorithmException("Algorithm '" + algorithm + "' not supported (default)");
+ }
+
+ default KeyFactory createKeyFactory(String algorithm) throws GeneralSecurityException {
+ throw new NoSuchAlgorithmException("Algorithm '" + algorithm + "' not supported (default)");
+ }
+
+ default KeyPairGenerator createKeyPairGenerator(String algorithm) throws GeneralSecurityException {
+ throw new NoSuchAlgorithmException("Algorithm '" + algorithm + "' not supported (default)");
+ }
+
+ default Mac createMac(String algorithm) throws GeneralSecurityException {
+ throw new NoSuchAlgorithmException("Algorithm '" + algorithm + "' not supported (default)");
+ }
+
+ default MessageDigest createMessageDigest(String algorithm) throws GeneralSecurityException {
+ throw new NoSuchAlgorithmException("Algorithm '" + algorithm + "' not supported (default)");
+ }
+
+ default Signature createSignature(String algorithm) throws GeneralSecurityException {
+ throw new NoSuchAlgorithmException("Algorithm '" + algorithm + "' not supported (default)");
+ }
+
+ default SecureRandom createSecureRandom(String algorithm) throws GeneralSecurityException {
+ throw new NoSuchAlgorithmException("Algorithm '" + algorithm + "' not supported (default)");
+ }
+
+ default KEM createKEM(String algorithm) throws GeneralSecurityException {
+ throw new NoSuchAlgorithmException("Algorithm '" + algorithm + "' not supported (default)");
}
- static <F> SecurityEntityFactory<F> toDefaultFactory(Class<F> entityType)
- throws ReflectiveOperationException {
- Method m = entityType.getDeclaredMethod("getInstance", String.class);
- return new SecurityEntityFactory<F>() {
- private final String s = SecurityEntityFactory.class.getSimpleName()
- + "[" + entityType.getSimpleName() + "]"
- + "[default]";
-
- @Override
- public Class<F> getEntityType() {
- return entityType;
- }
-
- @Override
- public F getInstance(String algorithm) throws GeneralSecurityException {
- try {
- Object value = m.invoke(null, algorithm);
- return entityType.cast(value);
- } catch (ReflectiveOperationException t) {
- Throwable e = ExceptionUtils.peelException(t);
- if (e instanceof GeneralSecurityException) {
- throw (GeneralSecurityException) e;
- } else if (e instanceof RuntimeException) {
- throw (RuntimeException) e;
- } else if (e instanceof Error) {
- throw (Error) e;
- } else {
- throw new GeneralSecurityException(e);
- }
- }
- }
-
- @Override
- public String toString() {
- return s;
- }
- };
+ class Named implements SecurityEntityFactory {
+
+ private final String name;
+
+ public Named(String name) {
+ this.name = ValidateUtils.checkNotNullAndNotEmpty(name, "Security provider name must not be empty");
+ }
+
++ @Override
++ public AlgorithmParameters createAlgorithmParameters(String algorithm) throws GeneralSecurityException {
++ return AlgorithmParameters.getInstance(algorithm, name);
++ }
++
+ @Override
+ public CertificateFactory createCertificateFactory(String algorithm) throws GeneralSecurityException {
+ return CertificateFactory.getInstance(algorithm, name);
+ }
+
+ @Override
+ public Cipher createCipher(String algorithm) throws GeneralSecurityException {
+ return Cipher.getInstance(algorithm, name);
+ }
+
+ @Override
+ public KeyAgreement createKeyAgreement(String algorithm) throws GeneralSecurityException {
+ return KeyAgreement.getInstance(algorithm, name);
+ }
+
+ @Override
+ public KeyFactory createKeyFactory(String algorithm) throws GeneralSecurityException {
+ return KeyFactory.getInstance(algorithm, name);
+ }
+
+ @Override
+ public KeyPairGenerator createKeyPairGenerator(String algorithm) throws GeneralSecurityException {
+ return KeyPairGenerator.getInstance(algorithm, name);
+ }
+
+ @Override
+ public Mac createMac(String algorithm) throws GeneralSecurityException {
+ return Mac.getInstance(algorithm, name);
+ }
+
+ @Override
+ public MessageDigest createMessageDigest(String algorithm) throws GeneralSecurityException {
+ return MessageDigest.getInstance(algorithm, name);
+ }
+
+ @Override
+ public Signature createSignature(String algorithm) throws GeneralSecurityException {
+ return Signature.getInstance(algorithm, name);
+ }
+
+ @Override
+ public SecureRandom createSecureRandom(String algorithm) throws GeneralSecurityException {
+ return SecureRandom.getInstance(algorithm, name);
+ }
}
- static <F> SecurityEntityFactory<F> toNamedProviderFactory(Class<F> entityType, String name)
- throws ReflectiveOperationException {
- ValidateUtils.checkNotNullAndNotEmpty(name, "No provider name specified");
- Method m = entityType.getDeclaredMethod("getInstance", String.class, String.class);
- return new SecurityEntityFactory<F>() {
- private final String s = SecurityEntityFactory.class.getSimpleName()
- + "[" + entityType.getSimpleName() + "]"
- + "[" + name + "]";
-
- @Override
- public Class<F> getEntityType() {
- return entityType;
- }
-
- @Override
- public F getInstance(String algorithm) throws GeneralSecurityException {
- try {
- Object value = m.invoke(null, algorithm, name);
- return entityType.cast(value);
- } catch (ReflectiveOperationException t) {
- Throwable e = ExceptionUtils.peelException(t);
- if (e instanceof GeneralSecurityException) {
- throw (GeneralSecurityException) e;
- } else if (e instanceof RuntimeException) {
- throw (RuntimeException) e;
- } else if (e instanceof Error) {
- throw (Error) e;
- } else {
- throw new GeneralSecurityException(e);
- }
- }
- }
-
- @Override
- public String toString() {
- return s;
- }
- };
+ class ByProvider implements SecurityEntityFactory {
+
+ private final Provider provider;
+
+ public ByProvider(Provider name) {
+ this.provider = ValidateUtils.checkNotNull(name, "Security provider must not be null");
+ }
+
++ @Override
++ public AlgorithmParameters createAlgorithmParameters(String algorithm) throws GeneralSecurityException {
++ return AlgorithmParameters.getInstance(algorithm, provider);
++ }
++
+ @Override
+ public CertificateFactory createCertificateFactory(String algorithm) throws GeneralSecurityException {
+ return CertificateFactory.getInstance(algorithm, provider);
+ }
+
+ @Override
+ public Cipher createCipher(String algorithm) throws GeneralSecurityException {
+ return Cipher.getInstance(algorithm, provider);
+ }
+
+ @Override
+ public KeyAgreement createKeyAgreement(String algorithm) throws GeneralSecurityException {
+ return KeyAgreement.getInstance(algorithm, provider);
+ }
+
+ @Override
+ public KeyFactory createKeyFactory(String algorithm) throws GeneralSecurityException {
+ return KeyFactory.getInstance(algorithm, provider);
+ }
+
+ @Override
+ public KeyPairGenerator createKeyPairGenerator(String algorithm) throws GeneralSecurityException {
+ return KeyPairGenerator.getInstance(algorithm, provider);
+ }
+
+ @Override
+ public Mac createMac(String algorithm) throws GeneralSecurityException {
+ return Mac.getInstance(algorithm, provider);
+ }
+
+ @Override
+ public MessageDigest createMessageDigest(String algorithm) throws GeneralSecurityException {
+ return MessageDigest.getInstance(algorithm, provider);
+ }
+
+ @Override
+ public Signature createSignature(String algorithm) throws GeneralSecurityException {
+ return Signature.getInstance(algorithm, provider);
+ }
+
+ @Override
+ public SecureRandom createSecureRandom(String algorithm) throws GeneralSecurityException {
+ return SecureRandom.getInstance(algorithm, provider);
+ }
}
- static <F> SecurityEntityFactory<F> toProviderInstanceFactory(Class<F> entityType, Provider provider)
- throws ReflectiveOperationException {
- Objects.requireNonNull(provider, "No provider instance");
- Method m = entityType.getDeclaredMethod("getInstance", String.class, Provider.class);
- return new SecurityEntityFactory<F>() {
- private final String s = SecurityEntityFactory.class.getSimpleName()
- + "[" + entityType.getSimpleName() + "]"
- + "[" + Provider.class.getSimpleName() + "]"
- + "[" + provider.getName() + "]";
-
- @Override
- public Class<F> getEntityType() {
- return entityType;
- }
-
- @Override
- public F getInstance(String algorithm) throws GeneralSecurityException {
- try {
- Object value = m.invoke(null, algorithm, provider);
- return entityType.cast(value);
- } catch (ReflectiveOperationException t) {
- Throwable e = ExceptionUtils.peelException(t);
- if (e instanceof GeneralSecurityException) {
- throw (GeneralSecurityException) e;
- } else if (e instanceof RuntimeException) {
- throw (RuntimeException) e;
- } else if (e instanceof Error) {
- throw (Error) e;
- } else {
- throw new GeneralSecurityException(e);
- }
- }
- }
-
- @Override
- public String toString() {
- return s;
- }
- };
+ enum Default implements SecurityEntityFactory {
+
+ INSTANCE;
+
++ @Override
++ public AlgorithmParameters createAlgorithmParameters(String algorithm) throws GeneralSecurityException {
++ return AlgorithmParameters.getInstance(algorithm);
++ }
++
+ @Override
+ public CertificateFactory createCertificateFactory(String algorithm) throws GeneralSecurityException {
+ return CertificateFactory.getInstance(algorithm);
+ }
+
+ @Override
+ public Cipher createCipher(String algorithm) throws GeneralSecurityException {
+ return Cipher.getInstance(algorithm);
+ }
+
+ @Override
+ public KeyAgreement createKeyAgreement(String algorithm) throws GeneralSecurityException {
+ return KeyAgreement.getInstance(algorithm);
+ }
+
+ @Override
+ public KeyFactory createKeyFactory(String algorithm) throws GeneralSecurityException {
+ return KeyFactory.getInstance(algorithm);
+ }
+
+ @Override
+ public KeyPairGenerator createKeyPairGenerator(String algorithm) throws GeneralSecurityException {
+ return KeyPairGenerator.getInstance(algorithm);
+ }
+
+ @Override
+ public Mac createMac(String algorithm) throws GeneralSecurityException {
+ return Mac.getInstance(algorithm);
+ }
+
+ @Override
+ public MessageDigest createMessageDigest(String algorithm) throws GeneralSecurityException {
+ return MessageDigest.getInstance(algorithm);
+ }
+
+ @Override
+ public Signature createSignature(String algorithm) throws GeneralSecurityException {
+ return Signature.getInstance(algorithm);
+ }
+
+ @Override
+ public SecureRandom createSecureRandom(String algorithm) throws GeneralSecurityException {
+ return SecureRandom.getInstance(algorithm);
+ }
+
+ @Override
+ public KEM createKEM(String algorithm) throws GeneralSecurityException {
+ return JceKEM.INSTANCE.get(algorithm);
+ }
}
}
diff --cc sshd-common/src/main/java/org/apache/sshd/common/util/security/SecurityUtils.java
index a2bbe89c2,525b66d01..2686b1ad5
--- 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
@@@ -22,8 -22,10 +22,9 @@@ import java.io.IOException
import java.io.InputStream;
import java.math.BigInteger;
import java.nio.file.Path;
+ import java.security.AlgorithmParameters;
import java.security.GeneralSecurityException;
import java.security.InvalidKeyException;
-import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
@@@ -697,25 -833,31 +698,32 @@@ public final class SecurityUtils
entitySelector, REGISTERED_PROVIDERS.values());
}
- try {
- return SecurityEntityFactory.toFactory(entityType, registrar, getDefaultProviderChoice());
- } catch (ReflectiveOperationException t) {
- Throwable e = ExceptionUtils.peelException(t);
- if (e instanceof RuntimeException) {
- throw (RuntimeException) e;
- } else if (e instanceof Error) {
- throw (Error) e;
- } else {
- throw new IllegalArgumentException(e);
+ return getSecurityEntityProvider(registrar, getDefaultProviderChoice());
+ }
+
+ public static SecurityEntityFactory getSecurityEntityProvider(
+ SecurityProviderRegistrar registrar,
+ SecurityProviderChoice defaultProvider) {
+ if (registrar == null) {
+ if ((defaultProvider == null) || (defaultProvider == SecurityProviderChoice.EMPTY)) {
+ return SecurityEntityFactory.Default.INSTANCE;
}
+ return defaultProvider.getFactory();
}
+ return registrar.getFactory();
}
+ public static AlgorithmParameters getAlgorithmParameters(String algorithm) throws GeneralSecurityException {
- SecurityEntityFactory<AlgorithmParameters> factory
++ SecurityEntityFactory factory
+ = resolveSecurityEntityFactory(AlgorithmParameters.class, algorithm,
+ r -> r.isSecurityEntitySupported(AlgorithmParameters.class, algorithm));
- return factory.getInstance(algorithm);
++ return factory.createAlgorithmParameters(algorithm);
+ }
+
public static KeyFactory getKeyFactory(String algorithm) throws GeneralSecurityException {
- SecurityEntityFactory<KeyFactory> factory
- = resolveSecurityEntityFactory(KeyFactory.class, algorithm, r -> r.isKeyFactorySupported(algorithm));
- return factory.getInstance(algorithm);
+ SecurityEntityFactory factory = resolveSecurityEntityFactory(KeyFactory.class, algorithm,
+ r -> r.isKeyFactorySupported(algorithm));
+ return factory.createKeyFactory(algorithm);
}
public static Cipher getCipher(String transformation) throws GeneralSecurityException {
diff --cc sshd-common/src/test/java/org/apache/sshd/common/util/security/SecurityUtilsTest.java
index e7b3454ce,a67168a61..60f818cbc
--- a/sshd-common/src/test/java/org/apache/sshd/common/util/security/SecurityUtilsTest.java
+++ b/sshd-common/src/test/java/org/apache/sshd/common/util/security/SecurityUtilsTest.java
@@@ -23,6 -23,6 +23,7 @@@ import java.io.IOException
import java.nio.file.Path;
import java.security.GeneralSecurityException;
import java.security.KeyPair;
++import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.DSAPrivateKey;
@@@ -32,6 -32,6 +33,7 @@@ import java.security.interfaces.ECPubli
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.ArrayList;
++import java.util.Base64;
import java.util.Collection;
import java.util.List;
@@@ -45,7 -45,8 +47,8 @@@ import org.apache.sshd.common.keyprovid
import org.apache.sshd.common.keyprovider.ClassLoadableResourceKeyPairProvider;
import org.apache.sshd.common.keyprovider.FileKeyPairProvider;
import org.apache.sshd.common.util.GenericUtils;
++import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
import org.apache.sshd.common.util.io.resource.PathResource;
-import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.api.MethodOrderer.MethodName;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
@@@ -118,6 -125,6 +121,19 @@@ class SecurityUtilsTest extends Securit
}
}
++ @Test
++ void x509EncodingEc() throws Exception {
++ KeyPairGenerator generator = SecurityUtils.getKeyPairGenerator(KeyUtils.EC_ALGORITHM);
++ generator.initialize(521);
++ KeyPair kp = generator.generateKeyPair();
++ String enc = Base64.getEncoder().encodeToString(kp.getPublic().getEncoded());
++ ByteArrayBuffer buf = new ByteArrayBuffer();
++ buf.putPublicKey(kp.getPublic());
++ PublicKey readBack = buf.getPublicKey();
++ assertTrue(KeyUtils.compareKeys(kp.getPublic(), readBack), "Public keys should be equal");
++ assertEquals(enc, Base64.getEncoder().encodeToString(readBack.getEncoded()), readBack.getClass().getCanonicalName());
++ }
++
private KeyPair testLoadECPrivateKey(String name) throws Exception {
return testLoadPrivateKey(name, ECPublicKey.class, ECPrivateKey.class);
}