| /* | |
| * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. | |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| * | |
| * This code is free software; you can redistribute it and/or modify it | |
| * under the terms of the GNU General Public License version 2 only, as | |
| * published by the Free Software Foundation. Oracle designates this | |
| * particular file as subject to the "Classpath" exception as provided | |
| * by Oracle in the LICENSE file that accompanied this code. | |
| * | |
| * This code is distributed in the hope that it will be useful, but WITHOUT | |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| * version 2 for more details (a copy is included in the LICENSE file that | |
| * accompanied this code). | |
| * | |
| * You should have received a copy of the GNU General Public License version | |
| * 2 along with this work; if not, write to the Free Software Foundation, | |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| * | |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| * or visit www.oracle.com if you need additional information or have any | |
| * questions. | |
| */ | |
| package javax.crypto; | |
| import sun.security.jca.GetInstance; | |
| import java.security.*; | |
| import java.security.InvalidAlgorithmParameterException; | |
| import java.security.spec.AlgorithmParameterSpec; | |
| import java.util.ArrayList; | |
| import java.util.Iterator; | |
| import java.util.List; | |
| import java.util.Objects; | |
| /** | |
| * 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. | |
| * <p> | |
| * The {@code getInstance} method creates a new {@code KEM} object that | |
| * implements the specified algorithm. | |
| * <p> | |
| * 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. | |
| * <p> | |
| * 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. | |
| * <p> | |
| * {@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. | |
| * <p> | |
| * | |
| * Example operation using a fictitious {@code KEM} algorithm {@code ABC}: | |
| * {@snippet lang = java: | |
| * // Receiver side | |
| * KeyPairGenerator g = KeyPairGenerator.getInstance("ABC"); | |
| * KeyPair kp = g.generateKeyPair(); | |
| * publishKey(kp.getPublic()); | |
| * | |
| * // Sender side | |
| * KEM senderKEM = KEM.getInstance("ABC"); | |
| * PublicKey receiverPublicKey = retrieveKey(); | |
| * ABCKEMParameterSpec senderSpec = new ABCKEMParameterSpec(args); | |
| * KEM.Encapsulator e = senderKEM.newEncapsulator( | |
| * receiverPublicKey, senderSpec, null); | |
| * KEM.Encapsulated enc = e.encapsulate(); | |
| * SecretKey senderSecret = enc.key(); | |
| * | |
| * sendBytes(enc.encapsulation()); | |
| * sendBytes(enc.params()); | |
| * | |
| * // Receiver side | |
| * byte[] ciphertext = receiveBytes(); | |
| * byte[] params = receiveBytes(); | |
| * | |
| * KEM receiverKEM = KEM.getInstance("ABC"); | |
| * AlgorithmParameters algParams = | |
| * AlgorithmParameters.getInstance("ABC"); | |
| * algParams.init(params); | |
| * ABCKEMParameterSpec receiverSpec = | |
| * algParams.getParameterSpec(ABCKEMParameterSpec.class); | |
| * KEM.Decapsulator d = | |
| * receiverKEM.newDecapsulator(kp.getPrivate(), receiverSpec); | |
| * SecretKey receiverSecret = d.decapsulate(ciphertext); | |
| * | |
| * // senderSecret and receiverSecret should now be equal. | |
| * } | |
| * | |
| * @since 21 | |
| */ | |
| 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. | |
| * <p> | |
| * Note: the key encapsulation message can be also referred to as ciphertext. | |
| * | |
| * @see #newEncapsulator(PublicKey, AlgorithmParameterSpec, SecureRandom) | |
| * @see Encapsulator#encapsulate(int, int, String) | |
| * | |
| * @since 21 | |
| */ | |
| public static final class Encapsulated { | |
| private final SecretKey key; | |
| private final byte[] encapsulation; | |
| private final byte[] params; | |
| /** | |
| * 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) { | |
| Objects.requireNonNull(key); | |
| Objects.requireNonNull(encapsulation); | |
| this.key = key; | |
| this.encapsulation = encapsulation.clone(); | |
| this.params = params == null ? null : params.clone(); | |
| } | |
| /** | |
| * Returns the {@code SecretKey}. | |
| * | |
| * @return the secret key | |
| */ | |
| public SecretKey key() { | |
| return key; | |
| } | |
| /** | |
| * Returns the key encapsulation message. | |
| * | |
| * @return the key encapsulation message. A new copy of the byte array | |
| * is returned. | |
| */ | |
| public byte[] encapsulation() { | |
| return encapsulation.clone(); | |
| } | |
| /** | |
| * 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() { | |
| return params == null ? null : params.clone(); | |
| } | |
| } | |
| /** | |
| * An encapsulator, generated by {@link #newEncapsulator} on the KEM | |
| * sender side. | |
| * <p> | |
| * 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. | |
| * | |
| * @since 21 | |
| */ | |
| public static final class Encapsulator { | |
| private final KEMSpi.EncapsulatorSpi e; | |
| private final Provider p; | |
| private Encapsulator(KEMSpi.EncapsulatorSpi e, Provider p) { | |
| assert e != null; | |
| assert p != null; | |
| this.e = e; | |
| this.p = p; | |
| } | |
| /** | |
| * Returns the name of the provider. | |
| * | |
| * @return the name of the provider | |
| */ | |
| public String providerName() { | |
| return p.getName(); | |
| } | |
| /** | |
| * The key encapsulation function. | |
| * <p> | |
| * This method is equivalent to | |
| * {@code encapsulate(0, secretSize(), "Generic")}. This combination | |
| * of arguments must be supported by every implementation. | |
| * <p> | |
| * 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() { | |
| return encapsulate(0, secretSize(), "Generic"); | |
| } | |
| /** | |
| * The key encapsulation function. | |
| * <p> | |
| * Each invocation of this method generates a new secret key and key | |
| * encapsulation message that is returned in an {@link Encapsulated} object. | |
| * <p> | |
| * 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. | |
| * See the SecretKey Algorithms section in the | |
| * <a href="{@docRoot}/../specs/security/standard-names.html#secretkey-algorithms"> | |
| * Java Security Standard Algorithm Names Specification</a> | |
| * for information about standard secret key algorithm names. | |
| * Specify "Generic" if the output will be used as the input keying | |
| * material of a key derivation function (KDF). | |
| * @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 | |
| * @spec security/standard-names.html Java Security Standard Algorithm Names | |
| */ | |
| public Encapsulated encapsulate(int from, int to, String algorithm) { | |
| return e.engineEncapsulate(from, to, algorithm); | |
| } | |
| /** | |
| * Returns the size of the shared secret. | |
| * <p> | |
| * 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() { | |
| int result = e.engineSecretSize(); | |
| assert result >= 0 && result != Integer.MAX_VALUE | |
| : "invalid engineSecretSize result"; | |
| return result; | |
| } | |
| /** | |
| * Returns the size of the key encapsulation message. | |
| * <p> | |
| * 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() { | |
| int result = e.engineEncapsulationSize(); | |
| assert result >= 0 && result != Integer.MAX_VALUE | |
| : "invalid engineEncapsulationSize result"; | |
| return result; | |
| } | |
| } | |
| /** | |
| * A decapsulator, generated by {@link #newDecapsulator} on the KEM | |
| * receiver side. | |
| * <p> | |
| * 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. | |
| * | |
| * @since 21 | |
| */ | |
| public static final class Decapsulator { | |
| private final KEMSpi.DecapsulatorSpi d; | |
| private final Provider p; | |
| private Decapsulator(KEMSpi.DecapsulatorSpi d, Provider p) { | |
| assert d != null; | |
| assert p != null; | |
| this.d = d; | |
| this.p = p; | |
| } | |
| /** | |
| * Returns the name of the provider. | |
| * | |
| * @return the name of the provider | |
| */ | |
| public String providerName() { | |
| return p.getName(); | |
| } | |
| /** | |
| * The key decapsulation function. | |
| * <p> | |
| * This method is equivalent to | |
| * {@code decapsulate(encapsulation, 0, secretSize(), "Generic")}. This | |
| * combination of arguments must be supported by every implementation. | |
| * <p> | |
| * 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 { | |
| return decapsulate(encapsulation, 0, secretSize(), "Generic"); | |
| } | |
| /** | |
| * The key decapsulation function. | |
| * <p> | |
| * An invocation of this method recovers the secret key from the key | |
| * encapsulation message. | |
| * <p> | |
| * 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. | |
| * See the SecretKey Algorithms section in the | |
| * <a href="{@docRoot}/../specs/security/standard-names.html#secretkey-algorithms"> | |
| * Java Security Standard Algorithm Names Specification</a> | |
| * for information about standard secret key algorithm names. | |
| * Specify "Generic" if the output will be used as the input keying | |
| * material of a key derivation function (KDF). | |
| * @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 | |
| * @spec security/standard-names.html Java Security Standard Algorithm Names | |
| */ | |
| public SecretKey decapsulate(byte[] encapsulation, | |
| int from, int to, String algorithm) | |
| throws DecapsulateException { | |
| return d.engineDecapsulate( | |
| encapsulation, | |
| from, to, | |
| algorithm); | |
| } | |
| /** | |
| * Returns the size of the shared secret. | |
| * <p> | |
| * 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() { | |
| int result = d.engineSecretSize(); | |
| assert result >= 0 && result != Integer.MAX_VALUE | |
| : "invalid engineSecretSize result"; | |
| return result; | |
| } | |
| /** | |
| * Returns the size of the key encapsulation message. | |
| * <p> | |
| * 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() { | |
| int result = d.engineEncapsulationSize(); | |
| assert result >= 0 && result != Integer.MAX_VALUE | |
| : "invalid engineEncapsulationSize result"; | |
| return result; | |
| } | |
| } | |
| private static final class DelayedKEM { | |
| private final Provider.Service[] list; // non empty array | |
| private DelayedKEM(Provider.Service[] list) { | |
| this.list = list; | |
| } | |
| private Encapsulator newEncapsulator(PublicKey publicKey, | |
| AlgorithmParameterSpec spec, SecureRandom secureRandom) | |
| throws InvalidAlgorithmParameterException, InvalidKeyException { | |
| if (publicKey == null) { | |
| throw new InvalidKeyException("input key is null"); | |
| } | |
| RuntimeException re = null; | |
| InvalidAlgorithmParameterException iape = null; | |
| InvalidKeyException ike = null; | |
| NoSuchAlgorithmException nsae = null; | |
| for (Provider.Service service : list) { | |
| if (!service.supportsParameter(publicKey)) { | |
| continue; | |
| } | |
| try { | |
| KEMSpi spi = (KEMSpi) service.newInstance(null); | |
| return new Encapsulator( | |
| spi.engineNewEncapsulator(publicKey, spec, secureRandom), | |
| service.getProvider()); | |
| } catch (NoSuchAlgorithmException e) { | |
| nsae = merge(nsae, e); | |
| } catch (InvalidAlgorithmParameterException e) { | |
| iape = merge(iape, e); | |
| } catch (InvalidKeyException e) { | |
| ike = merge(ike, e); | |
| } catch (RuntimeException e) { | |
| re = merge(re, e); | |
| } | |
| } | |
| if (iape != null) throw iape; | |
| if (ike != null) throw ike; | |
| if (nsae != null) { | |
| throw new InvalidKeyException("No installed provider found", nsae); | |
| } | |
| throw new InvalidKeyException("No installed provider supports this key: " | |
| + publicKey.getClass().getName(), re); | |
| } | |
| private static <T extends Exception> T merge(T e1, T e2) { | |
| if (e1 == null) { | |
| return e2; | |
| } else { | |
| e1.addSuppressed(e2); | |
| return e1; | |
| } | |
| } | |
| private Decapsulator newDecapsulator(PrivateKey privateKey, AlgorithmParameterSpec spec) | |
| throws InvalidAlgorithmParameterException, InvalidKeyException { | |
| if (privateKey == null) { | |
| throw new InvalidKeyException("input key is null"); | |
| } | |
| RuntimeException re = null; | |
| InvalidAlgorithmParameterException iape = null; | |
| InvalidKeyException ike = null; | |
| NoSuchAlgorithmException nsae = null; | |
| for (Provider.Service service : list) { | |
| if (!service.supportsParameter(privateKey)) { | |
| continue; | |
| } | |
| try { | |
| KEMSpi spi = (KEMSpi) service.newInstance(null); | |
| return new Decapsulator( | |
| spi.engineNewDecapsulator(privateKey, spec), | |
| service.getProvider()); | |
| } catch (NoSuchAlgorithmException e) { | |
| nsae = merge(nsae, e); | |
| } catch (InvalidAlgorithmParameterException e) { | |
| iape = merge(iape, e); | |
| } catch (InvalidKeyException e) { | |
| ike = merge(ike, e); | |
| } catch (RuntimeException e) { | |
| re = merge(re, e); | |
| } | |
| } | |
| if (iape != null) throw iape; | |
| if (ike != null) throw ike; | |
| if (nsae != null) { | |
| throw new InvalidKeyException("No installed provider found", nsae); | |
| } | |
| throw new InvalidKeyException("No installed provider supports this key: " | |
| + privateKey.getClass().getName(), re); | |
| } | |
| } | |
| // If delayed provider selection is needed | |
| private final DelayedKEM delayed; | |
| // otherwise | |
| private final KEMSpi spi; | |
| private final Provider provider; | |
| private final String algorithm; | |
| private KEM(String algorithm, KEMSpi spi, Provider provider) { | |
| assert spi != null; | |
| assert provider != null; | |
| this.delayed = null; | |
| this.spi = spi; | |
| this.provider = provider; | |
| this.algorithm = algorithm; | |
| } | |
| private KEM(String algorithm, DelayedKEM delayed) { | |
| assert delayed != null; | |
| this.delayed = delayed; | |
| this.spi = null; | |
| this.provider = null; | |
| this.algorithm = algorithm; | |
| } | |
| /** | |
| * 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 <a href= | |
| * "{@docRoot}/../specs/security/standard-names.html#kem-algorithms"> | |
| * Java Security Standard Algorithm Names Specification</a> | |
| * for information about standard KEM algorithm names. | |
| * @spec security/standard-names.html Java Security Standard 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 { | |
| Iterator<Provider.Service> t = GetInstance.getServices( | |
| "KEM", | |
| Objects.requireNonNull(algorithm, "null algorithm name")); | |
| List<Provider.Service> allowed = new ArrayList<>(); | |
| while (t.hasNext()) { | |
| Provider.Service s = t.next(); | |
| if (!JceSecurity.canUseProvider(s.getProvider())) { | |
| continue; | |
| } | |
| allowed.add(s); | |
| } | |
| if (allowed.isEmpty()) { | |
| throw new NoSuchAlgorithmException | |
| (algorithm + " KEM not available"); | |
| } | |
| return new KEM(algorithm, new DelayedKEM(allowed.toArray(new Provider.Service[0]))); | |
| } | |
| /** | |
| * 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 <a href= | |
| * "{@docRoot}/../specs/security/standard-names.html#kem-algorithms"> | |
| * Java Security Standard Algorithm Names Specification</a> | |
| * for information about standard KEM algorithm names. | |
| * @param provider the provider. If {@code null}, this method is equivalent | |
| * to {@link #getInstance(String)}. | |
| * @spec security/standard-names.html Java Security Standard Algorithm Names | |
| * @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 { | |
| if (provider == null) { | |
| return getInstance(algorithm); | |
| } | |
| GetInstance.Instance instance = JceSecurity.getInstance( | |
| "KEM", | |
| KEMSpi.class, | |
| Objects.requireNonNull(algorithm, "null algorithm name"), | |
| provider); | |
| return new KEM(algorithm, (KEMSpi) instance.impl, instance.provider); | |
| } | |
| /** | |
| * 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 <a href= | |
| * "{@docRoot}/../specs/security/standard-names.html#kem-algorithms"> | |
| * Java Security Standard Algorithm Names Specification</a> | |
| * for information about standard KEM algorithm names. | |
| * @param provider the provider. If {@code null}, this method is equivalent | |
| * to {@link #getInstance(String)}. | |
| * @spec security/standard-names.html Java Security Standard Algorithm Names | |
| * @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 { | |
| if (provider == null) { | |
| return getInstance(algorithm); | |
| } | |
| GetInstance.Instance instance = JceSecurity.getInstance( | |
| "KEM", | |
| KEMSpi.class, | |
| Objects.requireNonNull(algorithm, "null algorithm name"), | |
| provider); | |
| return new KEM(algorithm, (KEMSpi) instance.impl, instance.provider); | |
| } | |
| /** | |
| * Creates a KEM encapsulator on the KEM sender side. | |
| * <p> | |
| * 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 { | |
| try { | |
| return newEncapsulator(publicKey, null, null); | |
| } catch (InvalidAlgorithmParameterException e) { | |
| throw new UnsupportedOperationException( | |
| "AlgorithmParameterSpec must be provided", e); | |
| } | |
| } | |
| /** | |
| * Creates a KEM encapsulator on the KEM sender side. | |
| * <p> | |
| * 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 { | |
| try { | |
| return newEncapsulator(publicKey, null, secureRandom); | |
| } catch (InvalidAlgorithmParameterException e) { | |
| throw new UnsupportedOperationException( | |
| "AlgorithmParameterSpec must be provided", e); | |
| } | |
| } | |
| /** | |
| * Creates a KEM encapsulator on the KEM sender side. | |
| * <p> | |
| * 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 returned by the | |
| * {@link Encapsulated#params()} method within 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 { | |
| return delayed != null | |
| ? delayed.newEncapsulator(publicKey, spec, secureRandom) | |
| : new Encapsulator(spi.engineNewEncapsulator(publicKey, spec, secureRandom), provider); | |
| } | |
| /** | |
| * Creates a KEM decapsulator on the KEM receiver side. | |
| * <p> | |
| * 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 { | |
| try { | |
| return newDecapsulator(privateKey, null); | |
| } catch (InvalidAlgorithmParameterException e) { | |
| throw new UnsupportedOperationException(e); | |
| } | |
| } | |
| /** | |
| * 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 { | |
| return delayed != null | |
| ? delayed.newDecapsulator(privateKey, spec) | |
| : new Decapsulator(spi.engineNewDecapsulator(privateKey, spec), provider); | |
| } | |
| /** | |
| * 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() { | |
| return this.algorithm; | |
| } | |
| } |