package javax.crypto; /** * This class provides the functionality of a Key Encapsulation Mechanism (KEM). * A KEM can be used to secure symmetric keys using asymmetric or public key * cryptography between two parties. The sender calls the encapsulate method * to generate a secret key and a key encapsulation message, and the receiver * calls the decapsulate method to recover the same secret key from * the key encapsulation message. *

* The {@code getInstance} method creates a new {@code KEM} object that * implements the specified algorithm. *

* A {@code KEM} object is immutable. It is safe to call multiple * {@code newEncapsulator} and {@code newDecapsulator} methods on the * same {@code KEM} object at the same time. *

* If a provider is not specified in the {@code getInstance} method when * instantiating a {@code KEM} object, the {@code newEncapsulator} and * {@code newDecapsulator} methods may return encapsulators or decapsulators * from different providers. The provider selected is based on the parameters * passed to the {@code newEncapsulator} or {@code newDecapsulator} methods: * the private or public key and the optional {@code AlgorithmParameterSpec}. * The {@link Encapsulator#providerName} and {@link Decapsulator#providerName} * methods return the name of the selected provider. *

* {@code Encapsulator} and {@code Decapsulator} objects are also immutable. * It is safe to invoke multiple {@code encapsulate} and {@code decapsulate} * methods on the same {@code Encapsulator} or {@code Decapsulator} object * at the same time. Each invocation of {@code encapsulate} will generate a * new shared secret and key encapsulation message. *

* * Example: *

{@code
 *    // Receiver side
 *    var kpg = KeyPairGenerator.getInstance("X25519");
 *    var kp = kpg.generateKeyPair();
 *
 *    // Sender side
 *    var kem1 = KEM.getInstance("DHKEM");
 *    var sender = kem1.newEncapsulator(kp.getPublic());
 *    var encapsulated = sender.encapsulate();
 *    var k1 = encapsulated.key();
 *
 *    // Receiver side
 *    var kem2 = KEM.getInstance("DHKEM");
 *    var receiver = kem2.newDecapsulator(kp.getPrivate());
 *    var k2 = receiver.decapsulate(encapsulated.encapsulation());
 *
 *    assert Arrays.equals(k1.getEncoded(), k2.getEncoded());
 * }
* * @apiNote This class is defined in Java SE 17 Maintenance Release 1. * @since 17 */ public final class KEM { /** * This class specifies the return value of the encapsulate method of * a Key Encapsulation Mechanism (KEM), which includes the shared secret * (as a {@code SecretKey}), the key encapsulation message, * and optional parameters. *

* Note: the key encapsulation message can be also referred to as ciphertext. * * @see #newEncapsulator(PublicKey, AlgorithmParameterSpec, SecureRandom) * @see Encapsulator#encapsulate(int, int, String) * * @apiNote This class is defined in Java SE 17 Maintenance Release 1. * @since 17 */ public static final class Encapsulated { /** * Constructs an {@code Encapsulated} object. * * @param key the shared secret as a key, must not be {@code null}. * @param encapsulation the key encapsulation message, must not * be {@code null}. The contents of the array are copied * to protect against subsequent modification. * @param params optional parameters, can be {@code null}. * The contents of the array are copied to protect * against subsequent modification. * @throws NullPointerException if {@code key} or {@code encapsulation} * is {@code null} */ public Encapsulated(SecretKey key, byte[] encapsulation, byte[] params); /** * Returns the {@code SecretKey}. * * @return the secret key */ public SecretKey key(); /** * Returns the key encapsulation message. * * @return the key encapsulation message. A new copy of the byte array * is returned. */ public byte[] encapsulation(); /** * Returns the optional parameters in a byte array. * * @return the optional parameters in a byte array or {@code null} * if not specified. A new copy of the byte array is returned. */ public byte[] params(); } /** * An encapsulator, generated by {@link #newEncapsulator} on the KEM * sender side. *

* This class represents the key encapsulation function of a KEM. * Each invocation of the {@code encapsulate} method generates a * new secret key and key encapsulation message that is returned * in an {@link Encapsulated} object. * * @apiNote This class is defined in Java SE 17 Maintenance Release 1. * @since 17 */ public static final class Encapsulator { /** * Returns the name of the provider. * * @return the name of the provider */ public String providerName(); /** * The key encapsulation function. *

* This method is equivalent to * {@code encapsulate(0, secretSize(), "Generic")}. This combination * of arguments must be supported by every implementation. *

* The generated secret key is usually passed to a key derivation * function (KDF) as the input keying material. * * @return a {@link Encapsulated} object containing the shared * secret, key encapsulation message, and optional parameters. * The shared secret is a {@code SecretKey} containing all of * the bytes of the secret, and an algorithm name of "Generic". */ public Encapsulated encapsulate(); /** * The key encapsulation function. *

* Each invocation of this method generates a new secret key and key * encapsulation message that is returned in an {@link Encapsulated} object. *

* An implementation may choose to not support arbitrary combinations * of {@code from}, {@code to}, and {@code algorithm}. * * @param from the initial index of the shared secret byte array * to be returned, inclusive * @param to the final index of the shared secret byte array * to be returned, exclusive * @param algorithm the algorithm name for the secret key that is returned * @return a {@link Encapsulated} object containing a portion of * the shared secret, key encapsulation message, and optional * parameters. The portion of the shared secret is a * {@code SecretKey} containing the bytes of the secret * ranging from {@code from} to {@code to}, exclusive, * and an algorithm name as specified. For example, * {@code encapsulate(0, 16, "AES")} uses the first 16 bytes * of the shared secret as a 128-bit AES key. * @throws IndexOutOfBoundsException if {@code from < 0}, * {@code from > to}, or {@code to > secretSize()} * @throws NullPointerException if {@code algorithm} is {@code null} * @throws UnsupportedOperationException if the combination of * {@code from}, {@code to}, and {@code algorithm} * is not supported by the encapsulator */ public Encapsulated encapsulate(int from, int to, String algorithm); /** * Returns the size of the shared secret. *

* This method can be called to find out the length of the shared secret * before {@code encapsulate} is called or if the obtained * {@code SecretKey} is not extractable. * * @return the size of the shared secret */ public int secretSize(); /** * Returns the size of the key encapsulation message. *

* This method can be called to find out the length of the encapsulation * message before {@code encapsulate} is called. * * @return the size of the key encapsulation message */ public int encapsulationSize(); } /** * A decapsulator, generated by {@link #newDecapsulator} on the KEM * receiver side. *

* This class represents the key decapsulation function of a KEM. * An invocation of the {@code decapsulate} method recovers the * secret key from the key encapsulation message. * * @apiNote This class is defined in Java SE 17 Maintenance Release 1. * @since 17 */ public static final class Decapsulator { /** * Returns the name of the provider. * * @return the name of the provider */ public String providerName(); /** * The key decapsulation function. *

* This method is equivalent to * {@code decapsulate(encapsulation, 0, secretSize(), "Generic")}. This * combination of arguments must be supported by every implementation. *

* The generated secret key is usually passed to a key derivation * function (KDF) as the input keying material. * * @param encapsulation the key encapsulation message from the sender. * The size must be equal to the value returned by * {@link #encapsulationSize()}, or a {@code DecapsulateException} * will be thrown. * @return the shared secret as a {@code SecretKey} with * an algorithm name of "Generic" * @throws DecapsulateException if an error occurs during the * decapsulation process * @throws NullPointerException if {@code encapsulation} is {@code null} */ public SecretKey decapsulate(byte[] encapsulation) throws DecapsulateException; /** * The key decapsulation function. *

* An invocation of this method recovers the secret key from the key * encapsulation message. *

* An implementation may choose to not support arbitrary combinations * of {@code from}, {@code to}, and {@code algorithm}. * * @param encapsulation the key encapsulation message from the sender. * The size must be equal to the value returned by * {@link #encapsulationSize()}, or a {@code DecapsulateException} * will be thrown. * @param from the initial index of the shared secret byte array * to be returned, inclusive * @param to the final index of the shared secret byte array * to be returned, exclusive * @param algorithm the algorithm name for the secret key that is returned * @return a portion of the shared secret as a {@code SecretKey} * containing the bytes of the secret ranging from {@code from} * to {@code to}, exclusive, and an algorithm name as specified. * For example, {@code decapsulate(encapsulation, secretSize() * - 16, secretSize(), "AES")} uses the last 16 bytes * of the shared secret as a 128-bit AES key. * @throws DecapsulateException if an error occurs during the * decapsulation process * @throws IndexOutOfBoundsException if {@code from < 0}, * {@code from > to}, or {@code to > secretSize()} * @throws NullPointerException if {@code encapsulation} or * {@code algorithm} is {@code null} * @throws UnsupportedOperationException if the combination of * {@code from}, {@code to}, and {@code algorithm} * is not supported by the decapsulator */ public SecretKey decapsulate(byte[] encapsulation, int from, int to, String algorithm) throws DecapsulateException; /** * Returns the size of the shared secret. *

* This method can be called to find out the length of the shared secret * before {@code decapsulate} is called or if the obtained * {@code SecretKey} is not extractable. * * @return the size of the shared secret */ public int secretSize(); /** * Returns the size of the key encapsulation message. *

* This method can be used to extract the encapsulation message * from a longer byte array if no length information is provided * by a higher level protocol. * * @return the size of the key encapsulation message */ public int encapsulationSize(); } /** * Returns a {@code KEM} object that implements the specified algorithm. * * @param algorithm the name of the KEM algorithm. * See the {@code KEM} section in the * Java Security Standard Algorithm Names Specification * for information about standard KEM algorithm names. * @return the new {@code KEM} object * @throws NoSuchAlgorithmException if no {@code Provider} supports a * {@code KEM} implementation for the specified algorithm * @throws NullPointerException if {@code algorithm} is {@code null} */ public static KEM getInstance(String algorithm) throws NoSuchAlgorithmException; /** * Returns a {@code KEM} object that implements the specified algorithm * from the specified security provider. * * @param algorithm the name of the KEM algorithm. * See the {@code KEM} section in the * Java Security Standard Algorithm Names Specification * for information about standard KEM algorithm names. * @param provider the provider. If {@code null}, this method is equivalent * to {@link #getInstance(String)}. * @return the new {@code KEM} object * @throws NoSuchAlgorithmException if a {@code provider} is specified and * it does not support the specified KEM algorithm, * or if {@code provider} is {@code null} and there is no provider * that supports a KEM implementation of the specified algorithm * @throws NullPointerException if {@code algorithm} is {@code null} */ public static KEM getInstance(String algorithm, Provider provider) throws NoSuchAlgorithmException; /** * Returns a {@code KEM} object that implements the specified algorithm * from the specified security provider. * * @param algorithm the name of the KEM algorithm. * See the {@code KEM} section in the * Java Security Standard Algorithm Names Specification * for information about standard KEM algorithm names. * @param provider the provider. If {@code null}, this method is equivalent * to {@link #getInstance(String)}. * @return the new {@code KEM} object * @throws NoSuchAlgorithmException if a {@code provider} is specified and * it does not support the specified KEM algorithm, * or if {@code provider} is {@code null} and there is no provider * that supports a KEM implementation of the specified algorithm * @throws NoSuchProviderException if the specified provider is not * registered in the security provider list * @throws NullPointerException if {@code algorithm} is {@code null} */ public static KEM getInstance(String algorithm, String provider) throws NoSuchAlgorithmException, NoSuchProviderException; /** * Creates a KEM encapsulator on the KEM sender side. *

* This method is equivalent to {@code newEncapsulator(publicKey, null, null)}. * * @param publicKey the receiver's public key, must not be {@code null} * @return the encapsulator for this key * @throws InvalidKeyException if {@code publicKey} is {@code null} or invalid * @throws UnsupportedOperationException if this method is not supported * because an {@code AlgorithmParameterSpec} must be provided */ public Encapsulator newEncapsulator(PublicKey publicKey) throws InvalidKeyException; /** * Creates a KEM encapsulator on the KEM sender side. *

* This method is equivalent to {@code newEncapsulator(publicKey, null, secureRandom)}. * * @param publicKey the receiver's public key, must not be {@code null} * @param secureRandom the source of randomness for encapsulation. * If {@code} null, a default one from the * implementation will be used. * @return the encapsulator for this key * @throws InvalidKeyException if {@code publicKey} is {@code null} or invalid * @throws UnsupportedOperationException if this method is not supported * because an {@code AlgorithmParameterSpec} must be provided */ public Encapsulator newEncapsulator(PublicKey publicKey, SecureRandom secureRandom) throws InvalidKeyException; /** * Creates a KEM encapsulator on the KEM sender side. *

* An algorithm can define an {@code AlgorithmParameterSpec} child class to * provide extra information in this method. This is especially useful if * the same key can be used to derive shared secrets in different ways. * If any extra information inside this object needs to be transmitted along * with the key encapsulation message so that the receiver is able to create * a matching decapsulator, it will be included as a byte array in the * {@link Encapsulated#params} field inside the encapsulation output. * In this case, the security provider should provide an * {@code AlgorithmParameters} implementation using the same algorithm name * as the KEM. The receiver can initiate such an {@code AlgorithmParameters} * instance with the {@code params} byte array received and recover * an {@code AlgorithmParameterSpec} object to be used in its * {@link #newDecapsulator(PrivateKey, AlgorithmParameterSpec)} call. * * @param publicKey the receiver's public key, must not be {@code null} * @param spec the optional parameter, can be {@code null} * @param secureRandom the source of randomness for encapsulation. * If {@code} null, a default one from the * implementation will be used. * @return the encapsulator for this key * @throws InvalidAlgorithmParameterException if {@code spec} is invalid * or one is required but {@code spec} is {@code null} * @throws InvalidKeyException if {@code publicKey} is {@code null} or invalid */ public Encapsulator newEncapsulator(PublicKey publicKey, AlgorithmParameterSpec spec, SecureRandom secureRandom) throws InvalidAlgorithmParameterException, InvalidKeyException; /** * Creates a KEM decapsulator on the KEM receiver side. *

* This method is equivalent to {@code newDecapsulator(privateKey, null)}. * * @param privateKey the receiver's private key, must not be {@code null} * @return the decapsulator for this key * @throws InvalidKeyException if {@code privateKey} is {@code null} or invalid * @throws UnsupportedOperationException if this method is not supported * because an {@code AlgorithmParameterSpec} must be provided */ public Decapsulator newDecapsulator(PrivateKey privateKey) throws InvalidKeyException; /** * Creates a KEM decapsulator on the KEM receiver side. * * @param privateKey the receiver's private key, must not be {@code null} * @param spec the parameter, can be {@code null} * @return the decapsulator for this key * @throws InvalidAlgorithmParameterException if {@code spec} is invalid * or one is required but {@code spec} is {@code null} * @throws InvalidKeyException if {@code privateKey} is {@code null} or invalid */ public Decapsulator newDecapsulator(PrivateKey privateKey, AlgorithmParameterSpec spec) throws InvalidAlgorithmParameterException, InvalidKeyException; /** * Returns the name of the algorithm for this {@code KEM} object. * * @return the name of the algorithm for this {@code KEM} object. */ public String getAlgorithm(); } /** * This class defines the Service Provider Interface (SPI) for the {@link KEM} * class. A security provider implements this interface to provide an * implementation of a Key Encapsulation Mechanism (KEM) algorithm. *

* A KEM algorithm may support a family of configurations. Each configuration * may accept different types of keys, cryptographic primitives, and sizes of * shared secrets and key encapsulation messages. A configuration is defined * by the KEM algorithm name, the key it uses, and an optional * {@code AlgorithmParameterSpec} argument that is specified when creating * an encapsulator or decapsulator. The result of calling * {@link #engineNewEncapsulator} or {@link #engineNewDecapsulator} must return * an encapsulator or decapsulator that maps to a single configuration, * where its {@code engineSecretSize()} and {@code engineEncapsulationSize()} * methods return constant values. *

* A {@code KEMSpi} implementation must be immutable. It must be safe to * call multiple {@code engineNewEncapsulator} and {@code engineNewDecapsulator} * methods at the same time. *

* {@code EncapsulatorSpi} and {@code DecapsulatorSpi} implementations must also * be immutable. It must be safe to invoke multiple {@code encapsulate} and * {@code decapsulate} methods at the same time. Each invocation of * {@code encapsulate} should generate a new shared secret and key * encapsulation message. *

* For example, *

{@code
 * public static class MyKEMImpl implements KEMSpi {
 *
 *     @Override
 *     public KEMSpi.EncapsulatorSpi engineNewEncapsulator(PublicKey publicKey,
 *             AlgorithmParameterSpec spec, SecureRandom secureRandom)
 *             throws InvalidAlgorithmParameterException, InvalidKeyException {
 *         if (!checkPublicKey(publicKey)) {
 *             throw new InvalidKeyException("unsupported key");
 *         }
 *         if (!checkParameters(spec)) {
 *             throw new InvalidAlgorithmParameterException("unsupported params");
 *         }
 *         return new MyEncapsulator(publicKey, spec, secureRandom);
 *     }
 *
 *     class MyEncapsulator implements KEMSpi.EncapsulatorSpi {
 *         MyEncapsulator(PublicKey publicKey, AlgorithmParameterSpec spec,
 *                 SecureRandom secureRandom){
 *             this.spec = spec != null ? spec : getDefaultParameters();
 *             this.secureRandom = secureRandom != null
 *                     ? secureRandom
 *                     : getDefaultSecureRandom();
 *             this.publicKey = publicKey;
 *         }
 *
 *         @Override
 *         public KEM.Encapsulated encapsulate(int from, int to, String algorithm) {
 *             byte[] encapsulation;
 *             byte[] secret;
 *             // calculating...
 *             return new KEM.Encapsulated(
 *                     new SecretKeySpec(secret, from, to - from, algorithm),
 *                     encapsulation, null);
 *         }
 *
 *         // ...
 *     }
 *
 *     // ...
 * }
 * }
* * @see KEM * @apiNote This interface is defined in Java SE 17 Maintenance Release 1. * @since 17 */ public interface KEMSpi { /** * The KEM encapsulator implementation, generated by * {@link #engineNewEncapsulator} on the KEM sender side. * * @see KEM.Encapsulator * * @apiNote This interface is defined in Java SE 17 Maintenance Release 1. * @since 17 */ interface EncapsulatorSpi { /** * The key encapsulation function. *

* Each invocation of this method must generate a new secret key and key * encapsulation message that is returned in an {@link KEM.Encapsulated} object. *

* An implementation must support the case where {@code from} is 0, * {@code to} is the same as the return value of {@code secretSize()}, * and {@code algorithm} is "Generic". * * @param from the initial index of the shared secret byte array * to be returned, inclusive * @param to the final index of the shared secret byte array * to be returned, exclusive * @param algorithm the algorithm name for the secret key that is returned * @return an {@link KEM.Encapsulated} object containing a portion of * the shared secret as a key with the specified algorithm, * key encapsulation message, and optional parameters. * @throws IndexOutOfBoundsException if {@code from < 0}, * {@code from > to}, or {@code to > secretSize()} * @throws NullPointerException if {@code algorithm} is {@code null} * @throws UnsupportedOperationException if the combination of * {@code from}, {@code to}, and {@code algorithm} * is not supported by the encapsulator * @see KEM.Encapsulated * @see KEM.Encapsulator#encapsulate(int, int, String) */ KEM.Encapsulated engineEncapsulate(int from, int to, String algorithm); /** * Returns the size of the shared secret. * * @return the size of the shared secret as a finite non-negative integer * @see KEM.Encapsulator#secretSize() */ int engineSecretSize(); /** * Returns the size of the key encapsulation message. * * @return the size of the key encapsulation message as a finite non-negative integer * @see KEM.Encapsulator#encapsulationSize() */ int engineEncapsulationSize(); } /** * The KEM decapsulator implementation, generated by * {@link #engineNewDecapsulator} on the KEM receiver side. * * @see KEM.Decapsulator * * @apiNote This interface is defined in Java SE 17 Maintenance Release 1. * @since 17 */ interface DecapsulatorSpi { /** * The key decapsulation function. *

* An invocation of this method recovers the secret key from the key * encapsulation message. *

* An implementation must support the case where {@code from} is 0, * {@code to} is the same as the return value of {@code secretSize()}, * and {@code algorithm} is "Generic". * * @param encapsulation the key encapsulation message from the sender. * The size must be equal to the value returned by * {@link #engineEncapsulationSize()} ()}, or a * {@code DecapsulateException} must be thrown. * @param from the initial index of the shared secret byte array * to be returned, inclusive * @param to the final index of the shared secret byte array * to be returned, exclusive * @param algorithm the algorithm name for the secret key that is returned * @return a portion of the shared secret as a {@code SecretKey} with * the specified algorithm * @throws DecapsulateException if an error occurs during the * decapsulation process * @throws IndexOutOfBoundsException if {@code from < 0}, * {@code from > to}, or {@code to > secretSize()} * @throws NullPointerException if {@code encapsulation} or * {@code algorithm} is {@code null} * @throws UnsupportedOperationException if the combination of * {@code from}, {@code to}, and {@code algorithm} * is not supported by the decapsulator * @see KEM.Decapsulator#decapsulate(byte[], int, int, String) */ SecretKey engineDecapsulate(byte[] encapsulation, int from, int to, String algorithm) throws DecapsulateException; /** * Returns the size of the shared secret. * * @return the size of the shared secret as a finite non-negative integer * @see KEM.Decapsulator#secretSize() */ int engineSecretSize(); /** * Returns the size of the key encapsulation message. * * @return the size of the key encapsulation message as a finite non-negative integer * @see KEM.Decapsulator#encapsulationSize() */ int engineEncapsulationSize(); } /** * Creates a KEM encapsulator on the KEM sender side. * * @param publicKey the receiver's public key, must not be {@code null} * @param spec the optional parameter, can be {@code null} * @param secureRandom the source of randomness for encapsulation. * If {@code null}, the implementation must provide * a default one. * @return the encapsulator for this key * @throws InvalidAlgorithmParameterException if {@code spec} is invalid * or one is required but {@code spec} is {@code null} * @throws InvalidKeyException if {@code publicKey} is {@code null} or invalid * @see KEM#newEncapsulator(PublicKey, AlgorithmParameterSpec, SecureRandom) */ EncapsulatorSpi engineNewEncapsulator(PublicKey publicKey, AlgorithmParameterSpec spec, SecureRandom secureRandom) throws InvalidAlgorithmParameterException, InvalidKeyException; /** * Creates a KEM decapsulator on the KEM receiver side. * * @param privateKey the receiver's private key, must not be {@code null} * @param spec the optional parameter, can be {@code null} * @return the decapsulator for this key * @throws InvalidAlgorithmParameterException if {@code spec} is invalid * or one is required but {@code spec} is {@code null} * @throws InvalidKeyException if {@code privateKey} is {@code null} or invalid * @see KEM#newDecapsulator(PrivateKey, AlgorithmParameterSpec) */ DecapsulatorSpi engineNewDecapsulator(PrivateKey privateKey, AlgorithmParameterSpec spec) throws InvalidAlgorithmParameterException, InvalidKeyException; } /** * An exception that is thrown by the * {@link javax.crypto.KEM.Decapsulator#decapsulate} method to denote an * error during decapsulation. * * @apiNote This class is defined in Java SE 17 Maintenance Release 1. * @since 17 */ public class DecapsulateException extends GeneralSecurityException { @java.io.Serial private static final long serialVersionUID = 21L; /** * Creates a {@code DecapsulateException} with the specified * detail message. * * @param message the detail message (which is saved for later retrieval * by the {@link #getMessage()} method). */ public DecapsulateException(String message); /** * Creates a {@code DecapsulateException} with the specified * detail message and cause. * * @param message the detail message (which is saved for later retrieval * by the {@link #getMessage()} method). * @param cause the cause (which is saved for later retrieval by the * {@link #getCause()} method). (A {@code null} value is permitted, * and indicates that the cause is nonexistent or unknown.) */ public DecapsulateException(String message, Throwable cause); }