| /* | |
| * Copyright (c) 1999, 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 java.security.AlgorithmParameters; | |
| import java.security.Provider; | |
| import java.security.Key; | |
| import java.security.Security; | |
| import java.security.NoSuchAlgorithmException; | |
| import java.security.NoSuchProviderException; | |
| import java.security.InvalidKeyException; | |
| import java.security.InvalidAlgorithmParameterException; | |
| import java.security.spec.AlgorithmParameterSpec; | |
| import java.util.Objects; | |
| import sun.security.jca.GetInstance.Instance; | |
| /** | |
| * This class provides the functionality of an exemption mechanism, examples | |
| * of which are <i>key recovery</i>, <i>key weakening</i>, and | |
| * <i>key escrow</i>. | |
| * | |
| * <p>Applications that use an exemption mechanism may be granted | |
| * stronger encryption capabilities than those which don't. | |
| * | |
| * @since 1.4 | |
| */ | |
| public class ExemptionMechanism { | |
| // The provider | |
| private final Provider provider; | |
| // The provider implementation (delegate) | |
| private final ExemptionMechanismSpi exmechSpi; | |
| // The name of the exemption mechanism. | |
| private final String mechanism; | |
| // Flag which indicates whether this ExemptionMechanism | |
| // result is generated successfully. | |
| private boolean done = false; | |
| // State information | |
| private boolean initialized = false; | |
| // Store away the key at init() time for later comparison. | |
| private Key keyStored = null; | |
| /** | |
| * Creates an {@code ExemptionMechanism} object. | |
| * | |
| * @param exmechSpi the delegate | |
| * @param provider the provider | |
| * @param mechanism the exemption mechanism | |
| */ | |
| protected ExemptionMechanism(ExemptionMechanismSpi exmechSpi, | |
| Provider provider, | |
| String mechanism) { | |
| this.exmechSpi = exmechSpi; | |
| this.provider = provider; | |
| this.mechanism = mechanism; | |
| } | |
| /** | |
| * Returns the exemption mechanism name of this | |
| * {@code ExemptionMechanism} object. | |
| * | |
| * <p>This is the same name that was specified in one of the | |
| * {@code getInstance} calls that created this | |
| * {@code ExemptionMechanism} object. | |
| * | |
| * @return the exemption mechanism name of this | |
| * {@code ExemptionMechanism} object. | |
| */ | |
| public final String getName() { | |
| return this.mechanism; | |
| } | |
| /** | |
| * Returns an {@code ExemptionMechanism} object that implements the | |
| * specified exemption mechanism algorithm. | |
| * | |
| * <p> This method traverses the list of registered security providers, | |
| * starting with the most preferred provider. | |
| * A new {@code ExemptionMechanism} object encapsulating the | |
| * {@code ExemptionMechanismSpi} implementation from the first | |
| * provider that supports the specified algorithm is returned. | |
| * | |
| * <p> Note that the list of registered providers may be retrieved via | |
| * the {@link Security#getProviders() Security.getProviders()} method. | |
| * | |
| * @implNote | |
| * The JDK Reference Implementation additionally uses the | |
| * {@code jdk.security.provider.preferred} | |
| * {@link Security#getProperty(String) Security} property to determine | |
| * the preferred provider order for the specified algorithm. This | |
| * may be different from the order of providers returned by | |
| * {@link Security#getProviders() Security.getProviders()}. | |
| * | |
| * @param algorithm the standard name of the requested exemption | |
| * mechanism. | |
| * See the ExemptionMechanism section in the | |
| * <a href= | |
| * "{@docRoot}/../specs/security/standard-names.html#exemption-mechanisms"> | |
| * Java Security Standard Algorithm Names Specification</a> | |
| * for information about standard exemption mechanism names. | |
| * | |
| * @spec security/standard-names.html Java Security Standard Algorithm Names | |
| * @return the new {@code ExemptionMechanism} object | |
| * | |
| * @throws NoSuchAlgorithmException if no {@code Provider} supports an | |
| * {@code ExemptionMechanismSpi} implementation for the | |
| * specified algorithm | |
| * | |
| * @throws NullPointerException if {@code algorithm} is {@code null} | |
| * | |
| * @see java.security.Provider | |
| */ | |
| public static final ExemptionMechanism getInstance(String algorithm) | |
| throws NoSuchAlgorithmException { | |
| Objects.requireNonNull(algorithm, "null algorithm name"); | |
| Instance instance = JceSecurity.getInstance("ExemptionMechanism", | |
| ExemptionMechanismSpi.class, algorithm); | |
| return new ExemptionMechanism((ExemptionMechanismSpi)instance.impl, | |
| instance.provider, algorithm); | |
| } | |
| /** | |
| * Returns an {@code ExemptionMechanism} object that implements the | |
| * specified exemption mechanism algorithm. | |
| * | |
| * <p> A new {@code ExemptionMechanism} object encapsulating the | |
| * {@code ExemptionMechanismSpi} implementation from the specified | |
| * provider is returned. The specified provider must be registered | |
| * in the security provider list. | |
| * | |
| * <p> Note that the list of registered providers may be retrieved via | |
| * the {@link Security#getProviders() Security.getProviders()} method. | |
| * | |
| * @param algorithm the standard name of the requested exemption mechanism. | |
| * See the ExemptionMechanism section in the | |
| * <a href= | |
| * "{@docRoot}/../specs/security/standard-names.html#exemption-mechanisms"> | |
| * Java Security Standard Algorithm Names Specification</a> | |
| * for information about standard exemption mechanism names. | |
| * | |
| * @param provider the name of the provider. | |
| * | |
| * @spec security/standard-names.html Java Security Standard Algorithm Names | |
| * @return the new {@code ExemptionMechanism} object | |
| * | |
| * @throws IllegalArgumentException if the {@code provider} | |
| * is {@code null} or empty | |
| * | |
| * @throws NoSuchAlgorithmException if an {@code ExemptionMechanismSpi} | |
| * implementation for the specified algorithm is not | |
| * available from the specified provider | |
| * | |
| * @throws NoSuchProviderException if the specified provider is not | |
| * registered in the security provider list | |
| * | |
| * @throws NullPointerException if {@code algorithm} is {@code null} | |
| * | |
| * @see java.security.Provider | |
| */ | |
| public static final ExemptionMechanism getInstance(String algorithm, | |
| String provider) throws NoSuchAlgorithmException, | |
| NoSuchProviderException { | |
| Objects.requireNonNull(algorithm, "null algorithm name"); | |
| Instance instance = JceSecurity.getInstance("ExemptionMechanism", | |
| ExemptionMechanismSpi.class, algorithm, provider); | |
| return new ExemptionMechanism((ExemptionMechanismSpi)instance.impl, | |
| instance.provider, algorithm); | |
| } | |
| /** | |
| * Returns an {@code ExemptionMechanism} object that implements the | |
| * specified exemption mechanism algorithm. | |
| * | |
| * <p> A new {@code ExemptionMechanism} object encapsulating the | |
| * {@code ExemptionMechanismSpi} implementation from the specified | |
| * provider object is returned. Note that the specified provider object | |
| * does not have to be registered in the provider list. | |
| * | |
| * @param algorithm the standard name of the requested exemption mechanism. | |
| * See the ExemptionMechanism section in the | |
| * <a href= | |
| * "{@docRoot}/../specs/security/standard-names.html#exemption-mechanisms"> | |
| * Java Security Standard Algorithm Names Specification</a> | |
| * for information about standard exemption mechanism names. | |
| * | |
| * @param provider the provider. | |
| * | |
| * @spec security/standard-names.html Java Security Standard Algorithm Names | |
| * @return the new {@code ExemptionMechanism} object | |
| * | |
| * @throws IllegalArgumentException if the {@code provider} | |
| * is {@code null} | |
| * | |
| * @throws NoSuchAlgorithmException if an {@code ExemptionMechanismSpi} | |
| * implementation for the specified algorithm is not available | |
| * from the specified {@code Provider} object | |
| * | |
| * @exception NullPointerException if {@code algorithm} is {@code null} | |
| * | |
| * @see java.security.Provider | |
| */ | |
| public static final ExemptionMechanism getInstance(String algorithm, | |
| Provider provider) throws NoSuchAlgorithmException { | |
| Objects.requireNonNull(algorithm, "null algorithm name"); | |
| Instance instance = JceSecurity.getInstance("ExemptionMechanism", | |
| ExemptionMechanismSpi.class, algorithm, provider); | |
| return new ExemptionMechanism((ExemptionMechanismSpi)instance.impl, | |
| instance.provider, algorithm); | |
| } | |
| /** | |
| * Returns the provider of this {@code ExemptionMechanism} object. | |
| * | |
| * @return the provider of this {@code ExemptionMechanism} object. | |
| */ | |
| public final Provider getProvider() { | |
| return this.provider; | |
| } | |
| /** | |
| * Returns whether the result blob has been generated successfully by this | |
| * exemption mechanism. | |
| * | |
| * <p>The method also makes sure that the key passed in is the same as | |
| * the one this exemption mechanism used in initializing and generating | |
| * phases. | |
| * | |
| * @param key the key the crypto is going to use. | |
| * | |
| * @return whether the result blob of the same key has been generated | |
| * successfully by this exemption mechanism; {@code false} if {@code key} | |
| * is {@code null}. | |
| * | |
| * @exception ExemptionMechanismException if problem(s) encountered | |
| * while determining whether the result blob has been generated successfully | |
| * by this exemption mechanism object. | |
| */ | |
| public final boolean isCryptoAllowed(Key key) | |
| throws ExemptionMechanismException { | |
| boolean ret = false; | |
| if (done && (key != null)) { | |
| // Check if the key passed in is the same as the one | |
| // this exemption mechanism used. | |
| ret = keyStored.equals(key); | |
| } | |
| return ret; | |
| } | |
| /** | |
| * Returns the length in bytes that an output buffer would need to be in | |
| * order to hold the result of the next | |
| * {@link #genExemptionBlob(byte[]) genExemptionBlob} | |
| * operation, given the input length {@code inputLen} (in bytes). | |
| * | |
| * <p>The actual output length of the next | |
| * {@link #genExemptionBlob(byte[]) genExemptionBlob} | |
| * call may be smaller than the length returned by this method. | |
| * | |
| * @param inputLen the input length (in bytes) | |
| * | |
| * @return the required output buffer size (in bytes) | |
| * | |
| * @exception IllegalStateException if this exemption mechanism is in a | |
| * wrong state (e.g., has not yet been initialized) | |
| */ | |
| public final int getOutputSize(int inputLen) throws IllegalStateException { | |
| if (!initialized) { | |
| throw new IllegalStateException( | |
| "ExemptionMechanism not initialized"); | |
| } | |
| if (inputLen < 0) { | |
| throw new IllegalArgumentException( | |
| "Input size must be equal to " + "or greater than zero"); | |
| } | |
| return exmechSpi.engineGetOutputSize(inputLen); | |
| } | |
| /** | |
| * Initializes this exemption mechanism with a key. | |
| * | |
| * <p>If this exemption mechanism requires any algorithm parameters | |
| * that cannot be derived from the given {@code key}, the | |
| * underlying exemption mechanism implementation is supposed to | |
| * generate the required parameters itself (using provider-specific | |
| * default values); in the case that algorithm parameters must be | |
| * specified by the caller, an {@code InvalidKeyException} is raised. | |
| * | |
| * @param key the key for this exemption mechanism | |
| * | |
| * @exception InvalidKeyException if the given key is inappropriate for | |
| * this exemption mechanism. | |
| * @exception ExemptionMechanismException if problem(s) encountered in the | |
| * process of initializing. | |
| */ | |
| public final void init(Key key) | |
| throws InvalidKeyException, ExemptionMechanismException { | |
| done = false; | |
| initialized = false; | |
| keyStored = key; | |
| exmechSpi.engineInit(key); | |
| initialized = true; | |
| } | |
| /** | |
| * Initializes this exemption mechanism with a key and a set of algorithm | |
| * parameters. | |
| * | |
| * <p>If this exemption mechanism requires any algorithm parameters | |
| * and {@code params} is {@code null}, the underlying exemption | |
| * mechanism implementation is supposed to generate the required | |
| * parameters itself (using provider-specific default values); in the case | |
| * that algorithm parameters must be specified by the caller, an | |
| * {@code InvalidAlgorithmParameterException} is raised. | |
| * | |
| * @param key the key for this exemption mechanism | |
| * @param params the algorithm parameters | |
| * | |
| * @exception InvalidKeyException if the given key is inappropriate for | |
| * this exemption mechanism. | |
| * @exception InvalidAlgorithmParameterException if the given algorithm | |
| * parameters are inappropriate for this exemption mechanism. | |
| * @exception ExemptionMechanismException if problem(s) encountered in the | |
| * process of initializing. | |
| */ | |
| public final void init(Key key, AlgorithmParameterSpec params) | |
| throws InvalidKeyException, InvalidAlgorithmParameterException, | |
| ExemptionMechanismException { | |
| done = false; | |
| initialized = false; | |
| keyStored = key; | |
| exmechSpi.engineInit(key, params); | |
| initialized = true; | |
| } | |
| /** | |
| * Initializes this exemption mechanism with a key and a set of algorithm | |
| * parameters. | |
| * | |
| * <p>If this exemption mechanism requires any algorithm parameters | |
| * and {@code params} is {@code null}, the underlying exemption mechanism | |
| * implementation is supposed to generate the required parameters itself | |
| * (using provider-specific default values); in the case that algorithm | |
| * parameters must be specified by the caller, an | |
| * {@code InvalidAlgorithmParameterException} is raised. | |
| * | |
| * @param key the key for this exemption mechanism | |
| * @param params the algorithm parameters | |
| * | |
| * @exception InvalidKeyException if the given key is inappropriate for | |
| * this exemption mechanism. | |
| * @exception InvalidAlgorithmParameterException if the given algorithm | |
| * parameters are inappropriate for this exemption mechanism. | |
| * @exception ExemptionMechanismException if problem(s) encountered in the | |
| * process of initializing. | |
| */ | |
| public final void init(Key key, AlgorithmParameters params) | |
| throws InvalidKeyException, InvalidAlgorithmParameterException, | |
| ExemptionMechanismException { | |
| done = false; | |
| initialized = false; | |
| keyStored = key; | |
| exmechSpi.engineInit(key, params); | |
| initialized = true; | |
| } | |
| /** | |
| * Generates the exemption mechanism key blob. | |
| * | |
| * @return the new buffer with the result key blob. | |
| * | |
| * @exception IllegalStateException if this exemption mechanism is in | |
| * a wrong state (e.g., has not been initialized). | |
| * @exception ExemptionMechanismException if problem(s) encountered in the | |
| * process of generating. | |
| */ | |
| public final byte[] genExemptionBlob() throws IllegalStateException, | |
| ExemptionMechanismException { | |
| if (!initialized) { | |
| throw new IllegalStateException( | |
| "ExemptionMechanism not initialized"); | |
| } | |
| byte[] blob = exmechSpi.engineGenExemptionBlob(); | |
| done = true; | |
| return blob; | |
| } | |
| /** | |
| * Generates the exemption mechanism key blob, and stores the result in | |
| * the {@code output} buffer. | |
| * | |
| * <p>If the {@code output} buffer is too small to hold the result, | |
| * a {@code ShortBufferException} is thrown. In this case, repeat this | |
| * call with a larger output buffer. Use | |
| * {@link #getOutputSize(int) getOutputSize} to determine how big | |
| * the output buffer should be. | |
| * | |
| * @param output the buffer for the result | |
| * | |
| * @return the number of bytes stored in {@code output} | |
| * | |
| * @exception IllegalStateException if this exemption mechanism is in | |
| * a wrong state (e.g., has not been initialized). | |
| * @exception ShortBufferException if the given output buffer is too small | |
| * to hold the result. | |
| * @exception ExemptionMechanismException if problem(s) encountered in the | |
| * process of generating. | |
| */ | |
| public final int genExemptionBlob(byte[] output) | |
| throws IllegalStateException, ShortBufferException, | |
| ExemptionMechanismException { | |
| if (!initialized) { | |
| throw new IllegalStateException | |
| ("ExemptionMechanism not initialized"); | |
| } | |
| int n = exmechSpi.engineGenExemptionBlob(output, 0); | |
| done = true; | |
| return n; | |
| } | |
| /** | |
| * Generates the exemption mechanism key blob, and stores the result in | |
| * the {@code output} buffer, starting at {@code outputOffset} | |
| * inclusive. | |
| * | |
| * <p>If the {@code output} buffer is too small to hold the result, | |
| * a {@code ShortBufferException} is thrown. In this case, repeat this | |
| * call with a larger output buffer. Use | |
| * {@link #getOutputSize(int) getOutputSize} to determine how big | |
| * the output buffer should be. | |
| * | |
| * @param output the buffer for the result | |
| * @param outputOffset the offset in {@code output} where the result | |
| * is stored | |
| * | |
| * @return the number of bytes stored in {@code output} | |
| * | |
| * @exception IllegalStateException if this exemption mechanism is in | |
| * a wrong state (e.g., has not been initialized). | |
| * @exception ShortBufferException if the given output buffer is too small | |
| * to hold the result. | |
| * @exception ExemptionMechanismException if problem(s) encountered in the | |
| * process of generating. | |
| */ | |
| public final int genExemptionBlob(byte[] output, int outputOffset) | |
| throws IllegalStateException, ShortBufferException, | |
| ExemptionMechanismException { | |
| if (!initialized) { | |
| throw new IllegalStateException | |
| ("ExemptionMechanism not initialized"); | |
| } | |
| int n = exmechSpi.engineGenExemptionBlob(output, outputOffset); | |
| done = true; | |
| return n; | |
| } | |
| } |