/*
* Copyright (c) 1997, 2022, 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.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.regex.*;
import java.security.*;
import java.security.Provider.Service;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.InvalidParameterSpecException;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import javax.crypto.spec.*;
import java.nio.ByteBuffer;
import java.nio.ReadOnlyBufferException;
import sun.security.util.Debug;
import sun.security.jca.*;
import sun.security.util.KnownOIDs;
/**
* This class provides the functionality of a cryptographic cipher for
* encryption and decryption. It forms the core of the Java Cryptographic
* Extension (JCE) framework.
*
* <p>In order to create a {@code Cipher} object, the application calls the
* cipher's {@code getInstance} method, and passes the name of the
* requested <i>transformation</i> to it. Optionally, the name of a provider
* may be specified.
*
* <p>A <i>transformation</i> is a string that describes the operation (or
* set of operations) to be performed on the given input, to produce some
* output. A transformation always includes the name of a cryptographic
* algorithm (e.g., <i>AES</i>), and may be followed by a feedback mode and
* padding scheme.
*
* <p> A transformation is of the form:
*
* <ul>
* <li>"<i>algorithm/mode/padding</i>" or
*
* <li>"<i>algorithm</i>"
* </ul>
*
* <P> (in the latter case,
* provider-specific default values for the mode and padding scheme are used).
* For example, the following is a valid transformation:
*
* <pre>
* Cipher c = Cipher.getInstance("<i>AES/CBC/PKCS5Padding</i>");
* </pre>
*
* Using modes such as {@code CFB} and {@code OFB}, block
* ciphers can encrypt data in units smaller than the cipher's actual
* block size. When requesting such a mode, you may optionally specify
* the number of bits to be processed at a time by appending this number
* to the mode name as shown in the "{@code AES/CFB8/NoPadding}" and
* "{@code AES/OFB32/PKCS5Padding}" transformations. If no such
* number is specified, a provider-specific default is used.
* (See the
* {@extLink security_guide_jdk_providers JDK Providers Documentation}
* for the JDK Providers default values.)
* Thus, block ciphers can be turned into byte-oriented stream ciphers by
* using an 8 bit mode such as CFB8 or OFB8.
* <p>
* Modes such as Authenticated Encryption with Associated Data (AEAD)
* provide authenticity assurances for both confidential data and
* Additional Associated Data (AAD) that is not encrypted. (Please see
* <a href="http://www.ietf.org/rfc/rfc5116.txt"> RFC 5116 </a> for more
* information on AEAD and AAD algorithms such as GCM/CCM.) Both
* confidential and AAD data can be used when calculating the
* authentication tag (similar to a {@link Mac}). This tag is appended
* to the ciphertext during encryption, and is verified on decryption.
* <p>
* AEAD modes such as GCM/CCM perform all AAD authenticity calculations
* before starting the ciphertext authenticity calculations. To avoid
* implementations having to internally buffer ciphertext, all AAD data
* must be supplied to GCM/CCM implementations (via the {@code updateAAD}
* methods) <b>before</b> the ciphertext is processed (via
* the {@code update} and {@code doFinal} methods).
* <p>
* Note that GCM mode has a uniqueness requirement on IVs used in
* encryption with a given key. When IVs are repeated for GCM
* encryption, such usages are subject to forgery attacks. Thus, after
* each encryption operation using GCM mode, callers should re-initialize
* the {@code Cipher} objects with GCM parameters which have a different IV
* value.
* <pre>
* GCMParameterSpec s = ...;
* cipher.init(..., s);
*
* // If the GCM parameters were generated by the provider, it can
* // be retrieved by:
* // cipher.getParameters().getParameterSpec(GCMParameterSpec.class);
*
* cipher.updateAAD(...); // AAD
* cipher.update(...); // Multi-part update
* cipher.doFinal(...); // conclusion of operation
*
* // Use a different IV value for every encryption
* byte[] newIv = ...;
* s = new GCMParameterSpec(s.getTLen(), newIv);
* cipher.init(..., s);
* ...
*
* </pre>
* The ChaCha20 and ChaCha20-Poly1305 algorithms have a similar requirement
* for unique nonces with a given key. After each encryption or decryption
* operation, callers should re-initialize their ChaCha20 or ChaCha20-Poly1305
* ciphers with parameters that specify a different nonce value. Please
* see <a href="https://tools.ietf.org/html/rfc7539">RFC 7539</a> for more
* information on the ChaCha20 and ChaCha20-Poly1305 algorithms.
* <p>
* Every implementation of the Java platform is required to support
* the following standard {@code Cipher} object transformations with
* the keysizes in parentheses:
* <ul>
* <li>{@code AES/CBC/NoPadding} (128)</li>
* <li>{@code AES/CBC/PKCS5Padding} (128)</li>
* <li>{@code AES/ECB/NoPadding} (128)</li>
* <li>{@code AES/ECB/PKCS5Padding} (128)</li>
* <li>{@code AES/GCM/NoPadding} (128)</li>
* <li>{@code DESede/CBC/NoPadding} (168)</li>
* <li>{@code DESede/CBC/PKCS5Padding} (168)</li>
* <li>{@code DESede/ECB/NoPadding} (168)</li>
* <li>{@code DESede/ECB/PKCS5Padding} (168)</li>
* <li>{@code RSA/ECB/PKCS1Padding} (1024, 2048)</li>
* <li>{@code RSA/ECB/OAEPWithSHA-1AndMGF1Padding} (1024, 2048)</li>
* <li>{@code RSA/ECB/OAEPWithSHA-256AndMGF1Padding} (1024, 2048)</li>
* </ul>
* These transformations are described in the
* <a href="{@docRoot}/../specs/security/standard-names.html#cipher-algorithms">
* Cipher section</a> of the
* Java Security Standard Algorithm Names Specification.
* Consult the release documentation for your implementation to see if any
* other transformations are supported.
*
* @author Jan Luehe
* @see KeyGenerator
* @see SecretKey
* @since 1.4
*/
public class Cipher {
private static final Debug debug =
Debug.getInstance(
"jca",
"Cipher");
private static final Debug pdebug =
Debug.getInstance(
"provider",
"Provider");
private static final boolean skipDebug =
Debug.isOn(
"engine=") && !Debug.isOn(
"cipher");
/**
* Constant used to initialize cipher to encryption mode.
*/
public static final int ENCRYPT_MODE = 1;
/**
* Constant used to initialize cipher to decryption mode.
*/
public static final int DECRYPT_MODE = 2;
/**
* Constant used to initialize cipher to key-wrapping mode.
*/
public static final int WRAP_MODE = 3;
/**
* Constant used to initialize cipher to key-unwrapping mode.
*/
public static final int UNWRAP_MODE = 4;
/**
* Constant used to indicate the to-be-unwrapped key is a "public key".
*/
public static final int PUBLIC_KEY = 1;
/**
* Constant used to indicate the to-be-unwrapped key is a "private key".
*/
public static final int PRIVATE_KEY = 2;
/**
* Constant used to indicate the to-be-unwrapped key is a "secret key".
*/
public static final int SECRET_KEY = 3;
// The provider
private Provider provider;
// The provider implementation (delegate)
private CipherSpi spi;
// The transformation
private final String transformation;
// Crypto permission representing the maximum allowable cryptographic
// strength that this cipher can be used for. (The cryptographic
// strength is a function of the keysize and algorithm parameters encoded
// in the crypto permission.)
private CryptoPermission cryptoPerm;
// The exemption mechanism that needs to be enforced
private ExemptionMechanism exmech;
// Flag which indicates whether or not this cipher has been initialized
private boolean initialized =
false;
// The operation mode - store the operation mode after the
// cipher has been initialized.
private int opmode = 0;
// next SPI to try in provider selection
// null once provider is selected
private CipherSpi firstSpi;
// next service to try in provider selection
// null once provider is selected
private Service firstService;
// remaining services to try in provider selection
// null once provider is selected
private Iterator<Service> serviceIterator;
// list of transform Strings to lookup in the provider
private List<Transform> transforms;
private final Object lock;
/**
* Creates a {@code Cipher} object.
*
* @param cipherSpi the delegate
* @param provider the provider
* @param transformation the transformation
* @throws NullPointerException if {@code provider} is {@code null}
* @throws IllegalArgumentException if the supplied arguments
* are deemed invalid for constructing the {@code Cipher} object
*/
protected Cipher(CipherSpi cipherSpi,
Provider provider,
String transformation) {
// See bug 4341369 & 4334690 for more info.
// If the caller is trusted, then okay.
// Otherwise throw an IllegalArgumentException.
if (!JceSecurityManager.INSTANCE.isCallerTrusted(
JceSecurityManager.WALKER.getCallerClass(), provider)) {
throw new IllegalArgumentException(
"Cannot construct cipher");
}
this.spi = cipherSpi;
this.provider = provider;
this.transformation = transformation;
this.cryptoPerm = CryptoAllPermission.INSTANCE;
this.lock =
null;
}
/**
* Creates a {code Cipher} object. Called internally by {code NullCipher}.
*
* @param cipherSpi the delegate
* @param transformation the transformation
*/
Cipher(CipherSpi cipherSpi, String transformation) {
this.spi = cipherSpi;
this.transformation = transformation;
this.cryptoPerm = CryptoAllPermission.INSTANCE;
this.lock =
null;
}
private Cipher(CipherSpi firstSpi, Service firstService,
Iterator<Service> serviceIterator, String transformation,
List<Transform> transforms) {
this.firstSpi = firstSpi;
this.firstService = firstService;
this.serviceIterator = serviceIterator;
this.transforms = transforms;
this.transformation = transformation;
this.lock =
new Object();
}
private static String[] tokenizeTransformation(String transformation)
throws NoSuchAlgorithmException {
if (transformation ==
null) {
throw new NoSuchAlgorithmException(
"No transformation given");
}
/*
* array containing the components of a cipher transformation:
*
* index 0: algorithm component (e.g., AES)
* index 1: feedback component (e.g., CFB)
* index 2: padding component (e.g., PKCS5Padding)
*/
String[] parts =
new String[3];
int count = 0;
StringTokenizer parser =
new StringTokenizer(transformation,
"/");
try {
while (parser.hasMoreTokens() && count < 3) {
parts[count++] = parser.nextToken().trim();
}
if (count == 0 || count == 2) {
throw new NoSuchAlgorithmException(
"Invalid transformation"
+
" format:" +
transformation);
}
// treats all subsequent tokens as part of padding
if (count == 3 && parser.hasMoreTokens()) {
parts[2] = parts[2] + parser.nextToken(
"\r\n");
}
}
catch (NoSuchElementException e) {
throw new NoSuchAlgorithmException(
"Invalid transformation " +
"format:" + transformation);
}
if ((parts[0] ==
null) || (parts[0].isEmpty())) {
throw new NoSuchAlgorithmException(
"Invalid transformation: " +
"algorithm not specified-"
+ transformation);
}
return parts;
}
// Provider attribute name for supported chaining mode
private static final String ATTR_MODE =
"SupportedModes";
// Provider attribute name for supported padding names
private static final String ATTR_PAD =
"SupportedPaddings";
// constants indicating whether the provider supports
// a given mode or padding
private static final int S_NO = 0;
// does not support
private static final int S_MAYBE = 1;
// unable to determine
private static final int S_YES = 2;
// does support
/**
* Nested class to deal with modes and paddings.
*/
private static class Transform {
// transform string to lookup in the provider
final String transform;
// the mode/padding suffix in upper case. for example, if the algorithm
// to lookup is "AES/CBC/PKCS5Padding" suffix is "/CBC/PKCS5PADDING"
// if lookup is "AES", suffix is the empty string
// needed because aliases prevent straight transform.equals()
final String suffix;
// value to pass to setMode() or null if no such call required
final String mode;
// value to pass to setPadding() or null if no such call required
final String pad;
Transform(String alg, String suffix, String mode, String pad) {
this.transform = alg + suffix;
this.suffix = suffix.toUpperCase(Locale.ENGLISH);
this.mode = mode;
this.pad = pad;
}
// set mode and padding for the given SPI
void setModePadding(CipherSpi spi)
throws NoSuchAlgorithmException,
NoSuchPaddingException {
if (mode !=
null) {
spi.engineSetMode(mode);
}
if (pad !=
null) {
spi.engineSetPadding(pad);
}
}
// check whether the given services supports the mode and
// padding described by this Transform
int supportsModePadding(Service s) {
int smode = supportsMode(s);
if (smode == S_NO) {
return smode;
}
int spad = supportsPadding(s);
// our constants are defined so that Math.min() is a tri-valued AND
return Math.min(smode, spad);
}
// separate methods for mode and padding
// called directly by cipher only to throw the correct exception
int supportsMode(Service s) {
return supports(s, ATTR_MODE, mode);
}
int supportsPadding(Service s) {
return supports(s, ATTR_PAD, pad);
}
private static int supports(Service s, String attrName, String value) {
if (value ==
null) {
return S_YES;
}
String regexp = s.getAttribute(attrName);
if (regexp ==
null) {
return S_MAYBE;
}
return matches(regexp, value) ? S_YES : S_NO;
}
// ConcurrentMap<String,Pattern> for previously compiled patterns
private static final ConcurrentMap<String, Pattern> patternCache =
new ConcurrentHashMap<String, Pattern>();
private static boolean matches(String regexp, String str) {
Pattern pattern = patternCache.get(regexp);
if (pattern ==
null) {
pattern = Pattern.compile(regexp);
patternCache.putIfAbsent(regexp, pattern);
}
return pattern.matcher(str.toUpperCase(Locale.ENGLISH)).matches();
}
}
private static List<Transform> getTransforms(String transformation)
throws NoSuchAlgorithmException {
String[] parts = tokenizeTransformation(transformation);
String alg = parts[0];
String mode = parts[1];
String pad = parts[2];
if ((mode !=
null) && (mode.isEmpty())) {
mode =
null;
}
if ((pad !=
null) && (pad.isEmpty())) {
pad =
null;
}
if ((mode ==
null) && (pad ==
null)) {
// AES
Transform tr =
new Transform(alg,
"",
null,
null);
return Collections.singletonList(tr);
}
else {
// if ((mode != null) && (pad != null)) {
// AES/CBC/PKCS5Padding
List<Transform> list =
new ArrayList<>(4);
list.add(
new Transform(alg,
"/" + mode +
"/" + pad,
null,
null));
list.add(
new Transform(alg,
"/" + mode,
null, pad));
list.add(
new Transform(alg,
"//" + pad, mode, null));
list.add(
new Transform(alg,
"", mode, pad));
return list;
}
}
// get the transform matching the specified service
private static Transform getTransform(Service s,
List<Transform> transforms) {
String alg = s.getAlgorithm().toUpperCase(Locale.ENGLISH);
for (Transform tr : transforms) {
if (alg.endsWith(tr.suffix)) {
return tr;
}
}
return null;
}
/**
* Returns a {@code Cipher} object that implements the specified
* transformation.
*
* <p> This method traverses the list of registered security providers,
* starting with the most preferred provider.
* A new {@code Cipher} object encapsulating the
* {@code CipherSpi} 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.
*
* @apiNote
* It is recommended to use a transformation that fully specifies the
* algorithm, mode, and padding. By not doing so, the provider will
* use a default for the mode and padding which may not meet the security
* requirements of your application.
*
* @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 than the order of providers returned by
* {@link Security#getProviders() Security.getProviders()}.
* See also the Cipher Transformations section of the {@extLink
* security_guide_jdk_providers JDK Providers} document for information
* on the transformation defaults used by JDK providers.
*
* @param transformation the name of the transformation, e.g.,
* <i>AES/CBC/PKCS5Padding</i>.
* See the Cipher section in the <a href=
* "{@docRoot}/../specs/security/standard-names.html#cipher-algorithms">
* Java Security Standard Algorithm Names Specification</a>
* for information about standard transformation names.
*
* @return a {@code Cipher} object that implements the requested
* transformation
*
* @throws NoSuchAlgorithmException if {@code transformation}
* is {@code null}, empty, in an invalid format,
* or if no provider supports a {@code CipherSpi}
* implementation for the specified algorithm
*
* @throws NoSuchPaddingException if {@code transformation}
* contains a padding scheme that is not available
*
* @see java.security.Provider
*/
public static final Cipher getInstance(String transformation)
throws NoSuchAlgorithmException, NoSuchPaddingException
{
if ((transformation ==
null) || transformation.isEmpty()) {
throw new NoSuchAlgorithmException(
"Null or empty transformation");
}
List<Transform> transforms = getTransforms(transformation);
List<ServiceId> cipherServices =
new ArrayList<>(transforms.size());
for (Transform transform : transforms) {
cipherServices.add(
new ServiceId(
"Cipher", transform.transform));
}
List<Service> services = GetInstance.getServices(cipherServices);
// make sure there is at least one service from a signed provider
// and that it can use the specified mode and padding
Iterator<Service> t = services.iterator();
Exception failure =
null;
while (t.hasNext()) {
Service s = t.next();
if (JceSecurity.canUseProvider(s.getProvider()) ==
false) {
continue;
}
Transform tr = getTransform(s, transforms);
if (tr ==
null) {
// should never happen
continue;
}
int canuse = tr.supportsModePadding(s);
if (canuse == S_NO) {
// does not support mode or padding we need, ignore
continue;
}
// S_YES, S_MAYBE
// even when mode and padding are both supported, they
// may not be used together, try out and see if it works
try {
CipherSpi spi = (CipherSpi)s.newInstance(
null);
tr.setModePadding(spi);
// specify null instead of spi for delayed provider selection
return new Cipher(
null, s, t, transformation, transforms);
}
catch (Exception e) {
failure = e;
}
}
throw new NoSuchAlgorithmException
(
"Cannot find any provider supporting " + transformation, failure);
}
/**
* Returns a {@code Cipher} object that implements the specified
* transformation.
*
* <p> A new {@code Cipher} object encapsulating the
* {@code CipherSpi} 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.
*
* @apiNote
* It is recommended to use a transformation that fully specifies the
* algorithm, mode, and padding. By not doing so, the provider will
* use a default for the mode and padding which may not meet the security
* requirements of your application.
*
* @implNote
* See the Cipher Transformations section of the {@extLink
* security_guide_jdk_providers JDK Providers} document for information
* on the transformation defaults used by JDK providers.
*
* @param transformation the name of the transformation,
* e.g., <i>AES/CBC/PKCS5Padding</i>.
* See the Cipher section in the <a href=
* "{@docRoot}/../specs/security/standard-names.html#cipher-algorithms">
* Java Security Standard Algorithm Names Specification</a>
* for information about standard transformation names.
*
* @param provider the name of the provider
*
* @return a {@code Cipher} object that implements the requested
* transformation
*
* @throws IllegalArgumentException if the {@code provider}
* is {@code null} or empty
*
* @throws NoSuchAlgorithmException if {@code transformation}
* is {@code null}, empty, in an invalid format,
* or if a {@code CipherSpi} implementation for the
* specified algorithm is not available from the specified
* provider
*
* @throws NoSuchPaddingException if {@code transformation}
* contains a padding scheme that is not available
*
* @throws NoSuchProviderException if the specified provider is not
* registered in the security provider list
*
* @see java.security.Provider
*/
public static final Cipher getInstance(String transformation,
String provider)
throws NoSuchAlgorithmException, NoSuchProviderException,
NoSuchPaddingException
{
if ((transformation ==
null) || transformation.isEmpty()) {
throw new NoSuchAlgorithmException(
"Null or empty transformation");
}
if ((provider ==
null) || (provider.isEmpty())) {
throw new IllegalArgumentException(
"Missing provider");
}
Provider p = Security.getProvider(provider);
if (p ==
null) {
throw new NoSuchProviderException(
"No such provider: " +
provider);
}
return getInstance(transformation, p);
}
private String getProviderName() {
return (provider ==
null) ?
"(no provider)" : provider.getName();
}
/**
* Returns a {@code Cipher} object that implements the specified
* transformation.
*
* <p> A new {@code Cipher} object encapsulating the
* {@code CipherSpi} implementation from the specified {@code provider}
* object is returned. Note that the specified {@code provider} object
* does not have to be registered in the provider list.
*
* @apiNote
* It is recommended to use a transformation that fully specifies the
* algorithm, mode, and padding. By not doing so, the provider will
* use a default for the mode and padding which may not meet the security
* requirements of your application.
*
* @implNote
* See the Cipher Transformations section of the {@extLink
* security_guide_jdk_providers JDK Providers} document for information
* on the transformation defaults used by JDK providers.
*
* @param transformation the name of the transformation,
* e.g., <i>AES/CBC/PKCS5Padding</i>.
* See the Cipher section in the <a href=
* "{@docRoot}/../specs/security/standard-names.html#cipher-algorithms">
* Java Security Standard Algorithm Names Specification</a>
* for information about standard transformation names.
*
* @param provider the provider
*
* @return a {@code Cipher} object that implements the requested
* transformation
*
* @throws IllegalArgumentException if the {@code provider}
* is {@code null}
*
* @throws NoSuchAlgorithmException if {@code transformation}
* is {@code null}, empty, in an invalid format,
* or if a {@code CipherSpi} implementation for the
* specified algorithm is not available from the specified
* {@code provider} object
*
* @throws NoSuchPaddingException if {@code transformation}
* contains a padding scheme that is not available
*
* @see java.security.Provider
*/
public static final Cipher getInstance(String transformation,
Provider provider)
throws NoSuchAlgorithmException, NoSuchPaddingException
{
if ((transformation ==
null) || transformation.isEmpty()) {
throw new NoSuchAlgorithmException(
"Null or empty transformation");
}
if (provider ==
null) {
throw new IllegalArgumentException(
"Missing provider");
}
Exception failure =
null;
List<Transform> transforms = getTransforms(transformation);
boolean providerChecked =
false;
String paddingError =
null;
for (Transform tr : transforms) {
Service s = provider.getService(
"Cipher", tr.transform);
if (s ==
null) {
continue;
}
if (providerChecked ==
false) {
// for compatibility, first do the lookup and then verify
// the provider. this makes the difference between a NSAE
// and a SecurityException if the
// provider does not support the algorithm.
Exception ve = JceSecurity.getVerificationResult(provider);
if (ve !=
null) {
String msg =
"JCE cannot authenticate the provider "
+ provider.getName();
throw new SecurityException(msg, ve);
}
providerChecked =
true;
}
if (tr.supportsMode(s) == S_NO) {
continue;
}
if (tr.supportsPadding(s) == S_NO) {
paddingError = tr.pad;
continue;
}
try {
CipherSpi spi = (CipherSpi)s.newInstance(
null);
tr.setModePadding(spi);
Cipher cipher =
new Cipher(spi, transformation);
cipher.provider = s.getProvider();
cipher.initCryptoPermission();
return cipher;
}
catch (Exception e) {
failure = e;
}
}
// throw NoSuchPaddingException if the problem is with padding
if (failure
instanceof NoSuchPaddingException) {
throw (NoSuchPaddingException)failure;
}
if (paddingError !=
null) {
throw new NoSuchPaddingException
(
"Padding not supported: " + paddingError);
}
throw new NoSuchAlgorithmException
(
"No such algorithm: " + transformation, failure);
}
// If the requested crypto service is export-controlled,
// determine the maximum allowable keysize.
private void initCryptoPermission()
throws NoSuchAlgorithmException {
if (JceSecurity.isRestricted() ==
false) {
cryptoPerm = CryptoAllPermission.INSTANCE;
exmech =
null;
return;
}
cryptoPerm = getConfiguredPermission(transformation);
// Instantiate the exemption mechanism (if required)
String exmechName = cryptoPerm.getExemptionMechanism();
if (exmechName !=
null) {
exmech = ExemptionMechanism.getInstance(exmechName);
}
}
// max number of debug warnings to print from chooseFirstProvider()
private static int warnCount = 10;
/**
* Choose the Spi from the first provider available. Used if
* delayed provider selection is not possible because init()
* is not the first method called.
*/
void chooseFirstProvider() {
if (spi !=
null) {
return;
}
synchronized (lock) {
if (spi !=
null) {
return;
}
if (debug !=
null) {
int w = --warnCount;
if (w >= 0) {
debug.println(
"Cipher.init() not first method "
+
"called, disabling delayed provider selection");
if (w == 0) {
debug.println(
"Further warnings of this type will "
+
"be suppressed");
}
new Exception(
"Call trace").printStackTrace();
}
}
Exception lastException =
null;
while ((firstService !=
null) || serviceIterator.hasNext()) {
Service s;
CipherSpi thisSpi;
if (firstService !=
null) {
s = firstService;
thisSpi = firstSpi;
firstService =
null;
firstSpi =
null;
}
else {
s = serviceIterator.next();
thisSpi =
null;
}
if (JceSecurity.canUseProvider(s.getProvider()) ==
false) {
continue;
}
Transform tr = getTransform(s, transforms);
if (tr ==
null) {
// should never happen
continue;
}
if (tr.supportsModePadding(s) == S_NO) {
continue;
}
try {
if (thisSpi ==
null) {
Object obj = s.newInstance(
null);
if (obj
instanceof CipherSpi ==
false) {
continue;
}
thisSpi = (CipherSpi)obj;
}
tr.setModePadding(thisSpi);
initCryptoPermission();
spi = thisSpi;
provider = s.getProvider();
// not needed any more
firstService =
null;
serviceIterator =
null;
transforms =
null;
return;
}
catch (Exception e) {
lastException = e;
}
}
ProviderException e =
new ProviderException
(
"Could not construct CipherSpi instance");
if (lastException !=
null) {
e.initCause(lastException);
}
throw e;
}
}
private static final int I_KEY = 1;
private static final int I_PARAMSPEC = 2;
private static final int I_PARAMS = 3;
private static final int I_CERT = 4;
private void implInit(CipherSpi thisSpi,
int type,
int opmode, Key key,
AlgorithmParameterSpec paramSpec, AlgorithmParameters params,
SecureRandom random)
throws InvalidKeyException,
InvalidAlgorithmParameterException {
switch (type) {
case I_KEY:
checkCryptoPerm(thisSpi, key);
thisSpi.engineInit(opmode, key, random);
break;
case I_PARAMSPEC:
checkCryptoPerm(thisSpi, key, paramSpec);
thisSpi.engineInit(opmode, key, paramSpec, random);
break;
case I_PARAMS:
checkCryptoPerm(thisSpi, key, params);
thisSpi.engineInit(opmode, key, params, random);
break;
case I_CERT:
checkCryptoPerm(thisSpi, key);
thisSpi.engineInit(opmode, key, random);
break;
default:
throw new AssertionError(
"Internal Cipher error: " + type);
}
}
private void chooseProvider(
int initType,
int opmode, Key key,
AlgorithmParameterSpec paramSpec,
AlgorithmParameters params, SecureRandom random)
throws InvalidKeyException, InvalidAlgorithmParameterException {
synchronized (lock) {
if (spi !=
null) {
implInit(spi, initType, opmode, key, paramSpec, params, random);
return;
}
Exception lastException =
null;
while ((firstService !=
null) || serviceIterator.hasNext()) {
Service s;
CipherSpi thisSpi;
if (firstService !=
null) {
s = firstService;
thisSpi = firstSpi;
firstService =
null;
firstSpi =
null;
}
else {
s = serviceIterator.next();
thisSpi =
null;
}
// if provider says it does not support this key, ignore it
if (s.supportsParameter(key) ==
false) {
continue;
}
if (JceSecurity.canUseProvider(s.getProvider()) ==
false) {
continue;
}
Transform tr = getTransform(s, transforms);
if (tr ==
null) {
// should never happen
continue;
}
if (tr.supportsModePadding(s) == S_NO) {
continue;
}
try {
if (thisSpi ==
null) {
thisSpi = (CipherSpi)s.newInstance(
null);
}
tr.setModePadding(thisSpi);
initCryptoPermission();
implInit(thisSpi, initType, opmode, key, paramSpec,
params, random);
provider = s.getProvider();
this.spi = thisSpi;
firstService =
null;
serviceIterator =
null;
transforms =
null;
return;
}
catch (Exception e) {
// NoSuchAlgorithmException from newInstance()
// InvalidKeyException from init()
// RuntimeException (ProviderException) from init()
// SecurityException from crypto permission check
if (lastException ==
null) {
lastException = e;
}
}
}
// no working provider found, fail
if (lastException
instanceof InvalidKeyException) {
throw (InvalidKeyException)lastException;
}
if (lastException
instanceof InvalidAlgorithmParameterException) {
throw (InvalidAlgorithmParameterException)lastException;
}
if (lastException
instanceof RuntimeException) {
throw (RuntimeException)lastException;
}
String kName = (key !=
null) ? key.getClass().getName() :
"(null)";
throw new InvalidKeyException
(
"No installed provider supports this key: "
+ kName, lastException);
}
}
/**
* Returns the provider of this {@code Cipher} object.
*
* @return the provider of this {@code Cipher} object
*/
public final Provider getProvider() {
chooseFirstProvider();
return this.provider;
}
/**
* Returns the algorithm name of this {@code Cipher} object.
*
* <p>This is the same name that was specified in one of the
* {@code getInstance} calls that created this {@code Cipher}
* object.
*
* @return the algorithm name of this {@code Cipher} object
*/
public final String getAlgorithm() {
return this.transformation;
}
/**
* Returns the block size (in bytes).
*
* @return the block size (in bytes), or 0 if this cipher is
* not a block cipher
*/
public final int getBlockSize() {
chooseFirstProvider();
return spi.engineGetBlockSize();
}
/**
* Returns the length in bytes that an output buffer would need to be in
* order to hold the result of the next {@code update} or
* {@code doFinal} operation, given the input length
* {@code inputLen} (in bytes).
*
* <p>This call takes into account any unprocessed (buffered) data from a
* previous {@code update} call, padding, and AEAD tagging.
*
* <p>The actual output length of the next {@code update} or
* {@code doFinal} 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)
*
* @throws IllegalStateException if this {@code Cipher} object is in a
* wrong state (e.g., has not yet been initialized)
*/
public final int getOutputSize(
int inputLen) {
if (!initialized && !(
this instanceof NullCipher)) {
throw new IllegalStateException(
"Cipher not initialized");
}
if (inputLen < 0) {
throw new IllegalArgumentException(
"Input size must be equal " +
"to or greater than zero");
}
chooseFirstProvider();
return spi.engineGetOutputSize(inputLen);
}
/**
* Returns the initialization vector (IV) in a new buffer.
*
* <p>This is useful in the case where a random IV was created,
* or in the context of password-based encryption or
* decryption, where the IV is derived from a user-supplied password.
*
* @return the initialization vector in a new buffer, or {@code null} if
* this cipher does not use an IV, or if the IV has not yet
* been set.
*/
public final byte[] getIV() {
chooseFirstProvider();
return spi.engineGetIV();
}
/**
* Returns the parameters used with this {@code Cipher} object.
*
* <p>The returned parameters may be the same that were used to initialize
* this cipher, or may contain additional default or random parameter
* values used by the underlying cipher implementation. If the required
* parameters were not supplied and can be generated by the cipher, the
* generated parameters are returned. Otherwise, {@code null} is returned.
*
* @return the parameters used with this cipher, or {@code null}
*/
public final AlgorithmParameters getParameters() {
chooseFirstProvider();
return spi.engineGetParameters();
}
/**
* Returns the exemption mechanism object used with this {@code Cipher}
* object.
*
* @return the exemption mechanism object used with this {@code Cipher}
* object, or {@code null} if this {@code Cipher} object does not use any
* exemption mechanism.
*/
public final ExemptionMechanism getExemptionMechanism() {
chooseFirstProvider();
return exmech;
}
//
// Crypto permission check code below
//
private void checkCryptoPerm(CipherSpi checkSpi, Key key)
throws InvalidKeyException {
if (cryptoPerm == CryptoAllPermission.INSTANCE) {
return;
}
// Check if key size and default parameters are within legal limits
AlgorithmParameterSpec params;
try {
params = getAlgorithmParameterSpec(checkSpi.engineGetParameters());
}
catch (InvalidParameterSpecException ipse) {
throw new InvalidKeyException
(
"Unsupported default algorithm parameters");
}
if (!passCryptoPermCheck(checkSpi, key, params)) {
throw new InvalidKeyException(
"Illegal key size or default parameters");
}
}
private void checkCryptoPerm(CipherSpi checkSpi, Key key,
AlgorithmParameterSpec params)
throws InvalidKeyException,
InvalidAlgorithmParameterException {
if (cryptoPerm == CryptoAllPermission.INSTANCE) {
return;
}
// Determine keysize and check if it is within legal limits
if (!passCryptoPermCheck(checkSpi, key,
null)) {
throw new InvalidKeyException(
"Illegal key size");
}
if ((params !=
null) && (!passCryptoPermCheck(checkSpi, key, params))) {
throw new InvalidAlgorithmParameterException(
"Illegal parameters");
}
}
private void checkCryptoPerm(CipherSpi checkSpi, Key key,
AlgorithmParameters params)
throws InvalidKeyException, InvalidAlgorithmParameterException {
if (cryptoPerm == CryptoAllPermission.INSTANCE) {
return;
}
// Convert the specified parameters into specs and then delegate.
AlgorithmParameterSpec pSpec;
try {
pSpec = getAlgorithmParameterSpec(params);
}
catch (InvalidParameterSpecException ipse) {
throw new InvalidAlgorithmParameterException
(
"Failed to retrieve algorithm parameter specification");
}
checkCryptoPerm(checkSpi, key, pSpec);
}
private boolean passCryptoPermCheck(CipherSpi checkSpi, Key key,
AlgorithmParameterSpec params)
throws InvalidKeyException {
String em = cryptoPerm.getExemptionMechanism();
int keySize = checkSpi.engineGetKeySize(key);
// Use the "algorithm" component of the cipher
// transformation so that the perm check would
// work when the key has the "aliased" algo.
String algComponent;
int index = transformation.indexOf(
'/');
if (index != -1) {
algComponent = transformation.substring(0, index);
}
else {
algComponent = transformation;
}
CryptoPermission checkPerm =
new CryptoPermission(algComponent, keySize, params, em);
if (!cryptoPerm.implies(checkPerm)) {
if (debug !=
null) {
debug.println(
"Crypto Permission check failed");
debug.println(
"granted: " + cryptoPerm);
debug.println(
"requesting: " + checkPerm);
}
return false;
}
if (exmech ==
null) {
return true;
}
try {
if (!exmech.isCryptoAllowed(key)) {
if (debug !=
null) {
debug.println(exmech.getName() +
" isn't enforced");
}
return false;
}
}
catch (ExemptionMechanismException eme) {
if (debug !=
null) {
debug.println(
"Cannot determine whether "+
exmech.getName() +
" has been enforced");
eme.printStackTrace();
}
return false;
}
return true;
}
// check if opmode is one of the defined constants
// throw InvalidParameterException if not
private static void checkOpmode(
int opmode) {
if ((opmode < ENCRYPT_MODE) || (opmode > UNWRAP_MODE)) {
throw new InvalidParameterException(
"Invalid operation mode");
}
}
/**
* Initializes this {@code Cipher} object with a key.
*
* <p>The {@code Cipher} object is initialized for one of the following four
* operations:
* encryption, decryption, key wrapping or key unwrapping, depending
* on the value of {@code opmode}.
*
* <p>If this cipher requires any algorithm parameters that cannot be
* derived from the given {@code key}, the underlying cipher
* implementation is supposed to generate the required parameters itself
* (using provider-specific default or random values) if it is being
* initialized for encryption or key wrapping, and raise an
* {@code InvalidKeyException} if it is being
* initialized for decryption or key unwrapping.
* The generated parameters can be retrieved using
* {@link #getParameters() getParameters} or
* {@link #getIV() getIV} (if the parameter is an IV).
*
* <p>If this cipher requires algorithm parameters that cannot be
* derived from the input parameters, and there are no reasonable
* provider-specific default values, initialization will
* necessarily fail.
*
* <p>If this cipher (including its feedback or padding scheme)
* requires any random bytes (e.g., for parameter generation), it will get
* them using the {@link java.security.SecureRandom}
* implementation of the highest-priority
* installed provider as the source of randomness.
* (If none of the installed providers supply an implementation of
* SecureRandom, a system-provided source of randomness will be used.)
*
* <p>Note that when a {@code Cipher} object is initialized, it loses all
* previously-acquired state. In other words, initializing a {@code Cipher}
* object is equivalent to creating a new instance of that {@code Cipher}
* object and initializing it.
*
* @param opmode the operation mode of this {@code Cipher} object
* (this is one of the following:
* {@code ENCRYPT_MODE}, {@code DECRYPT_MODE},
* {@code WRAP_MODE} or {@code UNWRAP_MODE})
* @param key the key
*
* @throws InvalidKeyException if the given key is inappropriate for
* initializing this cipher, or requires
* algorithm parameters that cannot be
* determined from the given key, or if the given key has a keysize that
* exceeds the maximum allowable keysize (as determined from the
* configured jurisdiction policy files)
* @throws UnsupportedOperationException if {@code opmode} is
* {@code WRAP_MODE} or {@code UNWRAP_MODE} but the mode is not implemented
* by the underlying {@code CipherSpi}
* @throws InvalidParameterException if {@code opmode} is not one of the
* recognized values
*/
public final void init(
int opmode, Key key)
throws InvalidKeyException {
init(opmode, key, JCAUtil.getDefSecureRandom());
}
/**
* Initializes this {@code Cipher} object with a key and a
* source of randomness.
*
* <p>The {@code Cipher} object is initialized for one of the following four
* operations:
* encryption, decryption, key wrapping or key unwrapping, depending
* on the value of {@code opmode}.
*
* <p>If this cipher requires any algorithm parameters that cannot be
* derived from the given {@code key}, the underlying cipher
* implementation is supposed to generate the required parameters itself
* (using provider-specific default or random values) if it is being
* initialized for encryption or key wrapping, and raise an
* {@code InvalidKeyException} if it is being
* initialized for decryption or key unwrapping.
* The generated parameters can be retrieved using
* {@link #getParameters() getParameters} or
* {@link #getIV() getIV} (if the parameter is an IV).
*
* <p>If this cipher requires algorithm parameters that cannot be
* derived from the input parameters, and there are no reasonable
* provider-specific default values, initialization will
* necessarily fail.
*
* <p>If this cipher (including its feedback or padding scheme)
* requires any random bytes (e.g., for parameter generation), it will get
* them from {@code random}.
*
* <p>Note that when a {@code Cipher} object is initialized, it loses all
* previously-acquired state. In other words, initializing a {@code Cipher}
* object is equivalent to creating a new instance of that
* {@code Cipher} object and initializing it.
*
* @param opmode the operation mode of this {@code Cipher} object
* (this is one of the following:
* {@code ENCRYPT_MODE}, {@code DECRYPT_MODE},
* {@code WRAP_MODE} or {@code UNWRAP_MODE})
* @param key the encryption key
* @param random the source of randomness
*
* @throws InvalidKeyException if the given key is inappropriate for
* initializing this cipher, or requires
* algorithm parameters that cannot be
* determined from the given key, or if the given key has a keysize that
* exceeds the maximum allowable keysize (as determined from the
* configured jurisdiction policy files)
* @throws UnsupportedOperationException if {@code opmode} is
* {@code WRAP_MODE} or {@code UNWRAP_MODE} but the mode is not implemented
* by the underlying {@code CipherSpi}
* @throws InvalidParameterException if {@code opmode} is not one of the
* recognized values
*/
public final void init(
int opmode, Key key, SecureRandom random)
throws InvalidKeyException
{
initialized =
false;
checkOpmode(opmode);
if (spi !=
null) {
checkCryptoPerm(spi, key);
spi.engineInit(opmode, key, random);
}
else {
try {
chooseProvider(I_KEY, opmode, key,
null,
null, random);
}
catch (InvalidAlgorithmParameterException e) {
// should never occur
throw new InvalidKeyException(e);
}
}
initialized =
true;
this.opmode = opmode;
if (!skipDebug && pdebug !=
null) {
pdebug.println(
this.toString());
}
}
/**
* Initializes this {@code Cipher} object with a key and a set of algorithm
* parameters.
*
* <p>The {@code Cipher} object is initialized for one of the following four
* operations:
* encryption, decryption, key wrapping or key unwrapping, depending
* on the value of {@code opmode}.
*
* <p>If this cipher requires any algorithm parameters and
* {@code params} is {@code null}, the underlying cipher implementation is
* supposed to generate the required parameters itself (using
* provider-specific default or random values) if it is being
* initialized for encryption or key wrapping, and raise an
* {@code InvalidAlgorithmParameterException} if it is being
* initialized for decryption or key unwrapping.
* The generated parameters can be retrieved using
* {@link #getParameters() getParameters} or
* {@link #getIV() getIV} (if the parameter is an IV).
*
* <p>If this cipher requires algorithm parameters that cannot be
* derived from the input parameters, and there are no reasonable
* provider-specific default values, initialization will
* necessarily fail.
*
* <p>If this cipher (including its feedback or padding scheme)
* requires any random bytes (e.g., for parameter generation), it will get
* them using the {@link java.security.SecureRandom}
* implementation of the highest-priority
* installed provider as the source of randomness.
* (If none of the installed providers supply an implementation of
* SecureRandom, a system-provided source of randomness will be used.)
*
* <p>Note that when a {@code Cipher} object is initialized, it loses all
* previously-acquired state. In other words, initializing a {@code Cipher}
* object is equivalent to creating a new instance of that {@code Cipher}
* object and initializing it.
*
* @param opmode the operation mode of this {@code Cipher} object
* (this is one of the following:
* {@code ENCRYPT_MODE}, {@code DECRYPT_MODE},
* {@code WRAP_MODE} or {@code UNWRAP_MODE})
* @param key the encryption key
* @param params the algorithm parameters
*
* @throws InvalidKeyException if the given key is inappropriate for
* initializing this cipher, or its keysize exceeds the maximum allowable
* keysize (as determined from the configured jurisdiction policy files)
* @throws InvalidAlgorithmParameterException if the given algorithm
* parameters are inappropriate for this cipher,
* or this cipher requires
* algorithm parameters and {@code params} is {@code null}, or the given
* algorithm parameters imply a cryptographic strength that would exceed
* the legal limits (as determined from the configured jurisdiction
* policy files)
* @throws UnsupportedOperationException if {@code opmode} is
* {@code WRAP_MODE} or {@code UNWRAP_MODE} but the mode is not implemented
* by the underlying {@code CipherSpi}
* @throws InvalidParameterException if {@code opmode} is not one of the
* recognized values
*
*/
public final void init(
int opmode, Key key, AlgorithmParameterSpec params)
throws InvalidKeyException, InvalidAlgorithmParameterException
{
init(opmode, key, params, JCAUtil.getDefSecureRandom());
}
/**
* Initializes this {@code Cipher} object with a key, a set of algorithm
* parameters, and a source of randomness.
*
* <p>The {@code Cipher} object is initialized for one of the following four
* operations:
* encryption, decryption, key wrapping or key unwrapping, depending
* on the value of {@code opmode}.
*
* <p>If this cipher requires any algorithm parameters and
* {@code params} is {@code null}, the underlying cipher implementation is
* supposed to generate the required parameters itself (using
* provider-specific default or random values) if it is being
* initialized for encryption or key wrapping, and raise an
* {@code InvalidAlgorithmParameterException} if it is being
* initialized for decryption or key unwrapping.
* The generated parameters can be retrieved using
* {@link #getParameters() getParameters} or
* {@link #getIV() getIV} (if the parameter is an IV).
*
* <p>If this cipher requires algorithm parameters that cannot be
* derived from the input parameters, and there are no reasonable
* provider-specific default values, initialization will
* necessarily fail.
*
* <p>If this cipher (including its feedback or padding scheme)
* requires any random bytes (e.g., for parameter generation), it will get
* them from {@code random}.
*
* <p>Note that when a {@code Cipher} object is initialized, it loses all
* previously-acquired state. In other words, initializing a {@code Cipher}
* object is equivalent to creating a new instance of that {@code Cipher}
* object and initializing it.
*
* @param opmode the operation mode of this {@code Cipher} object
* (this is one of the following:
* {@code ENCRYPT_MODE}, {@code DECRYPT_MODE},
* {@code WRAP_MODE} or {@code UNWRAP_MODE})
* @param key the encryption key
* @param params the algorithm parameters
* @param random the source of randomness
*
* @throws InvalidKeyException if the given key is inappropriate for
* initializing this cipher, or its keysize exceeds the maximum allowable
* keysize (as determined from the configured jurisdiction policy files)
* @throws InvalidAlgorithmParameterException if the given algorithm
* parameters are inappropriate for this cipher,
* or this cipher requires
* algorithm parameters and {@code params} is {@code null}, or the given
* algorithm parameters imply a cryptographic strength that would exceed
* the legal limits (as determined from the configured jurisdiction
* policy files)
* @throws UnsupportedOperationException if {@code opmode} is
* {@code WRAP_MODE} or {@code UNWRAP_MODE} but the mode is not implemented
* by the underlying {@code CipherSpi}
* @throws InvalidParameterException if {@code opmode} is not one of the
* recognized values
*
*/
public final void init(
int opmode, Key key, AlgorithmParameterSpec params,
SecureRandom random)
throws InvalidKeyException, InvalidAlgorithmParameterException
{
initialized =
false;
checkOpmode(opmode);
if (spi !=
null) {
checkCryptoPerm(spi, key, params);
spi.engineInit(opmode, key, params, random);
}
else {
chooseProvider(I_PARAMSPEC, opmode, key, params,
null, random);
}
initialized =
true;
this.opmode = opmode;
if (!skipDebug && pdebug !=
null) {
pdebug.println(
this.toString());
}
}
/**
* Initializes this {@code Cipher} object with a key and a set of algorithm
* parameters.
*
* <p>The {@code Cipher} object is initialized for one of the following four
* operations:
* encryption, decryption, key wrapping or key unwrapping, depending
* on the value of {@code opmode}.
*
* <p>If this cipher requires any algorithm parameters and
* {@code params} is {@code null}, the underlying cipher implementation is
* supposed to generate the required parameters itself (using
* provider-specific default or random values) if it is being
* initialized for encryption or key wrapping, and raise an
* {@code InvalidAlgorithmParameterException} if it is being
* initialized for decryption or key unwrapping.
* The generated parameters can be retrieved using
* {@link #getParameters() getParameters} or
* {@link #getIV() getIV} (if the parameter is an IV).
*
* <p>If this cipher requires algorithm parameters that cannot be
* derived from the input parameters, and there are no reasonable
* provider-specific default values, initialization will
* necessarily fail.
*
* <p>If this cipher (including its feedback or padding scheme)
* requires any random bytes (e.g., for parameter generation), it will get
* them using the {@link java.security.SecureRandom}
* implementation of the highest-priority
* installed provider as the source of randomness.
* (If none of the installed providers supply an implementation of
* SecureRandom, a system-provided source of randomness will be used.)
*
* <p>Note that when a {@code Cipher} object is initialized, it loses all
* previously-acquired state. In other words, initializing a {@code Cipher}
* object is equivalent to creating a new instance of that {@code Cipher}
* object and initializing it.
*
* @param opmode the operation mode of this {@code Cipher} object
* this is one of the following: {@code ENCRYPT_MODE},
* {@code DECRYPT_MODE}, {@code WRAP_MODE}
* or {@code UNWRAP_MODE})
* @param key the encryption key
* @param params the algorithm parameters
*
* @throws InvalidKeyException if the given key is inappropriate for
* initializing this cipher, or its keysize exceeds the maximum allowable
* keysize (as determined from the configured jurisdiction policy files).
* @throws InvalidAlgorithmParameterException if the given algorithm
* parameters are inappropriate for this cipher,
* or this cipher requires
* algorithm parameters and {@code params} is {@code null}, or the given
* algorithm parameters imply a cryptographic strength that would exceed
* the legal limits (as determined from the configured jurisdiction
* policy files)
* @throws UnsupportedOperationException if {@code opmode} is
* {@code WRAP_MODE} or {@code UNWRAP_MODE} but the mode is not implemented
* by the underlying {@code CipherSpi}
* @throws InvalidParameterException if {@code opmode} is not one of the
* recognized values
*/
public final void init(
int opmode, Key key, AlgorithmParameters params)
throws InvalidKeyException, InvalidAlgorithmParameterException
{
init(opmode, key, params, JCAUtil.getDefSecureRandom());
}
/**
* Initializes this {@code Cipher} object with a key, a set of algorithm
* parameters, and a source of randomness.
*
* <p>The {@code Cipher} object is initialized for one of the following four
* operations:
* encryption, decryption, key wrapping or key unwrapping, depending
* on the value of {@code opmode}.
*
* <p>If this cipher requires any algorithm parameters and
* {@code params} is {@code null}, the underlying cipher implementation is
* supposed to generate the required parameters itself (using
* provider-specific default or random values) if it is being
* initialized for encryption or key wrapping, and raise an
* {@code InvalidAlgorithmParameterException} if it is being
* initialized for decryption or key unwrapping.
* The generated parameters can be retrieved using
* {@link #getParameters() getParameters} or
* {@link #getIV() getIV} (if the parameter is an IV).
*
* <p>If this cipher requires algorithm parameters that cannot be
* derived from the input parameters, and there are no reasonable
* provider-specific default values, initialization will
* necessarily fail.
*
* <p>If this cipher (including its feedback or padding scheme)
* requires any random bytes (e.g., for parameter generation), it will get
* them from {@code random}.
*
* <p>Note that when a {@code Cipher} object is initialized, it loses all
* previously-acquired state. In other words, initializing a {@code Cipher}
* object is equivalent to creating a new instance of that {@code Cipher}
* object and initializing it.
*
* @param opmode the operation mode of this {@code Cipher} object
* (this is one of the following: {@code ENCRYPT_MODE},
* {@code DECRYPT_MODE}, {@code WRAP_MODE}
* or {@code UNWRAP_MODE})
* @param key the encryption key
--> --------------------
--> maximum size reached
--> --------------------