feat: add message-oriented agreement contexts for DH, ECDH and XDH
Introduce GenericJcaMessageAgreementContext and KeyPairKey to support message-based key agreement without breaking existing AgreementContext capabilities. Key changes: - Add KeyPairKey wrapper to carry KeyPair through capability dispatch. - Introduce GenericJcaMessageAgreementContext implementing MessageAgreementContext, mapping the protocol message to an SPKI-encoded public key. - Extend DH, ECDH and XDH algorithms with an additional MessageAgreementContext capability while preserving existing PrivateKey-based agreement usage. - Improve core agreement tests to cover CLASSIC_AGREEMENT, PAIR_MESSAGE and KEM_ADAPTER variants with explicit branch identification. - Add demo samples illustrating practical usage patterns for ML-KEM and XDH agreement variants, including lifecycle and resource management guidance. This change adds capabilities by extension rather than replacement and keeps existing APIs and behaviors fully backward compatible. Signed-off-by: Leo Galambos <lg@hq.egothor.org>
This commit is contained in:
@@ -76,7 +76,7 @@ import zeroecho.core.context.AgreementContext;
|
||||
*
|
||||
* @since 1.0
|
||||
*/
|
||||
public final class GenericJcaAgreementContext implements AgreementContext {
|
||||
public class GenericJcaAgreementContext implements AgreementContext {
|
||||
private final CryptoAlgorithm algorithm;
|
||||
private final PrivateKey privateKey;
|
||||
private final String jcaName; // e.g., "ECDH" or "XDH" (or "X25519"/"X448")
|
||||
|
||||
@@ -0,0 +1,235 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (C) 2025, Leo Galambos All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. All advertising materials mentioning features or use of this software must
|
||||
* display the following acknowledgement: This product includes software
|
||||
* developed by the Egothor project.
|
||||
*
|
||||
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
******************************************************************************/
|
||||
package zeroecho.core.alg.common.agreement;
|
||||
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.PublicKey;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
import java.util.Objects;
|
||||
|
||||
import zeroecho.core.CryptoAlgorithm;
|
||||
import zeroecho.core.context.MessageAgreementContext;
|
||||
|
||||
/**
|
||||
* Message-oriented JCA key agreement context where the handshake message is a
|
||||
* public key encoding.
|
||||
*
|
||||
* <p>
|
||||
* This context provides a {@link MessageAgreementContext} view over a classical
|
||||
* JCA Diffie–Hellman style agreement (e.g., ECDH, XDH). The protocol
|
||||
* "to-be-sent" data for such agreements is the party's public key. This class
|
||||
* therefore maps:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>{@link #getPeerMessage()} to the local public key encoding (X.509
|
||||
* SubjectPublicKeyInfo),</li>
|
||||
* <li>{@link #setPeerMessage(byte[])} to importing the peer public key and
|
||||
* binding it as the peer key.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <h2>Encoding</h2>
|
||||
* <p>
|
||||
* The message format is the standard X.509 SubjectPublicKeyInfo encoding
|
||||
* returned by {@link java.security.PublicKey#getEncoded()}. This format is
|
||||
* stable, widely interoperable and avoids ad-hoc or algorithm-specific wire
|
||||
* formats.
|
||||
* </p>
|
||||
*
|
||||
* <h2>Algorithm and provider selection</h2>
|
||||
* <p>
|
||||
* The underlying key agreement algorithm name (for
|
||||
* {@link javax.crypto.KeyAgreement}) and the key factory algorithm name (for
|
||||
* {@link KeyFactory}) are supplied explicitly by the algorithm registration
|
||||
* code. This keeps algorithm-specific knowledge in {@code *Algorithm} classes
|
||||
* rather than embedding naming heuristics into shared code.
|
||||
* </p>
|
||||
*
|
||||
* <h2>Lifecycle</h2>
|
||||
* <ol>
|
||||
* <li>Create the context with the local key pair wrapper.</li>
|
||||
* <li>Send {@link #getPeerMessage()} to the remote party.</li>
|
||||
* <li>Receive the remote party's message and call
|
||||
* {@link #setPeerMessage(byte[])}.</li>
|
||||
* <li>Derive the raw shared secret with {@link #deriveSecret()}.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <h2>Security considerations</h2>
|
||||
* <ul>
|
||||
* <li>The message returned by {@link #getPeerMessage()} contains only public
|
||||
* key material.</li>
|
||||
* <li>The output of {@link #deriveSecret()} is a raw shared secret and must be
|
||||
* processed with a KDF by higher protocol layers before use as symmetric keying
|
||||
* material.</li>
|
||||
* <li>This class does not log, persist, or otherwise expose private key
|
||||
* material.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <h2>Thread safety</h2>
|
||||
* <p>
|
||||
* Instances are not thread-safe and are intended for single-use,
|
||||
* single-threaded protocol executions.
|
||||
* </p>
|
||||
*
|
||||
* @since 1.0
|
||||
*/
|
||||
public final class GenericJcaMessageAgreementContext extends GenericJcaAgreementContext
|
||||
implements MessageAgreementContext {
|
||||
|
||||
private final PublicKey localPublic;
|
||||
private final String keyFactoryAlg;
|
||||
private final String keyFactoryProvider;
|
||||
|
||||
/**
|
||||
* Creates a message-oriented agreement context over a JCA key agreement.
|
||||
*
|
||||
* <p>
|
||||
* The wrapped {@link KeyPairKey} supplies both local private and public key
|
||||
* components: the private key is used for the underlying agreement computation,
|
||||
* while the public key is exported as the handshake message via
|
||||
* {@link #getPeerMessage()}.
|
||||
* </p>
|
||||
*
|
||||
* @param alg algorithm descriptor that owns this context
|
||||
* @param keyPairKey local key pair wrapper; must contain both a private
|
||||
* and a public key
|
||||
* @param jcaAgreementName JCA {@link javax.crypto.KeyAgreement} algorithm
|
||||
* name (e.g., {@code "ECDH"}, {@code "X25519"})
|
||||
* @param agreementProvider optional JCA provider name for
|
||||
* {@link javax.crypto.KeyAgreement}, or {@code null}
|
||||
* for default provider selection
|
||||
* @param keyFactoryAlg JCA {@link KeyFactory} algorithm name used to
|
||||
* import peer public keys (e.g., {@code "EC"},
|
||||
* {@code "XDH"})
|
||||
* @param keyFactoryProvider optional JCA provider name for {@link KeyFactory},
|
||||
* or {@code null} for default provider selection
|
||||
* @throws NullPointerException if any required argument is {@code null}
|
||||
* @since 1.0
|
||||
*/
|
||||
public GenericJcaMessageAgreementContext(CryptoAlgorithm alg, KeyPairKey keyPairKey, String jcaAgreementName,
|
||||
String agreementProvider, String keyFactoryAlg, String keyFactoryProvider) {
|
||||
super(Objects.requireNonNull(alg, "alg"), Objects.requireNonNull(keyPairKey, "keyPairKey").privateKey(),
|
||||
Objects.requireNonNull(jcaAgreementName, "jcaAgreementName"), agreementProvider);
|
||||
this.localPublic = Objects.requireNonNull(keyPairKey.publicKey(), "keyPairKey.public");
|
||||
this.keyFactoryAlg = Objects.requireNonNull(keyFactoryAlg, "keyFactoryAlg");
|
||||
this.keyFactoryProvider = keyFactoryProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the local party's handshake message.
|
||||
*
|
||||
* <p>
|
||||
* For DH/XDH-style agreements, the handshake message is the local public key
|
||||
* encoding. The returned array is a defensive copy and may be safely
|
||||
* transmitted over untrusted channels.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* The encoding is the standard X.509 SubjectPublicKeyInfo bytes returned by
|
||||
* {@link PublicKey#getEncoded()}.
|
||||
* </p>
|
||||
*
|
||||
* @return a defensive copy of the local public key encoding (never
|
||||
* {@code null})
|
||||
* @throws IllegalStateException if the local public key does not provide an
|
||||
* encoding
|
||||
* @since 1.0
|
||||
*/
|
||||
@Override
|
||||
public byte[] getPeerMessage() {
|
||||
byte[] encoded = localPublic.getEncoded();
|
||||
if (encoded == null) {
|
||||
throw new IllegalStateException("Local public key does not provide an encoding");
|
||||
}
|
||||
return encoded.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Supplies the peer party's handshake message.
|
||||
*
|
||||
* <p>
|
||||
* The provided message is interpreted as an X.509 SubjectPublicKeyInfo encoding
|
||||
* of the peer public key. The key is imported using {@link KeyFactory} and then
|
||||
* assigned as the peer key for the underlying agreement computation.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Passing {@code null} resets the peer binding and makes
|
||||
* {@link #deriveSecret()} unusable until a new peer message is provided.
|
||||
* </p>
|
||||
*
|
||||
* @param message peer public key encoding (SPKI), or {@code null} to reset the
|
||||
* peer state
|
||||
* @throws IllegalArgumentException if the message cannot be imported as a
|
||||
* public key using the configured
|
||||
* {@link KeyFactory} algorithm/provider
|
||||
* @since 1.0
|
||||
*/
|
||||
@Override
|
||||
public void setPeerMessage(byte[] message) {
|
||||
if (message == null) {
|
||||
setPeerPublic(null);
|
||||
return;
|
||||
}
|
||||
|
||||
PublicKey peerPublic = importPeerPublic(message);
|
||||
setPeerPublic(peerPublic);
|
||||
}
|
||||
|
||||
/**
|
||||
* Imports a peer public key from an X.509 SubjectPublicKeyInfo encoding.
|
||||
*
|
||||
* <p>
|
||||
* This method performs no caching and always imports the key anew. The caller
|
||||
* is responsible for ensuring that the protocol-layer validation requirements
|
||||
* are met (e.g., checking that the received public key belongs to an expected
|
||||
* identity, or that the agreement mode requires ephemeral vs. static keys).
|
||||
* </p>
|
||||
*
|
||||
* @param spkiEncoded peer public key encoding (SPKI); must not be {@code null}
|
||||
* @return imported peer {@link PublicKey}
|
||||
* @throws IllegalArgumentException if the key cannot be imported
|
||||
*/
|
||||
private PublicKey importPeerPublic(byte[] spkiEncoded) {
|
||||
try {
|
||||
KeyFactory keyFactory = (keyFactoryProvider == null) ? KeyFactory.getInstance(keyFactoryAlg)
|
||||
: KeyFactory.getInstance(keyFactoryAlg, keyFactoryProvider);
|
||||
|
||||
X509EncodedKeySpec spec = new X509EncodedKeySpec(spkiEncoded);
|
||||
return keyFactory.generatePublic(spec);
|
||||
} catch (GeneralSecurityException e) {
|
||||
throw new IllegalArgumentException("Failed to import peer public key using KeyFactory " + keyFactoryAlg, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (C) 2025, Leo Galambos
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. All advertising materials mentioning features or use of this software must
|
||||
* display the following acknowledgement:
|
||||
* This product includes software developed by the Egothor project.
|
||||
*
|
||||
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
******************************************************************************/
|
||||
package zeroecho.core.alg.common.agreement;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.security.Key;
|
||||
import java.security.KeyPair;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A {@link Key} wrapper that carries a {@link KeyPair} through APIs that are
|
||||
* constrained to {@link Key} types.
|
||||
*
|
||||
* <p>
|
||||
* This type exists to support capabilities that require both private and public
|
||||
* components (e.g., message-oriented key agreement contexts), while preserving
|
||||
* backward-compatible capabilities that accept only a {@link PrivateKey}.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* The wrapper does not expose an encoding via {@link #getEncoded()} because
|
||||
* serializing private key material implicitly is dangerous and not required for
|
||||
* capability dispatch.
|
||||
* </p>
|
||||
*
|
||||
* @since 1.0
|
||||
*/
|
||||
public final class KeyPairKey implements Key, Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final KeyPair keyPair;
|
||||
|
||||
/**
|
||||
* Creates a wrapper around a {@link KeyPair}.
|
||||
*
|
||||
* @param keyPair key pair to wrap (must not be {@code null})
|
||||
* @throws NullPointerException if {@code keyPair} is {@code null}
|
||||
* @since 1.0
|
||||
*/
|
||||
public KeyPairKey(KeyPair keyPair) {
|
||||
this.keyPair = Objects.requireNonNull(keyPair, "keyPair");
|
||||
Objects.requireNonNull(keyPair.getPrivate(), "keyPair.private");
|
||||
Objects.requireNonNull(keyPair.getPublic(), "keyPair.public");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the wrapped {@link KeyPair}.
|
||||
*
|
||||
* @return key pair
|
||||
* @since 1.0
|
||||
*/
|
||||
public KeyPair keyPair() {
|
||||
return keyPair;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the wrapped private key.
|
||||
*
|
||||
* @return private key
|
||||
* @since 1.0
|
||||
*/
|
||||
public PrivateKey privateKey() {
|
||||
return keyPair.getPrivate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the wrapped public key.
|
||||
*
|
||||
* @return public key
|
||||
* @since 1.0
|
||||
*/
|
||||
public PublicKey publicKey() {
|
||||
return keyPair.getPublic();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the algorithm name of the wrapped private key.
|
||||
*
|
||||
* @return algorithm name
|
||||
* @since 1.0
|
||||
*/
|
||||
@Override
|
||||
public String getAlgorithm() {
|
||||
return privateKey().getAlgorithm();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code null}. This wrapper intentionally does not define a standard
|
||||
* encoding format.
|
||||
*
|
||||
* @return {@code null}
|
||||
* @since 1.0
|
||||
*/
|
||||
@Override
|
||||
public String getFormat() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code null}. This wrapper intentionally does not expose a combined
|
||||
* encoding.
|
||||
*
|
||||
* @return {@code null}
|
||||
* @since 1.0
|
||||
*/
|
||||
@Override
|
||||
public byte[] getEncoded() {
|
||||
return null; // NOPMD
|
||||
}
|
||||
}
|
||||
@@ -46,7 +46,10 @@ import zeroecho.core.AlgorithmFamily;
|
||||
import zeroecho.core.KeyUsage;
|
||||
import zeroecho.core.alg.AbstractCryptoAlgorithm;
|
||||
import zeroecho.core.alg.common.agreement.GenericJcaAgreementContext;
|
||||
import zeroecho.core.alg.common.agreement.GenericJcaMessageAgreementContext;
|
||||
import zeroecho.core.alg.common.agreement.KeyPairKey;
|
||||
import zeroecho.core.context.AgreementContext;
|
||||
import zeroecho.core.context.MessageAgreementContext;
|
||||
import zeroecho.core.spi.AsymmetricKeyBuilder;
|
||||
|
||||
/**
|
||||
@@ -133,6 +136,10 @@ public final class DhAlgorithm extends AbstractCryptoAlgorithm {
|
||||
DhSpec.class,
|
||||
(PrivateKey k, DhSpec s) -> new GenericJcaAgreementContext(this, k, "DiffieHellman", null),
|
||||
DhSpec::ffdhe2048);
|
||||
capability(AlgorithmFamily.AGREEMENT, KeyUsage.AGREEMENT, MessageAgreementContext.class, KeyPairKey.class,
|
||||
DhSpec.class, (KeyPairKey k, DhSpec s) -> new GenericJcaMessageAgreementContext(this, k,
|
||||
"DiffieHellman", null, "DH", null),
|
||||
DhSpec::ffdhe2048);
|
||||
|
||||
registerAsymmetricKeyBuilder(DhSpec.class, new DhKeyGenBuilder(), DhSpec::ffdhe2048);
|
||||
registerAsymmetricKeyBuilder(DhPublicKeySpec.class, new AsymmetricKeyBuilder<>() {
|
||||
|
||||
@@ -40,12 +40,15 @@ import zeroecho.core.AlgorithmFamily;
|
||||
import zeroecho.core.KeyUsage;
|
||||
import zeroecho.core.alg.AbstractCryptoAlgorithm;
|
||||
import zeroecho.core.alg.common.agreement.GenericJcaAgreementContext;
|
||||
import zeroecho.core.alg.common.agreement.GenericJcaMessageAgreementContext;
|
||||
import zeroecho.core.alg.common.agreement.KeyPairKey;
|
||||
import zeroecho.core.alg.ecdsa.EcdsaCurveSpec;
|
||||
import zeroecho.core.alg.ecdsa.EcdsaPrivateKeyBuilder;
|
||||
import zeroecho.core.alg.ecdsa.EcdsaPrivateKeySpec;
|
||||
import zeroecho.core.alg.ecdsa.EcdsaPublicKeyBuilder;
|
||||
import zeroecho.core.alg.ecdsa.EcdsaPublicKeySpec;
|
||||
import zeroecho.core.context.AgreementContext;
|
||||
import zeroecho.core.context.MessageAgreementContext;
|
||||
|
||||
/**
|
||||
* <h2>Elliptic Curve Diffie-Hellman (ECDH) Algorithm</h2>
|
||||
@@ -152,6 +155,10 @@ public final class EcdhAlgorithm extends AbstractCryptoAlgorithm {
|
||||
EcdsaCurveSpec.class,
|
||||
(PrivateKey k, EcdsaCurveSpec s) -> new GenericJcaAgreementContext(this, k, "ECDH", null),
|
||||
() -> EcdsaCurveSpec.P256); // XXX spec is not used at all ?!?!
|
||||
capability(AlgorithmFamily.AGREEMENT, KeyUsage.AGREEMENT, MessageAgreementContext.class, KeyPairKey.class,
|
||||
EcdsaCurveSpec.class, (KeyPairKey k, EcdsaCurveSpec s) -> new GenericJcaMessageAgreementContext(this, k,
|
||||
"ECDH", null, "EC", null),
|
||||
() -> EcdsaCurveSpec.P256);
|
||||
|
||||
// Reuse EC builders/importers
|
||||
registerAsymmetricKeyBuilder(EcdhCurveSpec.class, new EcdhKeyGenBuilder(), () -> EcdhCurveSpec.P256);
|
||||
|
||||
@@ -46,7 +46,10 @@ import zeroecho.core.AlgorithmFamily;
|
||||
import zeroecho.core.KeyUsage;
|
||||
import zeroecho.core.alg.AbstractCryptoAlgorithm;
|
||||
import zeroecho.core.alg.common.agreement.GenericJcaAgreementContext;
|
||||
import zeroecho.core.alg.common.agreement.GenericJcaMessageAgreementContext;
|
||||
import zeroecho.core.alg.common.agreement.KeyPairKey;
|
||||
import zeroecho.core.context.AgreementContext;
|
||||
import zeroecho.core.context.MessageAgreementContext;
|
||||
import zeroecho.core.spi.AsymmetricKeyBuilder;
|
||||
|
||||
/**
|
||||
@@ -145,6 +148,11 @@ public final class XdhAlgorithm extends AbstractCryptoAlgorithm {
|
||||
XdhSpec.class,
|
||||
(PrivateKey k, XdhSpec s) -> new GenericJcaAgreementContext(this, k, s.keyAgreementName(), null),
|
||||
() -> XdhSpec.X25519);
|
||||
// New capability: MessageAgreementContext over KeyPair
|
||||
capability(AlgorithmFamily.AGREEMENT, KeyUsage.AGREEMENT, MessageAgreementContext.class, KeyPairKey.class,
|
||||
XdhSpec.class, (KeyPairKey k, XdhSpec s) -> new GenericJcaMessageAgreementContext(this, k,
|
||||
s.keyAgreementName(), null, "XDH", null),
|
||||
() -> XdhSpec.X25519);
|
||||
|
||||
registerAsymmetricKeyBuilder(XdhSpec.class, new XdhKeyGenBuilder(), () -> XdhSpec.X25519);
|
||||
registerAsymmetricKeyBuilder(XdhPublicKeySpec.class, new AsymmetricKeyBuilder<>() {
|
||||
|
||||
Reference in New Issue
Block a user