0N/A/*
4598N/A * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage javax.crypto;
0N/A
0N/Aimport java.util.*;
4598N/Aimport java.util.concurrent.ConcurrentHashMap;
4598N/Aimport java.util.concurrent.ConcurrentMap;
0N/Aimport java.util.regex.*;
0N/A
0N/Aimport static java.util.Locale.ENGLISH;
0N/A
0N/Aimport java.security.*;
0N/Aimport java.security.Provider.Service;
0N/Aimport java.security.spec.AlgorithmParameterSpec;
0N/Aimport java.security.spec.InvalidParameterSpecException;
0N/Aimport java.security.cert.Certificate;
0N/Aimport java.security.cert.X509Certificate;
0N/A
0N/Aimport javax.crypto.spec.*;
0N/A
0N/Aimport java.nio.ByteBuffer;
0N/Aimport java.nio.ReadOnlyBufferException;
0N/A
0N/Aimport sun.security.util.Debug;
0N/Aimport sun.security.jca.*;
0N/Aimport sun.security.jca.GetInstance.Instance;
0N/A
0N/A/**
0N/A * This class provides the functionality of a cryptographic cipher for
0N/A * encryption and decryption. It forms the core of the Java Cryptographic
0N/A * Extension (JCE) framework.
0N/A *
0N/A * <p>In order to create a Cipher object, the application calls the
0N/A * Cipher's <code>getInstance</code> method, and passes the name of the
0N/A * requested <i>transformation</i> to it. Optionally, the name of a provider
0N/A * may be specified.
0N/A *
0N/A * <p>A <i>transformation</i> is a string that describes the operation (or
0N/A * set of operations) to be performed on the given input, to produce some
0N/A * output. A transformation always includes the name of a cryptographic
0N/A * algorithm (e.g., <i>DES</i>), and may be followed by a feedback mode and
0N/A * padding scheme.
0N/A *
0N/A * <p> A transformation is of the form:<p>
0N/A *
0N/A * <ul>
0N/A * <li>"<i>algorithm/mode/padding</i>" or
0N/A * <p>
0N/A * <li>"<i>algorithm</i>"
0N/A * </ul>
0N/A *
0N/A * <P> (in the latter case,
0N/A * provider-specific default values for the mode and padding scheme are used).
0N/A * For example, the following is a valid transformation:<p>
0N/A *
0N/A * <pre>
0N/A * Cipher c = Cipher.getInstance("<i>DES/CBC/PKCS5Padding</i>");
0N/A * </pre>
0N/A *
3465N/A * Using modes such as <code>CFB</code> and <code>OFB</code>, block
0N/A * ciphers can encrypt data in units smaller than the cipher's actual
0N/A * block size. When requesting such a mode, you may optionally specify
0N/A * the number of bits to be processed at a time by appending this number
0N/A * to the mode name as shown in the "<code>DES/CFB8/NoPadding</code>" and
0N/A * "<code>DES/OFB32/PKCS5Padding</code>" transformations. If no such
0N/A * number is specified, a provider-specific default is used. (For
0N/A * example, the SunJCE provider uses a default of 64 bits for DES.)
0N/A * Thus, block ciphers can be turned into byte-oriented stream ciphers by
0N/A * using an 8 bit mode such as CFB8 or OFB8.
4007N/A * <p>
4007N/A * Modes such as Authenticated Encryption with Associated Data (AEAD)
4007N/A * provide authenticity assurances for both confidential data and
4007N/A * Additional Associated Data (AAD) that is not encrypted. (Please see
4007N/A * <a href="http://www.ietf.org/rfc/rfc5116.txt"> RFC 5116 </a> for more
4007N/A * information on AEAD and AEAD algorithms such as GCM/CCM.) Both
4007N/A * confidential and AAD data can be used when calculating the
4007N/A * authentication tag (similar to a {@link Mac}). This tag is appended
4007N/A * to the ciphertext during encryption, and is verified on decryption.
4007N/A * <p>
4007N/A * AEAD modes such as GCM/CCM perform all AAD authenticity calculations
4007N/A * before starting the ciphertext authenticity calculations. To avoid
4007N/A * implementations having to internally buffer ciphertext, all AAD data
4007N/A * must be supplied to GCM/CCM implementations (via the {@code
4007N/A * updateAAD} methods) <b>before</b> the ciphertext is processed (via
4007N/A * the {@code update} and {@code doFinal} methods).
0N/A *
4007N/A * <pre>
4007N/A * GCMParameterSpec s = new GCMParameterSpec(...);
4007N/A * cipher.init(..., s);
4007N/A *
4007N/A * // If the GCMParameterSpec is needed again
4007N/A * cipher.getParameters().getParameterSpec(GCMParameterSpec.class));
4007N/A *
4007N/A * cipher.updateAAD(...); // AAD
4007N/A * cipher.update(...); // Multi-part update
4007N/A * cipher.doFinal(...); // conclusion of operation
4007N/A * </pre>
4007N/A * Every implementation of the Java platform is required to support
3465N/A * the following standard <code>Cipher</code> transformations with the keysizes
3465N/A * in parentheses:
3465N/A * <ul>
3465N/A * <li><tt>AES/CBC/NoPadding</tt> (128)</li>
3465N/A * <li><tt>AES/CBC/PKCS5Padding</tt> (128)</li>
3465N/A * <li><tt>AES/ECB/NoPadding</tt> (128)</li>
3465N/A * <li><tt>AES/ECB/PKCS5Padding</tt> (128)</li>
3465N/A * <li><tt>DES/CBC/NoPadding</tt> (56)</li>
3465N/A * <li><tt>DES/CBC/PKCS5Padding</tt> (56)</li>
3465N/A * <li><tt>DES/ECB/NoPadding</tt> (56)</li>
3465N/A * <li><tt>DES/ECB/PKCS5Padding</tt> (56)</li>
3465N/A * <li><tt>DESede/CBC/NoPadding</tt> (168)</li>
3465N/A * <li><tt>DESede/CBC/PKCS5Padding</tt> (168)</li>
3465N/A * <li><tt>DESede/ECB/NoPadding</tt> (168)</li>
3465N/A * <li><tt>DESede/ECB/PKCS5Padding</tt> (168)</li>
3465N/A * <li><tt>RSA/ECB/PKCS1Padding</tt> (1024, 2048)</li>
3465N/A * <li><tt>RSA/ECB/OAEPWithSHA-1AndMGF1Padding</tt> (1024, 2048)</li>
3465N/A * <li><tt>RSA/ECB/OAEPWithSHA-256AndMGF1Padding</tt> (1024, 2048)</li>
3465N/A * </ul>
3465N/A * These transformations are described in the
3465N/A * <a href="{@docRoot}/../technotes/guides/security/StandardNames.html#Cipher">
3465N/A * Cipher section</a> of the
3465N/A * Java Cryptography Architecture Standard Algorithm Name Documentation.
3465N/A * Consult the release documentation for your implementation to see if any
3465N/A * other transformations are supported.
3465N/A *
0N/A * @author Jan Luehe
0N/A * @see KeyGenerator
0N/A * @see SecretKey
0N/A * @since 1.4
0N/A */
0N/A
0N/Apublic class Cipher {
0N/A
0N/A private static final Debug debug =
0N/A Debug.getInstance("jca", "Cipher");
0N/A
0N/A /**
0N/A * Constant used to initialize cipher to encryption mode.
0N/A */
0N/A public static final int ENCRYPT_MODE = 1;
0N/A
0N/A /**
0N/A * Constant used to initialize cipher to decryption mode.
0N/A */
0N/A public static final int DECRYPT_MODE = 2;
0N/A
0N/A /**
0N/A * Constant used to initialize cipher to key-wrapping mode.
0N/A */
0N/A public static final int WRAP_MODE = 3;
0N/A
0N/A /**
0N/A * Constant used to initialize cipher to key-unwrapping mode.
0N/A */
0N/A public static final int UNWRAP_MODE = 4;
0N/A
0N/A /**
0N/A * Constant used to indicate the to-be-unwrapped key is a "public key".
0N/A */
0N/A public static final int PUBLIC_KEY = 1;
0N/A
0N/A /**
0N/A * Constant used to indicate the to-be-unwrapped key is a "private key".
0N/A */
0N/A public static final int PRIVATE_KEY = 2;
0N/A
0N/A /**
0N/A * Constant used to indicate the to-be-unwrapped key is a "secret key".
0N/A */
0N/A public static final int SECRET_KEY = 3;
0N/A
0N/A // The provider
0N/A private Provider provider;
0N/A
0N/A // The provider implementation (delegate)
0N/A private CipherSpi spi;
0N/A
0N/A // The transformation
0N/A private String transformation;
0N/A
0N/A // Crypto permission representing the maximum allowable cryptographic
0N/A // strength that this Cipher object can be used for. (The cryptographic
0N/A // strength is a function of the keysize and algorithm parameters encoded
0N/A // in the crypto permission.)
0N/A private CryptoPermission cryptoPerm;
0N/A
0N/A // The exemption mechanism that needs to be enforced
0N/A private ExemptionMechanism exmech;
0N/A
0N/A // Flag which indicates whether or not this cipher has been initialized
0N/A private boolean initialized = false;
0N/A
0N/A // The operation mode - store the operation mode after the
0N/A // cipher has been initialized.
0N/A private int opmode = 0;
0N/A
0N/A // The OID for the KeyUsage extension in an X.509 v3 certificate
0N/A private static final String KEY_USAGE_EXTENSION_OID = "2.5.29.15";
0N/A
0N/A // next SPI to try in provider selection
0N/A // null once provider is selected
0N/A private CipherSpi firstSpi;
0N/A
0N/A // next service to try in provider selection
0N/A // null once provider is selected
0N/A private Service firstService;
0N/A
0N/A // remaining services to try in provider selection
0N/A // null once provider is selected
0N/A private Iterator serviceIterator;
0N/A
0N/A // list of transform Strings to lookup in the provider
0N/A private List transforms;
0N/A
0N/A private final Object lock;
0N/A
0N/A /**
0N/A * Creates a Cipher object.
0N/A *
0N/A * @param cipherSpi the delegate
0N/A * @param provider the provider
0N/A * @param transformation the transformation
0N/A */
0N/A protected Cipher(CipherSpi cipherSpi,
0N/A Provider provider,
0N/A String transformation) {
0N/A // See bug 4341369 & 4334690 for more info.
0N/A // If the caller is trusted, then okey.
0N/A // Otherwise throw a NullPointerException.
0N/A if (!JceSecurityManager.INSTANCE.isCallerTrusted()) {
0N/A throw new NullPointerException();
0N/A }
0N/A this.spi = cipherSpi;
0N/A this.provider = provider;
0N/A this.transformation = transformation;
0N/A this.cryptoPerm = CryptoAllPermission.INSTANCE;
0N/A this.lock = null;
0N/A }
0N/A
0N/A /**
0N/A * Creates a Cipher object. Called internally and by NullCipher.
0N/A *
0N/A * @param cipherSpi the delegate
0N/A * @param transformation the transformation
0N/A */
0N/A Cipher(CipherSpi cipherSpi, String transformation) {
0N/A this.spi = cipherSpi;
0N/A this.transformation = transformation;
0N/A this.cryptoPerm = CryptoAllPermission.INSTANCE;
0N/A this.lock = null;
0N/A }
0N/A
0N/A private Cipher(CipherSpi firstSpi, Service firstService,
0N/A Iterator serviceIterator, String transformation, List transforms) {
0N/A this.firstSpi = firstSpi;
0N/A this.firstService = firstService;
0N/A this.serviceIterator = serviceIterator;
0N/A this.transforms = transforms;
0N/A this.transformation = transformation;
0N/A this.lock = new Object();
0N/A }
0N/A
0N/A private static String[] tokenizeTransformation(String transformation)
0N/A throws NoSuchAlgorithmException {
0N/A if (transformation == null) {
0N/A throw new NoSuchAlgorithmException("No transformation given");
0N/A }
0N/A /*
0N/A * array containing the components of a Cipher transformation:
0N/A *
0N/A * index 0: algorithm component (e.g., DES)
0N/A * index 1: feedback component (e.g., CFB)
0N/A * index 2: padding component (e.g., PKCS5Padding)
0N/A */
0N/A String[] parts = new String[3];
0N/A int count = 0;
0N/A StringTokenizer parser = new StringTokenizer(transformation, "/");
0N/A try {
0N/A while (parser.hasMoreTokens() && count < 3) {
0N/A parts[count++] = parser.nextToken().trim();
0N/A }
0N/A if (count == 0 || count == 2 || parser.hasMoreTokens()) {
0N/A throw new NoSuchAlgorithmException("Invalid transformation"
0N/A + " format:" +
0N/A transformation);
0N/A }
0N/A } catch (NoSuchElementException e) {
0N/A throw new NoSuchAlgorithmException("Invalid transformation " +
0N/A "format:" + transformation);
0N/A }
0N/A if ((parts[0] == null) || (parts[0].length() == 0)) {
0N/A throw new NoSuchAlgorithmException("Invalid transformation:" +
0N/A "algorithm not specified-"
0N/A + transformation);
0N/A }
0N/A return parts;
0N/A }
0N/A
0N/A // Provider attribute name for supported chaining mode
0N/A private final static String ATTR_MODE = "SupportedModes";
0N/A // Provider attribute name for supported padding names
0N/A private final static String ATTR_PAD = "SupportedPaddings";
0N/A
0N/A // constants indicating whether the provider supports
0N/A // a given mode or padding
0N/A private final static int S_NO = 0; // does not support
0N/A private final static int S_MAYBE = 1; // unable to determine
0N/A private final static int S_YES = 2; // does support
0N/A
0N/A /**
0N/A * Nested class to deal with modes and paddings.
0N/A */
0N/A private static class Transform {
0N/A // transform string to lookup in the provider
0N/A final String transform;
0N/A // the mode/padding suffix in upper case. for example, if the algorithm
0N/A // to lookup is "DES/CBC/PKCS5Padding" suffix is "/CBC/PKCS5PADDING"
0N/A // if loopup is "DES", suffix is the empty string
0N/A // needed because aliases prevent straight transform.equals()
0N/A final String suffix;
0N/A // value to pass to setMode() or null if no such call required
0N/A final String mode;
0N/A // value to pass to setPadding() or null if no such call required
0N/A final String pad;
0N/A Transform(String alg, String suffix, String mode, String pad) {
0N/A this.transform = alg + suffix;
0N/A this.suffix = suffix.toUpperCase(Locale.ENGLISH);
0N/A this.mode = mode;
0N/A this.pad = pad;
0N/A }
0N/A // set mode and padding for the given SPI
0N/A void setModePadding(CipherSpi spi) throws NoSuchAlgorithmException,
0N/A NoSuchPaddingException {
0N/A if (mode != null) {
0N/A spi.engineSetMode(mode);
0N/A }
0N/A if (pad != null) {
0N/A spi.engineSetPadding(pad);
0N/A }
0N/A }
0N/A // check whether the given services supports the mode and
0N/A // padding described by this Transform
0N/A int supportsModePadding(Service s) {
0N/A int smode = supportsMode(s);
0N/A if (smode == S_NO) {
0N/A return smode;
0N/A }
0N/A int spad = supportsPadding(s);
0N/A // our constants are defined so that Math.min() is a tri-valued AND
0N/A return Math.min(smode, spad);
0N/A }
0N/A
0N/A // separate methods for mode and padding
0N/A // called directly by Cipher only to throw the correct exception
0N/A int supportsMode(Service s) {
0N/A return supports(s, ATTR_MODE, mode);
0N/A }
0N/A int supportsPadding(Service s) {
0N/A return supports(s, ATTR_PAD, pad);
0N/A }
0N/A
0N/A private static int supports(Service s, String attrName, String value) {
0N/A if (value == null) {
0N/A return S_YES;
0N/A }
0N/A String regexp = s.getAttribute(attrName);
0N/A if (regexp == null) {
0N/A return S_MAYBE;
0N/A }
0N/A return matches(regexp, value) ? S_YES : S_NO;
0N/A }
0N/A
4598N/A // ConcurrentMap<String,Pattern> for previously compiled patterns
4598N/A private final static ConcurrentMap<String, Pattern> patternCache =
4598N/A new ConcurrentHashMap<String, Pattern>();
0N/A
0N/A private static boolean matches(String regexp, String str) {
0N/A Pattern pattern = (Pattern)patternCache.get(regexp);
0N/A if (pattern == null) {
0N/A pattern = Pattern.compile(regexp);
4598N/A patternCache.putIfAbsent(regexp, pattern);
0N/A }
0N/A return pattern.matcher(str.toUpperCase(Locale.ENGLISH)).matches();
0N/A }
0N/A
0N/A }
0N/A
0N/A private static List getTransforms(String transformation)
0N/A throws NoSuchAlgorithmException {
0N/A String[] parts = tokenizeTransformation(transformation);
0N/A
0N/A String alg = parts[0];
0N/A String mode = parts[1];
0N/A String pad = parts[2];
0N/A if ((mode != null) && (mode.length() == 0)) {
0N/A mode = null;
0N/A }
0N/A if ((pad != null) && (pad.length() == 0)) {
0N/A pad = null;
0N/A }
0N/A
0N/A if ((mode == null) && (pad == null)) {
0N/A // DES
0N/A Transform tr = new Transform(alg, "", null, null);
0N/A return Collections.singletonList(tr);
0N/A } else { // if ((mode != null) && (pad != null)) {
0N/A // DES/CBC/PKCS5Padding
0N/A List list = new ArrayList(4);
0N/A list.add(new Transform(alg, "/" + mode + "/" + pad, null, null));
0N/A list.add(new Transform(alg, "/" + mode, null, pad));
0N/A list.add(new Transform(alg, "//" + pad, mode, null));
0N/A list.add(new Transform(alg, "", mode, pad));
0N/A return list;
0N/A }
0N/A }
0N/A
0N/A // get the transform matching the specified service
0N/A private static Transform getTransform(Service s, List transforms) {
0N/A String alg = s.getAlgorithm().toUpperCase(Locale.ENGLISH);
0N/A for (Iterator t = transforms.iterator(); t.hasNext(); ) {
0N/A Transform tr = (Transform)t.next();
0N/A if (alg.endsWith(tr.suffix)) {
0N/A return tr;
0N/A }
0N/A }
0N/A return null;
0N/A }
0N/A
0N/A /**
0N/A * Returns a <code>Cipher</code> object that implements the specified
0N/A * transformation.
0N/A *
0N/A * <p> This method traverses the list of registered security Providers,
0N/A * starting with the most preferred Provider.
0N/A * A new Cipher object encapsulating the
0N/A * CipherSpi implementation from the first
0N/A * Provider that supports the specified algorithm is returned.
0N/A *
0N/A * <p> Note that the list of registered providers may be retrieved via
0N/A * the {@link Security#getProviders() Security.getProviders()} method.
0N/A *
0N/A * @param transformation the name of the transformation, e.g.,
0N/A * <i>DES/CBC/PKCS5Padding</i>.
3465N/A * See the Cipher section in the <a href=
3465N/A * "{@docRoot}/../technotes/guides/security/StandardNames.html#Cipher">
3465N/A * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
0N/A * for information about standard transformation names.
0N/A *
0N/A * @return a cipher that implements the requested transformation.
0N/A *
0N/A * @exception NoSuchAlgorithmException if <code>transformation</code>
0N/A * is null, empty, in an invalid format,
0N/A * or if no Provider supports a CipherSpi implementation for the
0N/A * specified algorithm.
0N/A *
0N/A * @exception NoSuchPaddingException if <code>transformation</code>
0N/A * contains a padding scheme that is not available.
0N/A *
0N/A * @see java.security.Provider
0N/A */
0N/A public static final Cipher getInstance(String transformation)
0N/A throws NoSuchAlgorithmException, NoSuchPaddingException
0N/A {
0N/A List transforms = getTransforms(transformation);
0N/A List cipherServices = new ArrayList(transforms.size());
0N/A for (Iterator t = transforms.iterator(); t.hasNext(); ) {
0N/A Transform transform = (Transform)t.next();
0N/A cipherServices.add(new ServiceId("Cipher", transform.transform));
0N/A }
0N/A List services = GetInstance.getServices(cipherServices);
0N/A // make sure there is at least one service from a signed provider
0N/A // and that it can use the specified mode and padding
0N/A Iterator t = services.iterator();
0N/A Exception failure = null;
0N/A while (t.hasNext()) {
0N/A Service s = (Service)t.next();
0N/A if (JceSecurity.canUseProvider(s.getProvider()) == false) {
0N/A continue;
0N/A }
0N/A Transform tr = getTransform(s, transforms);
0N/A if (tr == null) {
0N/A // should never happen
0N/A continue;
0N/A }
0N/A int canuse = tr.supportsModePadding(s);
0N/A if (canuse == S_NO) {
0N/A // does not support mode or padding we need, ignore
0N/A continue;
0N/A }
0N/A if (canuse == S_YES) {
0N/A return new Cipher(null, s, t, transformation, transforms);
0N/A } else { // S_MAYBE, try out if it works
0N/A try {
0N/A CipherSpi spi = (CipherSpi)s.newInstance(null);
0N/A tr.setModePadding(spi);
0N/A return new Cipher(spi, s, t, transformation, transforms);
0N/A } catch (Exception e) {
0N/A failure = e;
0N/A }
0N/A }
0N/A }
0N/A throw new NoSuchAlgorithmException
0N/A ("Cannot find any provider supporting " + transformation, failure);
0N/A }
0N/A
0N/A /**
0N/A * Returns a <code>Cipher</code> object that implements the specified
0N/A * transformation.
0N/A *
0N/A * <p> A new Cipher object encapsulating the
0N/A * CipherSpi implementation from the specified provider
0N/A * is returned. The specified provider must be registered
0N/A * in the security provider list.
0N/A *
0N/A * <p> Note that the list of registered providers may be retrieved via
0N/A * the {@link Security#getProviders() Security.getProviders()} method.
0N/A *
0N/A * @param transformation the name of the transformation,
0N/A * e.g., <i>DES/CBC/PKCS5Padding</i>.
3465N/A * See the Cipher section in the <a href=
3465N/A * "{@docRoot}/../technotes/guides/security/StandardNames.html#Cipher">
3465N/A * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
0N/A * for information about standard transformation names.
0N/A *
0N/A * @param provider the name of the provider.
0N/A *
0N/A * @return a cipher that implements the requested transformation.
0N/A *
0N/A * @exception NoSuchAlgorithmException if <code>transformation</code>
0N/A * is null, empty, in an invalid format,
0N/A * or if a CipherSpi implementation for the specified algorithm
0N/A * is not available from the specified provider.
0N/A *
0N/A * @exception NoSuchProviderException if the specified provider is not
0N/A * registered in the security provider list.
0N/A *
0N/A * @exception NoSuchPaddingException if <code>transformation</code>
0N/A * contains a padding scheme that is not available.
0N/A *
0N/A * @exception IllegalArgumentException if the <code>provider</code>
0N/A * is null or empty.
0N/A *
0N/A * @see java.security.Provider
0N/A */
0N/A public static final Cipher getInstance(String transformation,
0N/A String provider)
0N/A throws NoSuchAlgorithmException, NoSuchProviderException,
0N/A NoSuchPaddingException
0N/A {
0N/A if ((provider == null) || (provider.length() == 0)) {
0N/A throw new IllegalArgumentException("Missing provider");
0N/A }
0N/A Provider p = Security.getProvider(provider);
0N/A if (p == null) {
0N/A throw new NoSuchProviderException("No such provider: " +
0N/A provider);
0N/A }
0N/A return getInstance(transformation, p);
0N/A }
0N/A
0N/A /**
0N/A * Returns a <code>Cipher</code> object that implements the specified
0N/A * transformation.
0N/A *
0N/A * <p> A new Cipher object encapsulating the
0N/A * CipherSpi implementation from the specified Provider
0N/A * object is returned. Note that the specified Provider object
0N/A * does not have to be registered in the provider list.
0N/A *
0N/A * @param transformation the name of the transformation,
0N/A * e.g., <i>DES/CBC/PKCS5Padding</i>.
3465N/A * See the Cipher section in the <a href=
3465N/A * "{@docRoot}/../technotes/guides/security/StandardNames.html#Cipher">
3465N/A * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
0N/A * for information about standard transformation names.
0N/A *
0N/A * @param provider the provider.
0N/A *
0N/A * @return a cipher that implements the requested transformation.
0N/A *
0N/A * @exception NoSuchAlgorithmException if <code>transformation</code>
0N/A * is null, empty, in an invalid format,
0N/A * or if a CipherSpi implementation for the specified algorithm
0N/A * is not available from the specified Provider object.
0N/A *
0N/A * @exception NoSuchPaddingException if <code>transformation</code>
0N/A * contains a padding scheme that is not available.
0N/A *
0N/A * @exception IllegalArgumentException if the <code>provider</code>
0N/A * is null.
0N/A *
0N/A * @see java.security.Provider
0N/A */
0N/A public static final Cipher getInstance(String transformation,
0N/A Provider provider)
0N/A throws NoSuchAlgorithmException, NoSuchPaddingException
0N/A {
0N/A if (provider == null) {
0N/A throw new IllegalArgumentException("Missing provider");
0N/A }
0N/A Exception failure = null;
0N/A List transforms = getTransforms(transformation);
0N/A boolean providerChecked = false;
0N/A String paddingError = null;
0N/A for (Iterator t = transforms.iterator(); t.hasNext();) {
0N/A Transform tr = (Transform)t.next();
0N/A Service s = provider.getService("Cipher", tr.transform);
0N/A if (s == null) {
0N/A continue;
0N/A }
0N/A if (providerChecked == false) {
0N/A // for compatibility, first do the lookup and then verify
0N/A // the provider. this makes the difference between a NSAE
0N/A // and a SecurityException if the
0N/A // provider does not support the algorithm.
0N/A Exception ve = JceSecurity.getVerificationResult(provider);
0N/A if (ve != null) {
0N/A String msg = "JCE cannot authenticate the provider "
0N/A + provider.getName();
0N/A throw new SecurityException(msg, ve);
0N/A }
0N/A providerChecked = true;
0N/A }
0N/A if (tr.supportsMode(s) == S_NO) {
0N/A continue;
0N/A }
0N/A if (tr.supportsPadding(s) == S_NO) {
0N/A paddingError = tr.pad;
0N/A continue;
0N/A }
0N/A try {
0N/A CipherSpi spi = (CipherSpi)s.newInstance(null);
0N/A tr.setModePadding(spi);
0N/A Cipher cipher = new Cipher(spi, transformation);
0N/A cipher.provider = s.getProvider();
0N/A cipher.initCryptoPermission();
0N/A return cipher;
0N/A } catch (Exception e) {
0N/A failure = e;
0N/A }
0N/A }
0N/A
0N/A // throw NoSuchPaddingException if the problem is with padding
0N/A if (failure instanceof NoSuchPaddingException) {
0N/A throw (NoSuchPaddingException)failure;
0N/A }
0N/A if (paddingError != null) {
0N/A throw new NoSuchPaddingException
0N/A ("Padding not supported: " + paddingError);
0N/A }
0N/A throw new NoSuchAlgorithmException
0N/A ("No such algorithm: " + transformation, failure);
0N/A }
0N/A
0N/A // If the requested crypto service is export-controlled,
0N/A // determine the maximum allowable keysize.
0N/A private void initCryptoPermission() throws NoSuchAlgorithmException {
0N/A if (JceSecurity.isRestricted() == false) {
0N/A cryptoPerm = CryptoAllPermission.INSTANCE;
0N/A exmech = null;
0N/A return;
0N/A }
0N/A cryptoPerm = getConfiguredPermission(transformation);
0N/A // Instantiate the exemption mechanism (if required)
0N/A String exmechName = cryptoPerm.getExemptionMechanism();
0N/A if (exmechName != null) {
0N/A exmech = ExemptionMechanism.getInstance(exmechName);
0N/A }
0N/A }
0N/A
0N/A // max number of debug warnings to print from chooseFirstProvider()
0N/A private static int warnCount = 10;
0N/A
0N/A /**
0N/A * Choose the Spi from the first provider available. Used if
0N/A * delayed provider selection is not possible because init()
0N/A * is not the first method called.
0N/A */
0N/A void chooseFirstProvider() {
0N/A if (spi != null) {
0N/A return;
0N/A }
0N/A synchronized (lock) {
0N/A if (spi != null) {
0N/A return;
0N/A }
0N/A if (debug != null) {
0N/A int w = --warnCount;
0N/A if (w >= 0) {
0N/A debug.println("Cipher.init() not first method "
0N/A + "called, disabling delayed provider selection");
0N/A if (w == 0) {
0N/A debug.println("Further warnings of this type will "
0N/A + "be suppressed");
0N/A }
0N/A new Exception("Call trace").printStackTrace();
0N/A }
0N/A }
0N/A Exception lastException = null;
0N/A while ((firstService != null) || serviceIterator.hasNext()) {
0N/A Service s;
0N/A CipherSpi thisSpi;
0N/A if (firstService != null) {
0N/A s = firstService;
0N/A thisSpi = firstSpi;
0N/A firstService = null;
0N/A firstSpi = null;
0N/A } else {
0N/A s = (Service)serviceIterator.next();
0N/A thisSpi = null;
0N/A }
0N/A if (JceSecurity.canUseProvider(s.getProvider()) == false) {
0N/A continue;
0N/A }
0N/A Transform tr = getTransform(s, transforms);
0N/A if (tr == null) {
0N/A // should never happen
0N/A continue;
0N/A }
0N/A if (tr.supportsModePadding(s) == S_NO) {
0N/A continue;
0N/A }
0N/A try {
0N/A if (thisSpi == null) {
0N/A Object obj = s.newInstance(null);
0N/A if (obj instanceof CipherSpi == false) {
0N/A continue;
0N/A }
0N/A thisSpi = (CipherSpi)obj;
0N/A }
0N/A tr.setModePadding(thisSpi);
0N/A initCryptoPermission();
0N/A spi = thisSpi;
0N/A provider = s.getProvider();
0N/A // not needed any more
0N/A firstService = null;
0N/A serviceIterator = null;
0N/A transforms = null;
0N/A return;
0N/A } catch (Exception e) {
0N/A lastException = e;
0N/A }
0N/A }
0N/A ProviderException e = new ProviderException
0N/A ("Could not construct CipherSpi instance");
0N/A if (lastException != null) {
0N/A e.initCause(lastException);
0N/A }
0N/A throw e;
0N/A }
0N/A }
0N/A
0N/A private final static int I_KEY = 1;
0N/A private final static int I_PARAMSPEC = 2;
0N/A private final static int I_PARAMS = 3;
0N/A private final static int I_CERT = 4;
0N/A
0N/A private void implInit(CipherSpi thisSpi, int type, int opmode, Key key,
0N/A AlgorithmParameterSpec paramSpec, AlgorithmParameters params,
0N/A SecureRandom random) throws InvalidKeyException,
0N/A InvalidAlgorithmParameterException {
0N/A switch (type) {
0N/A case I_KEY:
0N/A checkCryptoPerm(thisSpi, key);
0N/A thisSpi.engineInit(opmode, key, random);
0N/A break;
0N/A case I_PARAMSPEC:
0N/A checkCryptoPerm(thisSpi, key, paramSpec);
0N/A thisSpi.engineInit(opmode, key, paramSpec, random);
0N/A break;
0N/A case I_PARAMS:
0N/A checkCryptoPerm(thisSpi, key, params);
0N/A thisSpi.engineInit(opmode, key, params, random);
0N/A break;
0N/A case I_CERT:
0N/A checkCryptoPerm(thisSpi, key);
0N/A thisSpi.engineInit(opmode, key, random);
0N/A break;
0N/A default:
0N/A throw new AssertionError("Internal Cipher error: " + type);
0N/A }
0N/A }
0N/A
0N/A private void chooseProvider(int initType, int opmode, Key key,
0N/A AlgorithmParameterSpec paramSpec,
0N/A AlgorithmParameters params, SecureRandom random)
0N/A throws InvalidKeyException, InvalidAlgorithmParameterException {
0N/A synchronized (lock) {
0N/A if (spi != null) {
0N/A implInit(spi, initType, opmode, key, paramSpec, params, random);
0N/A return;
0N/A }
0N/A Exception lastException = null;
0N/A while ((firstService != null) || serviceIterator.hasNext()) {
0N/A Service s;
0N/A CipherSpi thisSpi;
0N/A if (firstService != null) {
0N/A s = firstService;
0N/A thisSpi = firstSpi;
0N/A firstService = null;
0N/A firstSpi = null;
0N/A } else {
0N/A s = (Service)serviceIterator.next();
0N/A thisSpi = null;
0N/A }
0N/A // if provider says it does not support this key, ignore it
0N/A if (s.supportsParameter(key) == false) {
0N/A continue;
0N/A }
0N/A if (JceSecurity.canUseProvider(s.getProvider()) == false) {
0N/A continue;
0N/A }
0N/A Transform tr = getTransform(s, transforms);
0N/A if (tr == null) {
0N/A // should never happen
0N/A continue;
0N/A }
0N/A if (tr.supportsModePadding(s) == S_NO) {
0N/A continue;
0N/A }
0N/A try {
0N/A if (thisSpi == null) {
0N/A thisSpi = (CipherSpi)s.newInstance(null);
0N/A }
0N/A tr.setModePadding(thisSpi);
0N/A initCryptoPermission();
0N/A implInit(thisSpi, initType, opmode, key, paramSpec,
0N/A params, random);
0N/A provider = s.getProvider();
0N/A this.spi = thisSpi;
0N/A firstService = null;
0N/A serviceIterator = null;
0N/A transforms = null;
0N/A return;
0N/A } catch (Exception e) {
0N/A // NoSuchAlgorithmException from newInstance()
0N/A // InvalidKeyException from init()
0N/A // RuntimeException (ProviderException) from init()
0N/A // SecurityException from crypto permission check
0N/A if (lastException == null) {
0N/A lastException = e;
0N/A }
0N/A }
0N/A }
0N/A // no working provider found, fail
0N/A if (lastException instanceof InvalidKeyException) {
0N/A throw (InvalidKeyException)lastException;
0N/A }
0N/A if (lastException instanceof InvalidAlgorithmParameterException) {
0N/A throw (InvalidAlgorithmParameterException)lastException;
0N/A }
0N/A if (lastException instanceof RuntimeException) {
0N/A throw (RuntimeException)lastException;
0N/A }
0N/A String kName = (key != null) ? key.getClass().getName() : "(null)";
0N/A throw new InvalidKeyException
0N/A ("No installed provider supports this key: "
0N/A + kName, lastException);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Returns the provider of this <code>Cipher</code> object.
0N/A *
0N/A * @return the provider of this <code>Cipher</code> object
0N/A */
0N/A public final Provider getProvider() {
0N/A chooseFirstProvider();
0N/A return this.provider;
0N/A }
0N/A
0N/A /**
0N/A * Returns the algorithm name of this <code>Cipher</code> object.
0N/A *
0N/A * <p>This is the same name that was specified in one of the
0N/A * <code>getInstance</code> calls that created this <code>Cipher</code>
0N/A * object..
0N/A *
0N/A * @return the algorithm name of this <code>Cipher</code> object.
0N/A */
0N/A public final String getAlgorithm() {
0N/A return this.transformation;
0N/A }
0N/A
0N/A /**
0N/A * Returns the block size (in bytes).
0N/A *
0N/A * @return the block size (in bytes), or 0 if the underlying algorithm is
0N/A * not a block cipher
0N/A */
0N/A public final int getBlockSize() {
0N/A chooseFirstProvider();
0N/A return spi.engineGetBlockSize();
0N/A }
0N/A
0N/A /**
0N/A * Returns the length in bytes that an output buffer would need to be in
0N/A * order to hold the result of the next <code>update</code> or
0N/A * <code>doFinal</code> operation, given the input length
0N/A * <code>inputLen</code> (in bytes).
0N/A *
0N/A * <p>This call takes into account any unprocessed (buffered) data from a
4007N/A * previous <code>update</code> call, padding, and AEAD tagging.
0N/A *
0N/A * <p>The actual output length of the next <code>update</code> or
0N/A * <code>doFinal</code> call may be smaller than the length returned by
0N/A * this method.
0N/A *
0N/A * @param inputLen the input length (in bytes)
0N/A *
0N/A * @return the required output buffer size (in bytes)
0N/A *
0N/A * @exception IllegalStateException if this cipher is in a wrong state
0N/A * (e.g., has not yet been initialized)
0N/A */
0N/A public final int getOutputSize(int inputLen) {
0N/A
0N/A if (!initialized && !(this instanceof NullCipher)) {
0N/A throw new IllegalStateException("Cipher not initialized");
0N/A }
0N/A if (inputLen < 0) {
0N/A throw new IllegalArgumentException("Input size must be equal " +
0N/A "to or greater than zero");
0N/A }
0N/A chooseFirstProvider();
0N/A return spi.engineGetOutputSize(inputLen);
0N/A }
0N/A
0N/A /**
0N/A * Returns the initialization vector (IV) in a new buffer.
0N/A *
0N/A * <p>This is useful in the case where a random IV was created,
0N/A * or in the context of password-based encryption or
0N/A * decryption, where the IV is derived from a user-supplied password.
0N/A *
0N/A * @return the initialization vector in a new buffer, or null if the
0N/A * underlying algorithm does not use an IV, or if the IV has not yet
0N/A * been set.
0N/A */
0N/A public final byte[] getIV() {
0N/A chooseFirstProvider();
0N/A return spi.engineGetIV();
0N/A }
0N/A
0N/A /**
0N/A * Returns the parameters used with this cipher.
0N/A *
0N/A * <p>The returned parameters may be the same that were used to initialize
0N/A * this cipher, or may contain a combination of default and random
0N/A * parameter values used by the underlying cipher implementation if this
0N/A * cipher requires algorithm parameters but was not initialized with any.
0N/A *
0N/A * @return the parameters used with this cipher, or null if this cipher
0N/A * does not use any parameters.
0N/A */
0N/A public final AlgorithmParameters getParameters() {
0N/A chooseFirstProvider();
0N/A return spi.engineGetParameters();
0N/A }
0N/A
0N/A /**
0N/A * Returns the exemption mechanism object used with this cipher.
0N/A *
0N/A * @return the exemption mechanism object used with this cipher, or
0N/A * null if this cipher does not use any exemption mechanism.
0N/A */
0N/A public final ExemptionMechanism getExemptionMechanism() {
0N/A chooseFirstProvider();
0N/A return exmech;
0N/A }
0N/A
0N/A //
0N/A // Crypto permission check code below
0N/A //
0N/A private void checkCryptoPerm(CipherSpi checkSpi, Key key)
0N/A throws InvalidKeyException {
0N/A if (cryptoPerm == CryptoAllPermission.INSTANCE) {
0N/A return;
0N/A }
0N/A // Check if key size and default parameters are within legal limits
0N/A AlgorithmParameterSpec params;
0N/A try {
0N/A params = getAlgorithmParameterSpec(checkSpi.engineGetParameters());
0N/A } catch (InvalidParameterSpecException ipse) {
0N/A throw new InvalidKeyException
0N/A ("Unsupported default algorithm parameters");
0N/A }
0N/A if (!passCryptoPermCheck(checkSpi, key, params)) {
0N/A throw new InvalidKeyException(
0N/A "Illegal key size or default parameters");
0N/A }
0N/A }
0N/A
0N/A private void checkCryptoPerm(CipherSpi checkSpi, Key key,
0N/A AlgorithmParameterSpec params) throws InvalidKeyException,
0N/A InvalidAlgorithmParameterException {
0N/A if (cryptoPerm == CryptoAllPermission.INSTANCE) {
0N/A return;
0N/A }
0N/A // Determine keysize and check if it is within legal limits
0N/A if (!passCryptoPermCheck(checkSpi, key, null)) {
0N/A throw new InvalidKeyException("Illegal key size");
0N/A }
0N/A if ((params != null) && (!passCryptoPermCheck(checkSpi, key, params))) {
0N/A throw new InvalidAlgorithmParameterException("Illegal parameters");
0N/A }
0N/A }
0N/A
0N/A private void checkCryptoPerm(CipherSpi checkSpi, Key key,
0N/A AlgorithmParameters params)
0N/A throws InvalidKeyException, InvalidAlgorithmParameterException {
0N/A if (cryptoPerm == CryptoAllPermission.INSTANCE) {
0N/A return;
0N/A }
0N/A // Convert the specified parameters into specs and then delegate.
0N/A AlgorithmParameterSpec pSpec;
0N/A try {
0N/A pSpec = getAlgorithmParameterSpec(params);
0N/A } catch (InvalidParameterSpecException ipse) {
0N/A throw new InvalidAlgorithmParameterException
0N/A ("Failed to retrieve algorithm parameter specification");
0N/A }
0N/A checkCryptoPerm(checkSpi, key, pSpec);
0N/A }
0N/A
0N/A private boolean passCryptoPermCheck(CipherSpi checkSpi, Key key,
0N/A AlgorithmParameterSpec params)
0N/A throws InvalidKeyException {
0N/A String em = cryptoPerm.getExemptionMechanism();
0N/A int keySize = checkSpi.engineGetKeySize(key);
0N/A // Use the "algorithm" component of the cipher
0N/A // transformation so that the perm check would
0N/A // work when the key has the "aliased" algo.
0N/A String algComponent;
0N/A int index = transformation.indexOf('/');
0N/A if (index != -1) {
0N/A algComponent = transformation.substring(0, index);
0N/A } else {
0N/A algComponent = transformation;
0N/A }
0N/A CryptoPermission checkPerm =
0N/A new CryptoPermission(algComponent, keySize, params, em);
0N/A
0N/A if (!cryptoPerm.implies(checkPerm)) {
0N/A if (debug != null) {
0N/A debug.println("Crypto Permission check failed");
0N/A debug.println("granted: " + cryptoPerm);
0N/A debug.println("requesting: " + checkPerm);
0N/A }
0N/A return false;
0N/A }
0N/A if (exmech == null) {
0N/A return true;
0N/A }
0N/A try {
0N/A if (!exmech.isCryptoAllowed(key)) {
0N/A if (debug != null) {
0N/A debug.println(exmech.getName() + " isn't enforced");
0N/A }
0N/A return false;
0N/A }
0N/A } catch (ExemptionMechanismException eme) {
0N/A if (debug != null) {
0N/A debug.println("Cannot determine whether "+
0N/A exmech.getName() + " has been enforced");
0N/A eme.printStackTrace();
0N/A }
0N/A return false;
0N/A }
0N/A return true;
0N/A }
0N/A
0N/A // check if opmode is one of the defined constants
0N/A // throw InvalidParameterExeption if not
0N/A private static void checkOpmode(int opmode) {
0N/A if ((opmode < ENCRYPT_MODE) || (opmode > UNWRAP_MODE)) {
0N/A throw new InvalidParameterException("Invalid operation mode");
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Initializes this cipher with a key.
0N/A *
0N/A * <p>The cipher is initialized for one of the following four operations:
0N/A * encryption, decryption, key wrapping or key unwrapping, depending
0N/A * on the value of <code>opmode</code>.
0N/A *
0N/A * <p>If this cipher requires any algorithm parameters that cannot be
0N/A * derived from the given <code>key</code>, the underlying cipher
0N/A * implementation is supposed to generate the required parameters itself
0N/A * (using provider-specific default or random values) if it is being
0N/A * initialized for encryption or key wrapping, and raise an
0N/A * <code>InvalidKeyException</code> if it is being
0N/A * initialized for decryption or key unwrapping.
0N/A * The generated parameters can be retrieved using
0N/A * {@link #getParameters() getParameters} or
0N/A * {@link #getIV() getIV} (if the parameter is an IV).
0N/A *
4007N/A * <p>If this cipher requires algorithm parameters that cannot be
4007N/A * derived from the input parameters, and there are no reasonable
4007N/A * provider-specific default values, initialization will
4007N/A * necessarily fail.
4007N/A *
0N/A * <p>If this cipher (including its underlying feedback or padding scheme)
0N/A * requires any random bytes (e.g., for parameter generation), it will get
0N/A * them using the {@link SecureRandom <code>SecureRandom</code>}
0N/A * implementation of the highest-priority
0N/A * installed provider as the source of randomness.
0N/A * (If none of the installed providers supply an implementation of
0N/A * SecureRandom, a system-provided source of randomness will be used.)
0N/A *
0N/A * <p>Note that when a Cipher object is initialized, it loses all
0N/A * previously-acquired state. In other words, initializing a Cipher is
0N/A * equivalent to creating a new instance of that Cipher and initializing
0N/A * it.
0N/A *
0N/A * @param opmode the operation mode of this cipher (this is one of
0N/A * the following:
0N/A * <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>,
0N/A * <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>)
0N/A * @param key the key
0N/A *
0N/A * @exception InvalidKeyException if the given key is inappropriate for
4007N/A * initializing this cipher, or requires
4007N/A * algorithm parameters that cannot be
0N/A * determined from the given key, or if the given key has a keysize that
0N/A * exceeds the maximum allowable keysize (as determined from the
0N/A * configured jurisdiction policy files).
0N/A */
0N/A public final void init(int opmode, Key key) throws InvalidKeyException {
0N/A init(opmode, key, JceSecurity.RANDOM);
0N/A }
0N/A
0N/A /**
0N/A * Initializes this cipher with a key and a source of randomness.
0N/A *
0N/A * <p>The cipher is initialized for one of the following four operations:
0N/A * encryption, decryption, key wrapping or key unwrapping, depending
0N/A * on the value of <code>opmode</code>.
0N/A *
0N/A * <p>If this cipher requires any algorithm parameters that cannot be
0N/A * derived from the given <code>key</code>, the underlying cipher
0N/A * implementation is supposed to generate the required parameters itself
0N/A * (using provider-specific default or random values) if it is being
0N/A * initialized for encryption or key wrapping, and raise an
0N/A * <code>InvalidKeyException</code> if it is being
0N/A * initialized for decryption or key unwrapping.
0N/A * The generated parameters can be retrieved using
0N/A * {@link #getParameters() getParameters} or
0N/A * {@link #getIV() getIV} (if the parameter is an IV).
0N/A *
4007N/A * <p>If this cipher requires algorithm parameters that cannot be
4007N/A * derived from the input parameters, and there are no reasonable
4007N/A * provider-specific default values, initialization will
4007N/A * necessarily fail.
4007N/A *
0N/A * <p>If this cipher (including its underlying feedback or padding scheme)
0N/A * requires any random bytes (e.g., for parameter generation), it will get
0N/A * them from <code>random</code>.
0N/A *
0N/A * <p>Note that when a Cipher object is initialized, it loses all
0N/A * previously-acquired state. In other words, initializing a Cipher is
0N/A * equivalent to creating a new instance of that Cipher and initializing
0N/A * it.
0N/A *
0N/A * @param opmode the operation mode of this cipher (this is one of the
0N/A * following:
0N/A * <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>,
0N/A * <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>)
0N/A * @param key the encryption key
0N/A * @param random the source of randomness
0N/A *
0N/A * @exception InvalidKeyException if the given key is inappropriate for
4007N/A * initializing this cipher, or requires
4007N/A * algorithm parameters that cannot be
0N/A * determined from the given key, or if the given key has a keysize that
0N/A * exceeds the maximum allowable keysize (as determined from the
0N/A * configured jurisdiction policy files).
0N/A */
0N/A public final void init(int opmode, Key key, SecureRandom random)
0N/A throws InvalidKeyException
0N/A {
0N/A initialized = false;
0N/A checkOpmode(opmode);
0N/A
0N/A if (spi != null) {
0N/A checkCryptoPerm(spi, key);
0N/A spi.engineInit(opmode, key, random);
0N/A } else {
0N/A try {
0N/A chooseProvider(I_KEY, opmode, key, null, null, random);
0N/A } catch (InvalidAlgorithmParameterException e) {
0N/A // should never occur
0N/A throw new InvalidKeyException(e);
0N/A }
0N/A }
0N/A
0N/A initialized = true;
0N/A this.opmode = opmode;
0N/A }
0N/A
0N/A /**
0N/A * Initializes this cipher with a key and a set of algorithm
0N/A * parameters.
0N/A *
0N/A * <p>The cipher is initialized for one of the following four operations:
0N/A * encryption, decryption, key wrapping or key unwrapping, depending
0N/A * on the value of <code>opmode</code>.
0N/A *
0N/A * <p>If this cipher requires any algorithm parameters and
0N/A * <code>params</code> is null, the underlying cipher implementation is
0N/A * supposed to generate the required parameters itself (using
0N/A * provider-specific default or random values) if it is being
0N/A * initialized for encryption or key wrapping, and raise an
0N/A * <code>InvalidAlgorithmParameterException</code> if it is being
0N/A * initialized for decryption or key unwrapping.
0N/A * The generated parameters can be retrieved using
0N/A * {@link #getParameters() getParameters} or
0N/A * {@link #getIV() getIV} (if the parameter is an IV).
0N/A *
4007N/A * <p>If this cipher requires algorithm parameters that cannot be
4007N/A * derived from the input parameters, and there are no reasonable
4007N/A * provider-specific default values, initialization will
4007N/A * necessarily fail.
4007N/A *
0N/A * <p>If this cipher (including its underlying feedback or padding scheme)
0N/A * requires any random bytes (e.g., for parameter generation), it will get
0N/A * them using the {@link SecureRandom <code>SecureRandom</code>}
0N/A * implementation of the highest-priority
0N/A * installed provider as the source of randomness.
0N/A * (If none of the installed providers supply an implementation of
0N/A * SecureRandom, a system-provided source of randomness will be used.)
0N/A *
0N/A * <p>Note that when a Cipher object is initialized, it loses all
0N/A * previously-acquired state. In other words, initializing a Cipher is
0N/A * equivalent to creating a new instance of that Cipher and initializing
0N/A * it.
0N/A *
0N/A * @param opmode the operation mode of this cipher (this is one of the
0N/A * following:
0N/A * <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>,
0N/A * <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>)
0N/A * @param key the encryption key
0N/A * @param params the algorithm parameters
0N/A *
0N/A * @exception InvalidKeyException if the given key is inappropriate for
0N/A * initializing this cipher, or its keysize exceeds the maximum allowable
0N/A * keysize (as determined from the configured jurisdiction policy files).
0N/A * @exception InvalidAlgorithmParameterException if the given algorithm
0N/A * parameters are inappropriate for this cipher,
4007N/A * or this cipher requires
0N/A * algorithm parameters and <code>params</code> is null, or the given
0N/A * algorithm parameters imply a cryptographic strength that would exceed
0N/A * the legal limits (as determined from the configured jurisdiction
0N/A * policy files).
0N/A */
0N/A public final void init(int opmode, Key key, AlgorithmParameterSpec params)
0N/A throws InvalidKeyException, InvalidAlgorithmParameterException
0N/A {
0N/A init(opmode, key, params, JceSecurity.RANDOM);
0N/A }
0N/A
0N/A /**
0N/A * Initializes this cipher with a key, a set of algorithm
0N/A * parameters, and a source of randomness.
0N/A *
0N/A * <p>The cipher is initialized for one of the following four operations:
0N/A * encryption, decryption, key wrapping or key unwrapping, depending
0N/A * on the value of <code>opmode</code>.
0N/A *
0N/A * <p>If this cipher requires any algorithm parameters and
0N/A * <code>params</code> is null, the underlying cipher implementation is
0N/A * supposed to generate the required parameters itself (using
0N/A * provider-specific default or random values) if it is being
0N/A * initialized for encryption or key wrapping, and raise an
0N/A * <code>InvalidAlgorithmParameterException</code> if it is being
0N/A * initialized for decryption or key unwrapping.
0N/A * The generated parameters can be retrieved using
0N/A * {@link #getParameters() getParameters} or
0N/A * {@link #getIV() getIV} (if the parameter is an IV).
0N/A *
4007N/A * <p>If this cipher requires algorithm parameters that cannot be
4007N/A * derived from the input parameters, and there are no reasonable
4007N/A * provider-specific default values, initialization will
4007N/A * necessarily fail.
4007N/A *
0N/A * <p>If this cipher (including its underlying feedback or padding scheme)
0N/A * requires any random bytes (e.g., for parameter generation), it will get
0N/A * them from <code>random</code>.
0N/A *
0N/A * <p>Note that when a Cipher object is initialized, it loses all
0N/A * previously-acquired state. In other words, initializing a Cipher is
0N/A * equivalent to creating a new instance of that Cipher and initializing
0N/A * it.
0N/A *
0N/A * @param opmode the operation mode of this cipher (this is one of the
0N/A * following:
0N/A * <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>,
0N/A * <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>)
0N/A * @param key the encryption key
0N/A * @param params the algorithm parameters
0N/A * @param random the source of randomness
0N/A *
0N/A * @exception InvalidKeyException if the given key is inappropriate for
0N/A * initializing this cipher, or its keysize exceeds the maximum allowable
0N/A * keysize (as determined from the configured jurisdiction policy files).
0N/A * @exception InvalidAlgorithmParameterException if the given algorithm
0N/A * parameters are inappropriate for this cipher,
4007N/A * or this cipher requires
0N/A * algorithm parameters and <code>params</code> is null, or the given
0N/A * algorithm parameters imply a cryptographic strength that would exceed
0N/A * the legal limits (as determined from the configured jurisdiction
0N/A * policy files).
0N/A */
0N/A public final void init(int opmode, Key key, AlgorithmParameterSpec params,
0N/A SecureRandom random)
0N/A throws InvalidKeyException, InvalidAlgorithmParameterException
0N/A {
0N/A initialized = false;
0N/A checkOpmode(opmode);
0N/A
0N/A if (spi != null) {
0N/A checkCryptoPerm(spi, key, params);
0N/A spi.engineInit(opmode, key, params, random);
0N/A } else {
0N/A chooseProvider(I_PARAMSPEC, opmode, key, params, null, random);
0N/A }
0N/A
0N/A initialized = true;
0N/A this.opmode = opmode;
0N/A }
0N/A
0N/A /**
0N/A * Initializes this cipher with a key and a set of algorithm
0N/A * parameters.
0N/A *
0N/A * <p>The cipher is initialized for one of the following four operations:
0N/A * encryption, decryption, key wrapping or key unwrapping, depending
0N/A * on the value of <code>opmode</code>.
0N/A *
0N/A * <p>If this cipher requires any algorithm parameters and
0N/A * <code>params</code> is null, the underlying cipher implementation is
0N/A * supposed to generate the required parameters itself (using
0N/A * provider-specific default or random values) if it is being
0N/A * initialized for encryption or key wrapping, and raise an
0N/A * <code>InvalidAlgorithmParameterException</code> if it is being
0N/A * initialized for decryption or key unwrapping.
0N/A * The generated parameters can be retrieved using
0N/A * {@link #getParameters() getParameters} or
0N/A * {@link #getIV() getIV} (if the parameter is an IV).
0N/A *
4007N/A * <p>If this cipher requires algorithm parameters that cannot be
4007N/A * derived from the input parameters, and there are no reasonable
4007N/A * provider-specific default values, initialization will
4007N/A * necessarily fail.
4007N/A *
0N/A * <p>If this cipher (including its underlying feedback or padding scheme)
0N/A * requires any random bytes (e.g., for parameter generation), it will get
0N/A * them using the {@link SecureRandom <code>SecureRandom</code>}
0N/A * implementation of the highest-priority
0N/A * installed provider as the source of randomness.
0N/A * (If none of the installed providers supply an implementation of
0N/A * SecureRandom, a system-provided source of randomness will be used.)
0N/A *
0N/A * <p>Note that when a Cipher object is initialized, it loses all
0N/A * previously-acquired state. In other words, initializing a Cipher is
0N/A * equivalent to creating a new instance of that Cipher and initializing
0N/A * it.
0N/A *
0N/A * @param opmode the operation mode of this cipher (this is one of the
0N/A * following: <code>ENCRYPT_MODE</code>,
0N/A * <code>DECRYPT_MODE</code>, <code>WRAP_MODE</code>
0N/A * or <code>UNWRAP_MODE</code>)
0N/A * @param key the encryption key
0N/A * @param params the algorithm parameters
0N/A *
0N/A * @exception InvalidKeyException if the given key is inappropriate for
0N/A * initializing this cipher, or its keysize exceeds the maximum allowable
0N/A * keysize (as determined from the configured jurisdiction policy files).
0N/A * @exception InvalidAlgorithmParameterException if the given algorithm
0N/A * parameters are inappropriate for this cipher,
4007N/A * or this cipher requires
0N/A * algorithm parameters and <code>params</code> is null, or the given
0N/A * algorithm parameters imply a cryptographic strength that would exceed
0N/A * the legal limits (as determined from the configured jurisdiction
0N/A * policy files).
0N/A */
0N/A public final void init(int opmode, Key key, AlgorithmParameters params)
0N/A throws InvalidKeyException, InvalidAlgorithmParameterException
0N/A {
0N/A init(opmode, key, params, JceSecurity.RANDOM);
0N/A }
0N/A
0N/A /**
0N/A * Initializes this cipher with a key, a set of algorithm
0N/A * parameters, and a source of randomness.
0N/A *
0N/A * <p>The cipher is initialized for one of the following four operations:
0N/A * encryption, decryption, key wrapping or key unwrapping, depending
0N/A * on the value of <code>opmode</code>.
0N/A *
0N/A * <p>If this cipher requires any algorithm parameters and
0N/A * <code>params</code> is null, the underlying cipher implementation is
0N/A * supposed to generate the required parameters itself (using
0N/A * provider-specific default or random values) if it is being
0N/A * initialized for encryption or key wrapping, and raise an
0N/A * <code>InvalidAlgorithmParameterException</code> if it is being
0N/A * initialized for decryption or key unwrapping.
0N/A * The generated parameters can be retrieved using
0N/A * {@link #getParameters() getParameters} or
0N/A * {@link #getIV() getIV} (if the parameter is an IV).
0N/A *
4007N/A * <p>If this cipher requires algorithm parameters that cannot be
4007N/A * derived from the input parameters, and there are no reasonable
4007N/A * provider-specific default values, initialization will
4007N/A * necessarily fail.
4007N/A *
0N/A * <p>If this cipher (including its underlying feedback or padding scheme)
0N/A * requires any random bytes (e.g., for parameter generation), it will get
0N/A * them from <code>random</code>.
0N/A *
0N/A * <p>Note that when a Cipher object is initialized, it loses all
0N/A * previously-acquired state. In other words, initializing a Cipher is
0N/A * equivalent to creating a new instance of that Cipher and initializing
0N/A * it.
0N/A *
0N/A * @param opmode the operation mode of this cipher (this is one of the
0N/A * following: <code>ENCRYPT_MODE</code>,
0N/A * <code>DECRYPT_MODE</code>, <code>WRAP_MODE</code>
0N/A * or <code>UNWRAP_MODE</code>)
0N/A * @param key the encryption key
0N/A * @param params the algorithm parameters
0N/A * @param random the source of randomness
0N/A *
0N/A * @exception InvalidKeyException if the given key is inappropriate for
0N/A * initializing this cipher, or its keysize exceeds the maximum allowable
0N/A * keysize (as determined from the configured jurisdiction policy files).
0N/A * @exception InvalidAlgorithmParameterException if the given algorithm
0N/A * parameters are inappropriate for this cipher,
4007N/A * or this cipher requires
0N/A * algorithm parameters and <code>params</code> is null, or the given
0N/A * algorithm parameters imply a cryptographic strength that would exceed
0N/A * the legal limits (as determined from the configured jurisdiction
0N/A * policy files).
0N/A */
0N/A public final void init(int opmode, Key key, AlgorithmParameters params,
0N/A SecureRandom random)
0N/A throws InvalidKeyException, InvalidAlgorithmParameterException
0N/A {
0N/A initialized = false;
0N/A checkOpmode(opmode);
0N/A
0N/A if (spi != null) {
0N/A checkCryptoPerm(spi, key, params);
0N/A spi.engineInit(opmode, key, params, random);
0N/A } else {
0N/A chooseProvider(I_PARAMS, opmode, key, null, params, random);
0N/A }
0N/A
0N/A initialized = true;
0N/A this.opmode = opmode;
0N/A }
0N/A
0N/A /**
0N/A * Initializes this cipher with the public key from the given certificate.
0N/A * <p> The cipher is initialized for one of the following four operations:
0N/A * encryption, decryption, key wrapping or key unwrapping, depending
0N/A * on the value of <code>opmode</code>.
0N/A *
0N/A * <p>If the certificate is of type X.509 and has a <i>key usage</i>
0N/A * extension field marked as critical, and the value of the <i>key usage</i>
0N/A * extension field implies that the public key in
0N/A * the certificate and its corresponding private key are not
0N/A * supposed to be used for the operation represented by the value
0N/A * of <code>opmode</code>,
0N/A * an <code>InvalidKeyException</code>
0N/A * is thrown.
0N/A *
0N/A * <p> If this cipher requires any algorithm parameters that cannot be
0N/A * derived from the public key in the given certificate, the underlying
0N/A * cipher
0N/A * implementation is supposed to generate the required parameters itself
4007N/A * (using provider-specific default or random values) if it is being
0N/A * initialized for encryption or key wrapping, and raise an <code>
0N/A * InvalidKeyException</code> if it is being initialized for decryption or
0N/A * key unwrapping.
0N/A * The generated parameters can be retrieved using
0N/A * {@link #getParameters() getParameters} or
0N/A * {@link #getIV() getIV} (if the parameter is an IV).
0N/A *
4007N/A * <p>If this cipher requires algorithm parameters that cannot be
4007N/A * derived from the input parameters, and there are no reasonable
4007N/A * provider-specific default values, initialization will
4007N/A * necessarily fail.
4007N/A *
0N/A * <p>If this cipher (including its underlying feedback or padding scheme)
0N/A * requires any random bytes (e.g., for parameter generation), it will get
0N/A * them using the
0N/A * <code>SecureRandom</code>
0N/A * implementation of the highest-priority
0N/A * installed provider as the source of randomness.
0N/A * (If none of the installed providers supply an implementation of
0N/A * SecureRandom, a system-provided source of randomness will be used.)
0N/A *
0N/A * <p>Note that when a Cipher object is initialized, it loses all
0N/A * previously-acquired state. In other words, initializing a Cipher is
0N/A * equivalent to creating a new instance of that Cipher and initializing
0N/A * it.
0N/A *
0N/A * @param opmode the operation mode of this cipher (this is one of the
0N/A * following:
0N/A * <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>,
0N/A * <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>)
0N/A * @param certificate the certificate
0N/A *
0N/A * @exception InvalidKeyException if the public key in the given
0N/A * certificate is inappropriate for initializing this cipher, or this
4007N/A * cipher requires algorithm parameters that cannot be determined from the
0N/A * public key in the given certificate, or the keysize of the public key
0N/A * in the given certificate has a keysize that exceeds the maximum
0N/A * allowable keysize (as determined by the configured jurisdiction policy
0N/A * files).
0N/A */
0N/A public final void init(int opmode, Certificate certificate)
0N/A throws InvalidKeyException
0N/A {
0N/A init(opmode, certificate, JceSecurity.RANDOM);
0N/A }
0N/A
0N/A /**
0N/A * Initializes this cipher with the public key from the given certificate
0N/A * and
0N/A * a source of randomness.
0N/A *
0N/A * <p>The cipher is initialized for one of the following four operations:
0N/A * encryption, decryption, key wrapping
0N/A * or key unwrapping, depending on
0N/A * the value of <code>opmode</code>.
0N/A *
0N/A * <p>If the certificate is of type X.509 and has a <i>key usage</i>
0N/A * extension field marked as critical, and the value of the <i>key usage</i>
0N/A * extension field implies that the public key in
0N/A * the certificate and its corresponding private key are not
0N/A * supposed to be used for the operation represented by the value of
0N/A * <code>opmode</code>,
0N/A * an <code>InvalidKeyException</code>
0N/A * is thrown.
0N/A *
0N/A * <p>If this cipher requires any algorithm parameters that cannot be
0N/A * derived from the public key in the given <code>certificate</code>,
0N/A * the underlying cipher
0N/A * implementation is supposed to generate the required parameters itself
0N/A * (using provider-specific default or random values) if it is being
0N/A * initialized for encryption or key wrapping, and raise an
0N/A * <code>InvalidKeyException</code> if it is being
0N/A * initialized for decryption or key unwrapping.
0N/A * The generated parameters can be retrieved using
0N/A * {@link #getParameters() getParameters} or
0N/A * {@link #getIV() getIV} (if the parameter is an IV).
0N/A *
4007N/A * <p>If this cipher requires algorithm parameters that cannot be
4007N/A * derived from the input parameters, and there are no reasonable
4007N/A * provider-specific default values, initialization will
4007N/A * necessarily fail.
4007N/A *
0N/A * <p>If this cipher (including its underlying feedback or padding scheme)
0N/A * requires any random bytes (e.g., for parameter generation), it will get
0N/A * them from <code>random</code>.
0N/A *
0N/A * <p>Note that when a Cipher object is initialized, it loses all
0N/A * previously-acquired state. In other words, initializing a Cipher is
0N/A * equivalent to creating a new instance of that Cipher and initializing
0N/A * it.
0N/A *
0N/A * @param opmode the operation mode of this cipher (this is one of the
0N/A * following:
0N/A * <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>,
0N/A * <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>)
0N/A * @param certificate the certificate
0N/A * @param random the source of randomness
0N/A *
0N/A * @exception InvalidKeyException if the public key in the given
0N/A * certificate is inappropriate for initializing this cipher, or this
4007N/A * cipher
0N/A * requires algorithm parameters that cannot be determined from the
0N/A * public key in the given certificate, or the keysize of the public key
0N/A * in the given certificate has a keysize that exceeds the maximum
0N/A * allowable keysize (as determined by the configured jurisdiction policy
0N/A * files).
0N/A */
0N/A public final void init(int opmode, Certificate certificate,
0N/A SecureRandom random)
0N/A throws InvalidKeyException
0N/A {
0N/A initialized = false;
0N/A checkOpmode(opmode);
0N/A
0N/A // Check key usage if the certificate is of
0N/A // type X.509.
0N/A if (certificate instanceof java.security.cert.X509Certificate) {
0N/A // Check whether the cert has a key usage extension
0N/A // marked as a critical extension.
0N/A X509Certificate cert = (X509Certificate)certificate;
0N/A Set critSet = cert.getCriticalExtensionOIDs();
0N/A
0N/A if (critSet != null && !critSet.isEmpty()
0N/A && critSet.contains(KEY_USAGE_EXTENSION_OID)) {
0N/A boolean[] keyUsageInfo = cert.getKeyUsage();
0N/A // keyUsageInfo[2] is for keyEncipherment;
0N/A // keyUsageInfo[3] is for dataEncipherment.
0N/A if ((keyUsageInfo != null) &&
0N/A (((opmode == Cipher.ENCRYPT_MODE) &&
0N/A (keyUsageInfo.length > 3) &&
0N/A (keyUsageInfo[3] == false)) ||
0N/A ((opmode == Cipher.WRAP_MODE) &&
0N/A (keyUsageInfo.length > 2) &&
0N/A (keyUsageInfo[2] == false)))) {
0N/A throw new InvalidKeyException("Wrong key usage");
0N/A }
0N/A }
0N/A }
0N/A
0N/A PublicKey publicKey =
0N/A (certificate==null? null:certificate.getPublicKey());
0N/A
0N/A if (spi != null) {
0N/A checkCryptoPerm(spi, publicKey);
0N/A spi.engineInit(opmode, publicKey, random);
0N/A } else {
0N/A try {
0N/A chooseProvider(I_CERT, opmode, publicKey, null, null, random);
0N/A } catch (InvalidAlgorithmParameterException e) {
0N/A // should never occur
0N/A throw new InvalidKeyException(e);
0N/A }
0N/A }
0N/A
0N/A initialized = true;
0N/A this.opmode = opmode;
0N/A }
0N/A
0N/A /**
0N/A * Ensures that Cipher is in a valid state for update() and doFinal()
0N/A * calls - should be initialized and in ENCRYPT_MODE or DECRYPT_MODE.
0N/A * @throws IllegalStateException if Cipher object is not in valid state.
0N/A */
0N/A private void checkCipherState() {
0N/A if (!(this instanceof NullCipher)) {
0N/A if (!initialized) {
0N/A throw new IllegalStateException("Cipher not initialized");
0N/A }
0N/A if ((opmode != Cipher.ENCRYPT_MODE) &&
0N/A (opmode != Cipher.DECRYPT_MODE)) {
0N/A throw new IllegalStateException("Cipher not initialized " +
0N/A "for encryption/decryption");
0N/A }
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Continues a multiple-part encryption or decryption operation
0N/A * (depending on how this cipher was initialized), processing another data
0N/A * part.
0N/A *
0N/A * <p>The bytes in the <code>input</code> buffer are processed, and the
0N/A * result is stored in a new buffer.
0N/A *
0N/A * <p>If <code>input</code> has a length of zero, this method returns
0N/A * <code>null</code>.
0N/A *
0N/A * @param input the input buffer
0N/A *
0N/A * @return the new buffer with the result, or null if the underlying
0N/A * cipher is a block cipher and the input data is too short to result in a
0N/A * new block.
0N/A *
0N/A * @exception IllegalStateException if this cipher is in a wrong state
0N/A * (e.g., has not been initialized)
0N/A */
0N/A public final byte[] update(byte[] input) {
0N/A checkCipherState();
0N/A
0N/A // Input sanity check
0N/A if (input == null) {
0N/A throw new IllegalArgumentException("Null input buffer");
0N/A }
0N/A
0N/A chooseFirstProvider();
0N/A if (input.length == 0) {
0N/A return null;
0N/A }
0N/A return spi.engineUpdate(input, 0, input.length);
0N/A }
0N/A
0N/A /**
0N/A * Continues a multiple-part encryption or decryption operation
0N/A * (depending on how this cipher was initialized), processing another data
0N/A * part.
0N/A *
0N/A * <p>The first <code>inputLen</code> bytes in the <code>input</code>
0N/A * buffer, starting at <code>inputOffset</code> inclusive, are processed,
0N/A * and the result is stored in a new buffer.
0N/A *
0N/A * <p>If <code>inputLen</code> is zero, this method returns
0N/A * <code>null</code>.
0N/A *
0N/A * @param input the input buffer
0N/A * @param inputOffset the offset in <code>input</code> where the input
0N/A * starts
0N/A * @param inputLen the input length
0N/A *
0N/A * @return the new buffer with the result, or null if the underlying
0N/A * cipher is a block cipher and the input data is too short to result in a
0N/A * new block.
0N/A *
0N/A * @exception IllegalStateException if this cipher is in a wrong state
0N/A * (e.g., has not been initialized)
0N/A */
0N/A public final byte[] update(byte[] input, int inputOffset, int inputLen) {
0N/A checkCipherState();
0N/A
0N/A // Input sanity check
0N/A if (input == null || inputOffset < 0
0N/A || inputLen > (input.length - inputOffset) || inputLen < 0) {
0N/A throw new IllegalArgumentException("Bad arguments");
0N/A }
0N/A
0N/A chooseFirstProvider();
0N/A if (inputLen == 0) {
0N/A return null;
0N/A }
0N/A return spi.engineUpdate(input, inputOffset, inputLen);
0N/A }
0N/A
0N/A /**
0N/A * Continues a multiple-part encryption or decryption operation
0N/A * (depending on how this cipher was initialized), processing another data
0N/A * part.
0N/A *
0N/A * <p>The first <code>inputLen</code> bytes in the <code>input</code>
0N/A * buffer, starting at <code>inputOffset</code> inclusive, are processed,
0N/A * and the result is stored in the <code>output</code> buffer.
0N/A *
0N/A * <p>If the <code>output</code> buffer is too small to hold the result,
0N/A * a <code>ShortBufferException</code> is thrown. In this case, repeat this
0N/A * call with a larger output buffer. Use
0N/A * {@link #getOutputSize(int) getOutputSize} to determine how big
0N/A * the output buffer should be.
0N/A *
0N/A * <p>If <code>inputLen</code> is zero, this method returns
0N/A * a length of zero.
0N/A *
0N/A * <p>Note: this method should be copy-safe, which means the
0N/A * <code>input</code> and <code>output</code> buffers can reference
0N/A * the same byte array and no unprocessed input data is overwritten
0N/A * when the result is copied into the output buffer.
0N/A *
0N/A * @param input the input buffer
0N/A * @param inputOffset the offset in <code>input</code> where the input
0N/A * starts
0N/A * @param inputLen the input length
0N/A * @param output the buffer for the result
0N/A *
0N/A * @return the number of bytes stored in <code>output</code>
0N/A *
0N/A * @exception IllegalStateException if this cipher is in a wrong state
0N/A * (e.g., has not been initialized)
0N/A * @exception ShortBufferException if the given output buffer is too small
0N/A * to hold the result
0N/A */
0N/A public final int update(byte[] input, int inputOffset, int inputLen,
0N/A byte[] output)
0N/A throws ShortBufferException {
0N/A checkCipherState();
0N/A
0N/A // Input sanity check
0N/A if (input == null || inputOffset < 0
0N/A || inputLen > (input.length - inputOffset) || inputLen < 0) {
0N/A throw new IllegalArgumentException("Bad arguments");
0N/A }
0N/A
0N/A chooseFirstProvider();
0N/A if (inputLen == 0) {
0N/A return 0;
0N/A }
0N/A return spi.engineUpdate(input, inputOffset, inputLen,
0N/A output, 0);
0N/A }
0N/A
0N/A /**
0N/A * Continues a multiple-part encryption or decryption operation
0N/A * (depending on how this cipher was initialized), processing another data
0N/A * part.
0N/A *
0N/A * <p>The first <code>inputLen</code> bytes in the <code>input</code>
0N/A * buffer, starting at <code>inputOffset</code> inclusive, are processed,
0N/A * and the result is stored in the <code>output</code> buffer, starting at
0N/A * <code>outputOffset</code> inclusive.
0N/A *
0N/A * <p>If the <code>output</code> buffer is too small to hold the result,
0N/A * a <code>ShortBufferException</code> is thrown. In this case, repeat this
0N/A * call with a larger output buffer. Use
0N/A * {@link #getOutputSize(int) getOutputSize} to determine how big
0N/A * the output buffer should be.
0N/A *
0N/A * <p>If <code>inputLen</code> is zero, this method returns
0N/A * a length of zero.
0N/A *
0N/A * <p>Note: this method should be copy-safe, which means the
0N/A * <code>input</code> and <code>output</code> buffers can reference
0N/A * the same byte array and no unprocessed input data is overwritten
0N/A * when the result is copied into the output buffer.
0N/A *
0N/A * @param input the input buffer
0N/A * @param inputOffset the offset in <code>input</code> where the input
0N/A * starts
0N/A * @param inputLen the input length
0N/A * @param output the buffer for the result
0N/A * @param outputOffset the offset in <code>output</code> where the result
0N/A * is stored
0N/A *
0N/A * @return the number of bytes stored in <code>output</code>
0N/A *
0N/A * @exception IllegalStateException if this cipher is in a wrong state
0N/A * (e.g., has not been initialized)
0N/A * @exception ShortBufferException if the given output buffer is too small
0N/A * to hold the result
0N/A */
0N/A public final int update(byte[] input, int inputOffset, int inputLen,
0N/A byte[] output, int outputOffset)
0N/A throws ShortBufferException {
0N/A checkCipherState();
0N/A
0N/A // Input sanity check
0N/A if (input == null || inputOffset < 0
0N/A || inputLen > (input.length - inputOffset) || inputLen < 0
0N/A || outputOffset < 0) {
0N/A throw new IllegalArgumentException("Bad arguments");
0N/A }
0N/A
0N/A chooseFirstProvider();
0N/A if (inputLen == 0) {
0N/A return 0;
0N/A }
0N/A return spi.engineUpdate(input, inputOffset, inputLen,
0N/A output, outputOffset);
0N/A }
0N/A
0N/A /**
0N/A * Continues a multiple-part encryption or decryption operation
0N/A * (depending on how this cipher was initialized), processing another data
0N/A * part.
0N/A *
0N/A * <p>All <code>input.remaining()</code> bytes starting at
0N/A * <code>input.position()</code> are processed. The result is stored
0N/A * in the output buffer.
0N/A * Upon return, the input buffer's position will be equal
0N/A * to its limit; its limit will not have changed. The output buffer's
0N/A * position will have advanced by n, where n is the value returned
0N/A * by this method; the output buffer's limit will not have changed.
0N/A *
0N/A * <p>If <code>output.remaining()</code> bytes are insufficient to
0N/A * hold the result, a <code>ShortBufferException</code> is thrown.
0N/A * In this case, repeat this call with a larger output buffer. Use
0N/A * {@link #getOutputSize(int) getOutputSize} to determine how big
0N/A * the output buffer should be.
0N/A *
0N/A * <p>Note: this method should be copy-safe, which means the
0N/A * <code>input</code> and <code>output</code> buffers can reference
0N/A * the same block of memory and no unprocessed input data is overwritten
0N/A * when the result is copied into the output buffer.
0N/A *
0N/A * @param input the input ByteBuffer
0N/A * @param output the output ByteByffer
0N/A *
0N/A * @return the number of bytes stored in <code>output</code>
0N/A *
0N/A * @exception IllegalStateException if this cipher is in a wrong state
0N/A * (e.g., has not been initialized)
0N/A * @exception IllegalArgumentException if input and output are the
0N/A * same object
0N/A * @exception ReadOnlyBufferException if the output buffer is read-only
0N/A * @exception ShortBufferException if there is insufficient space in the
0N/A * output buffer
0N/A * @since 1.5
0N/A */
0N/A public final int update(ByteBuffer input, ByteBuffer output)
0N/A throws ShortBufferException {
0N/A checkCipherState();
0N/A
0N/A if ((input == null) || (output == null)) {
0N/A throw new IllegalArgumentException("Buffers must not be null");
0N/A }
0N/A if (input == output) {
0N/A throw new IllegalArgumentException("Input and output buffers must "
0N/A + "not be the same object, consider using buffer.duplicate()");
0N/A }
0N/A if (output.isReadOnly()) {
0N/A throw new ReadOnlyBufferException();
0N/A }
0N/A
0N/A chooseFirstProvider();
0N/A return spi.engineUpdate(input, output);
0N/A }
0N/A
0N/A /**
0N/A * Finishes a multiple-part encryption or decryption operation, depending
0N/A * on how this cipher was initialized.
0N/A *
0N/A * <p>Input data that may have been buffered during a previous
0N/A * <code>update</code> operation is processed, with padding (if requested)
0N/A * being applied.
4007N/A * If an AEAD mode such as GCM/CCM is being used, the authentication
4007N/A * tag is appended in the case of encryption, or verified in the
4007N/A * case of decryption.
0N/A * The result is stored in a new buffer.
0N/A *
0N/A * <p>Upon finishing, this method resets this cipher object to the state
0N/A * it was in when previously initialized via a call to <code>init</code>.
0N/A * That is, the object is reset and available to encrypt or decrypt
0N/A * (depending on the operation mode that was specified in the call to
0N/A * <code>init</code>) more data.
0N/A *
0N/A * <p>Note: if any exception is thrown, this cipher object may need to
0N/A * be reset before it can be used again.
0N/A *
0N/A * @return the new buffer with the result
0N/A *
0N/A * @exception IllegalStateException if this cipher is in a wrong state
0N/A * (e.g., has not been initialized)
0N/A * @exception IllegalBlockSizeException if this cipher is a block cipher,
0N/A * no padding has been requested (only in encryption mode), and the total
0N/A * input length of the data processed by this cipher is not a multiple of
0N/A * block size; or if this encryption algorithm is unable to
0N/A * process the input data provided.
0N/A * @exception BadPaddingException if this cipher is in decryption mode,
0N/A * and (un)padding has been requested, but the decrypted data is not
0N/A * bounded by the appropriate padding bytes
4007N/A * @exception AEADBadTagException if this cipher is decrypting in an
4007N/A * AEAD mode (such as GCM/CCM), and the received authentication tag
4007N/A * does not match the calculated value
0N/A */
0N/A public final byte[] doFinal()
0N/A throws IllegalBlockSizeException, BadPaddingException {
0N/A checkCipherState();
0N/A
0N/A chooseFirstProvider();
0N/A return spi.engineDoFinal(null, 0, 0);
0N/A }
0N/A
0N/A /**
0N/A * Finishes a multiple-part encryption or decryption operation, depending
0N/A * on how this cipher was initialized.
0N/A *
0N/A * <p>Input data that may have been buffered during a previous
0N/A * <code>update</code> operation is processed, with padding (if requested)
0N/A * being applied.
4007N/A * If an AEAD mode such as GCM/CCM is being used, the authentication
4007N/A * tag is appended in the case of encryption, or verified in the
4007N/A * case of decryption.
0N/A * The result is stored in the <code>output</code> buffer, starting at
0N/A * <code>outputOffset</code> inclusive.
0N/A *
0N/A * <p>If the <code>output</code> buffer is too small to hold the result,
0N/A * a <code>ShortBufferException</code> is thrown. In this case, repeat this
0N/A * call with a larger output buffer. Use
0N/A * {@link #getOutputSize(int) getOutputSize} to determine how big
0N/A * the output buffer should be.
0N/A *
0N/A * <p>Upon finishing, this method resets this cipher object to the state
0N/A * it was in when previously initialized via a call to <code>init</code>.
0N/A * That is, the object is reset and available to encrypt or decrypt
0N/A * (depending on the operation mode that was specified in the call to
0N/A * <code>init</code>) more data.
0N/A *
0N/A * <p>Note: if any exception is thrown, this cipher object may need to
0N/A * be reset before it can be used again.
0N/A *
0N/A * @param output the buffer for the result
0N/A * @param outputOffset the offset in <code>output</code> where the result
0N/A * is stored
0N/A *
0N/A * @return the number of bytes stored in <code>output</code>
0N/A *
0N/A * @exception IllegalStateException if this cipher is in a wrong state
0N/A * (e.g., has not been initialized)
0N/A * @exception IllegalBlockSizeException if this cipher is a block cipher,
0N/A * no padding has been requested (only in encryption mode), and the total
0N/A * input length of the data processed by this cipher is not a multiple of
0N/A * block size; or if this encryption algorithm is unable to
0N/A * process the input data provided.
0N/A * @exception ShortBufferException if the given output buffer is too small
0N/A * to hold the result
0N/A * @exception BadPaddingException if this cipher is in decryption mode,
0N/A * and (un)padding has been requested, but the decrypted data is not
0N/A * bounded by the appropriate padding bytes
4007N/A * @exception AEADBadTagException if this cipher is decrypting in an
4007N/A * AEAD mode (such as GCM/CCM), and the received authentication tag
4007N/A * does not match the calculated value
0N/A */
0N/A public final int doFinal(byte[] output, int outputOffset)
0N/A throws IllegalBlockSizeException, ShortBufferException,
0N/A BadPaddingException {
0N/A checkCipherState();
0N/A
0N/A // Input sanity check
0N/A if ((output == null) || (outputOffset < 0)) {
0N/A throw new IllegalArgumentException("Bad arguments");
0N/A }
0N/A
0N/A chooseFirstProvider();
0N/A return spi.engineDoFinal(null, 0, 0, output, outputOffset);
0N/A }
0N/A
0N/A /**
0N/A * Encrypts or decrypts data in a single-part operation, or finishes a
0N/A * multiple-part operation. The data is encrypted or decrypted,
0N/A * depending on how this cipher was initialized.
0N/A *
0N/A * <p>The bytes in the <code>input</code> buffer, and any input bytes that
0N/A * may have been buffered during a previous <code>update</code> operation,
0N/A * are processed, with padding (if requested) being applied.
4007N/A * If an AEAD mode such as GCM/CCM is being used, the authentication
4007N/A * tag is appended in the case of encryption, or verified in the
4007N/A * case of decryption.
0N/A * The result is stored in a new buffer.
0N/A *
0N/A * <p>Upon finishing, this method resets this cipher object to the state
0N/A * it was in when previously initialized via a call to <code>init</code>.
0N/A * That is, the object is reset and available to encrypt or decrypt
0N/A * (depending on the operation mode that was specified in the call to
0N/A * <code>init</code>) more data.
0N/A *
0N/A * <p>Note: if any exception is thrown, this cipher object may need to
0N/A * be reset before it can be used again.
0N/A *
0N/A * @param input the input buffer
0N/A *
0N/A * @return the new buffer with the result
0N/A *
0N/A * @exception IllegalStateException if this cipher is in a wrong state
0N/A * (e.g., has not been initialized)
0N/A * @exception IllegalBlockSizeException if this cipher is a block cipher,
0N/A * no padding has been requested (only in encryption mode), and the total
0N/A * input length of the data processed by this cipher is not a multiple of
0N/A * block size; or if this encryption algorithm is unable to
0N/A * process the input data provided.
0N/A * @exception BadPaddingException if this cipher is in decryption mode,
0N/A * and (un)padding has been requested, but the decrypted data is not
0N/A * bounded by the appropriate padding bytes
4007N/A * @exception AEADBadTagException if this cipher is decrypting in an
4007N/A * AEAD mode (such as GCM/CCM), and the received authentication tag
4007N/A * does not match the calculated value
0N/A */
0N/A public final byte[] doFinal(byte[] input)
0N/A throws IllegalBlockSizeException, BadPaddingException {
0N/A checkCipherState();
0N/A
0N/A // Input sanity check
0N/A if (input == null) {
0N/A throw new IllegalArgumentException("Null input buffer");
0N/A }
0N/A
0N/A chooseFirstProvider();
0N/A return spi.engineDoFinal(input, 0, input.length);
0N/A }
0N/A
0N/A /**
0N/A * Encrypts or decrypts data in a single-part operation, or finishes a
0N/A * multiple-part operation. The data is encrypted or decrypted,
0N/A * depending on how this cipher was initialized.
0N/A *
0N/A * <p>The first <code>inputLen</code> bytes in the <code>input</code>
0N/A * buffer, starting at <code>inputOffset</code> inclusive, and any input
0N/A * bytes that may have been buffered during a previous <code>update</code>
0N/A * operation, are processed, with padding (if requested) being applied.
4007N/A * If an AEAD mode such as GCM/CCM is being used, the authentication
4007N/A * tag is appended in the case of encryption, or verified in the
4007N/A * case of decryption.
0N/A * The result is stored in a new buffer.
0N/A *
0N/A * <p>Upon finishing, this method resets this cipher object to the state
0N/A * it was in when previously initialized via a call to <code>init</code>.
0N/A * That is, the object is reset and available to encrypt or decrypt
0N/A * (depending on the operation mode that was specified in the call to
0N/A * <code>init</code>) more data.
0N/A *
0N/A * <p>Note: if any exception is thrown, this cipher object may need to
0N/A * be reset before it can be used again.
0N/A *
0N/A * @param input the input buffer
0N/A * @param inputOffset the offset in <code>input</code> where the input
0N/A * starts
0N/A * @param inputLen the input length
0N/A *
0N/A * @return the new buffer with the result
0N/A *
0N/A * @exception IllegalStateException if this cipher is in a wrong state
0N/A * (e.g., has not been initialized)
0N/A * @exception IllegalBlockSizeException if this cipher is a block cipher,
0N/A * no padding has been requested (only in encryption mode), and the total
0N/A * input length of the data processed by this cipher is not a multiple of
0N/A * block size; or if this encryption algorithm is unable to
0N/A * process the input data provided.
0N/A * @exception BadPaddingException if this cipher is in decryption mode,
0N/A * and (un)padding has been requested, but the decrypted data is not
0N/A * bounded by the appropriate padding bytes
4007N/A * @exception AEADBadTagException if this cipher is decrypting in an
4007N/A * AEAD mode (such as GCM/CCM), and the received authentication tag
4007N/A * does not match the calculated value
0N/A */
0N/A public final byte[] doFinal(byte[] input, int inputOffset, int inputLen)
0N/A throws IllegalBlockSizeException, BadPaddingException {
0N/A checkCipherState();
0N/A
0N/A // Input sanity check
0N/A if (input == null || inputOffset < 0
0N/A || inputLen > (input.length - inputOffset) || inputLen < 0) {
0N/A throw new IllegalArgumentException("Bad arguments");
0N/A }
0N/A
0N/A chooseFirstProvider();
0N/A return spi.engineDoFinal(input, inputOffset, inputLen);
0N/A }
0N/A
0N/A /**
0N/A * Encrypts or decrypts data in a single-part operation, or finishes a
0N/A * multiple-part operation. The data is encrypted or decrypted,
0N/A * depending on how this cipher was initialized.
0N/A *
0N/A * <p>The first <code>inputLen</code> bytes in the <code>input</code>
0N/A * buffer, starting at <code>inputOffset</code> inclusive, and any input
0N/A * bytes that may have been buffered during a previous <code>update</code>
0N/A * operation, are processed, with padding (if requested) being applied.
4007N/A * If an AEAD mode such as GCM/CCM is being used, the authentication
4007N/A * tag is appended in the case of encryption, or verified in the
4007N/A * case of decryption.
0N/A * The result is stored in the <code>output</code> buffer.
0N/A *
0N/A * <p>If the <code>output</code> buffer is too small to hold the result,
0N/A * a <code>ShortBufferException</code> is thrown. In this case, repeat this
0N/A * call with a larger output buffer. Use
0N/A * {@link #getOutputSize(int) getOutputSize} to determine how big
0N/A * the output buffer should be.
0N/A *
0N/A * <p>Upon finishing, this method resets this cipher object to the state
0N/A * it was in when previously initialized via a call to <code>init</code>.
0N/A * That is, the object is reset and available to encrypt or decrypt
0N/A * (depending on the operation mode that was specified in the call to
0N/A * <code>init</code>) more data.
0N/A *
0N/A * <p>Note: if any exception is thrown, this cipher object may need to
0N/A * be reset before it can be used again.
0N/A *
0N/A * <p>Note: this method should be copy-safe, which means the
0N/A * <code>input</code> and <code>output</code> buffers can reference
0N/A * the same byte array and no unprocessed input data is overwritten
0N/A * when the result is copied into the output buffer.
0N/A *
0N/A * @param input the input buffer
0N/A * @param inputOffset the offset in <code>input</code> where the input
0N/A * starts
0N/A * @param inputLen the input length
0N/A * @param output the buffer for the result
0N/A *
0N/A * @return the number of bytes stored in <code>output</code>
0N/A *
0N/A * @exception IllegalStateException if this cipher is in a wrong state
0N/A * (e.g., has not been initialized)
0N/A * @exception IllegalBlockSizeException if this cipher is a block cipher,
0N/A * no padding has been requested (only in encryption mode), and the total
0N/A * input length of the data processed by this cipher is not a multiple of
0N/A * block size; or if this encryption algorithm is unable to
0N/A * process the input data provided.
0N/A * @exception ShortBufferException if the given output buffer is too small
0N/A * to hold the result
0N/A * @exception BadPaddingException if this cipher is in decryption mode,
0N/A * and (un)padding has been requested, but the decrypted data is not
0N/A * bounded by the appropriate padding bytes
4007N/A * @exception AEADBadTagException if this cipher is decrypting in an
4007N/A * AEAD mode (such as GCM/CCM), and the received authentication tag
4007N/A * does not match the calculated value
0N/A */
0N/A public final int doFinal(byte[] input, int inputOffset, int inputLen,
0N/A byte[] output)
0N/A throws ShortBufferException, IllegalBlockSizeException,
0N/A BadPaddingException {
0N/A checkCipherState();
0N/A
0N/A // Input sanity check
0N/A if (input == null || inputOffset < 0
0N/A || inputLen > (input.length - inputOffset) || inputLen < 0) {
0N/A throw new IllegalArgumentException("Bad arguments");
0N/A }
0N/A
0N/A chooseFirstProvider();
0N/A return spi.engineDoFinal(input, inputOffset, inputLen,
0N/A output, 0);
0N/A }
0N/A
0N/A /**
0N/A * Encrypts or decrypts data in a single-part operation, or finishes a
0N/A * multiple-part operation. The data is encrypted or decrypted,
0N/A * depending on how this cipher was initialized.
0N/A *
0N/A * <p>The first <code>inputLen</code> bytes in the <code>input</code>
0N/A * buffer, starting at <code>inputOffset</code> inclusive, and any input
0N/A * bytes that may have been buffered during a previous
0N/A * <code>update</code> operation, are processed, with padding
0N/A * (if requested) being applied.
4007N/A * If an AEAD mode such as GCM/CCM is being used, the authentication
4007N/A * tag is appended in the case of encryption, or verified in the
4007N/A * case of decryption.
0N/A * The result is stored in the <code>output</code> buffer, starting at
0N/A * <code>outputOffset</code> inclusive.
0N/A *
0N/A * <p>If the <code>output</code> buffer is too small to hold the result,
0N/A * a <code>ShortBufferException</code> is thrown. In this case, repeat this
0N/A * call with a larger output buffer. Use
0N/A * {@link #getOutputSize(int) getOutputSize} to determine how big
0N/A * the output buffer should be.
0N/A *
0N/A * <p>Upon finishing, this method resets this cipher object to the state
0N/A * it was in when previously initialized via a call to <code>init</code>.
0N/A * That is, the object is reset and available to encrypt or decrypt
0N/A * (depending on the operation mode that was specified in the call to
0N/A * <code>init</code>) more data.
0N/A *
0N/A * <p>Note: if any exception is thrown, this cipher object may need to
0N/A * be reset before it can be used again.
0N/A *
0N/A * <p>Note: this method should be copy-safe, which means the
0N/A * <code>input</code> and <code>output</code> buffers can reference
0N/A * the same byte array and no unprocessed input data is overwritten
0N/A * when the result is copied into the output buffer.
0N/A *
0N/A * @param input the input buffer
0N/A * @param inputOffset the offset in <code>input</code> where the input
0N/A * starts
0N/A * @param inputLen the input length
0N/A * @param output the buffer for the result
0N/A * @param outputOffset the offset in <code>output</code> where the result
0N/A * is stored
0N/A *
0N/A * @return the number of bytes stored in <code>output</code>
0N/A *
0N/A * @exception IllegalStateException if this cipher is in a wrong state
0N/A * (e.g., has not been initialized)
0N/A * @exception IllegalBlockSizeException if this cipher is a block cipher,
0N/A * no padding has been requested (only in encryption mode), and the total
0N/A * input length of the data processed by this cipher is not a multiple of
0N/A * block size; or if this encryption algorithm is unable to
0N/A * process the input data provided.
0N/A * @exception ShortBufferException if the given output buffer is too small
0N/A * to hold the result
0N/A * @exception BadPaddingException if this cipher is in decryption mode,
0N/A * and (un)padding has been requested, but the decrypted data is not
0N/A * bounded by the appropriate padding bytes
4007N/A * @exception AEADBadTagException if this cipher is decrypting in an
4007N/A * AEAD mode (such as GCM/CCM), and the received authentication tag
4007N/A * does not match the calculated value
0N/A */
0N/A public final int doFinal(byte[] input, int inputOffset, int inputLen,
0N/A byte[] output, int outputOffset)
0N/A throws ShortBufferException, IllegalBlockSizeException,
0N/A BadPaddingException {
0N/A checkCipherState();
0N/A
0N/A // Input sanity check
0N/A if (input == null || inputOffset < 0
0N/A || inputLen > (input.length - inputOffset) || inputLen < 0
0N/A || outputOffset < 0) {
0N/A throw new IllegalArgumentException("Bad arguments");
0N/A }
0N/A
0N/A chooseFirstProvider();
0N/A return spi.engineDoFinal(input, inputOffset, inputLen,
0N/A output, outputOffset);
0N/A }
0N/A
0N/A /**
0N/A * Encrypts or decrypts data in a single-part operation, or finishes a
0N/A * multiple-part operation. The data is encrypted or decrypted,
0N/A * depending on how this cipher was initialized.
0N/A *
0N/A * <p>All <code>input.remaining()</code> bytes starting at
4007N/A * <code>input.position()</code> are processed.
4007N/A * If an AEAD mode such as GCM/CCM is being used, the authentication
4007N/A * tag is appended in the case of encryption, or verified in the
4007N/A * case of decryption.
4007N/A * The result is stored in the output buffer.
0N/A * Upon return, the input buffer's position will be equal
0N/A * to its limit; its limit will not have changed. The output buffer's
0N/A * position will have advanced by n, where n is the value returned
0N/A * by this method; the output buffer's limit will not have changed.
0N/A *
0N/A * <p>If <code>output.remaining()</code> bytes are insufficient to
0N/A * hold the result, a <code>ShortBufferException</code> is thrown.
0N/A * In this case, repeat this call with a larger output buffer. Use
0N/A * {@link #getOutputSize(int) getOutputSize} to determine how big
0N/A * the output buffer should be.
0N/A *
0N/A * <p>Upon finishing, this method resets this cipher object to the state
0N/A * it was in when previously initialized via a call to <code>init</code>.
0N/A * That is, the object is reset and available to encrypt or decrypt
0N/A * (depending on the operation mode that was specified in the call to
0N/A * <code>init</code>) more data.
0N/A *
0N/A * <p>Note: if any exception is thrown, this cipher object may need to
0N/A * be reset before it can be used again.
0N/A *
0N/A * <p>Note: this method should be copy-safe, which means the
0N/A * <code>input</code> and <code>output</code> buffers can reference
0N/A * the same byte array and no unprocessed input data is overwritten
0N/A * when the result is copied into the output buffer.
0N/A *
0N/A * @param input the input ByteBuffer
0N/A * @param output the output ByteBuffer
0N/A *
0N/A * @return the number of bytes stored in <code>output</code>
0N/A *
0N/A * @exception IllegalStateException if this cipher is in a wrong state
0N/A * (e.g., has not been initialized)
0N/A * @exception IllegalArgumentException if input and output are the
0N/A * same object
0N/A * @exception ReadOnlyBufferException if the output buffer is read-only
0N/A * @exception IllegalBlockSizeException if this cipher is a block cipher,
0N/A * no padding has been requested (only in encryption mode), and the total
0N/A * input length of the data processed by this cipher is not a multiple of
0N/A * block size; or if this encryption algorithm is unable to
0N/A * process the input data provided.
0N/A * @exception ShortBufferException if there is insufficient space in the
0N/A * output buffer
0N/A * @exception BadPaddingException if this cipher is in decryption mode,
0N/A * and (un)padding has been requested, but the decrypted data is not
0N/A * bounded by the appropriate padding bytes
4007N/A * @exception AEADBadTagException if this cipher is decrypting in an
4007N/A * AEAD mode (such as GCM/CCM), and the received authentication tag
4007N/A * does not match the calculated value
4007N/A *
0N/A * @since 1.5
0N/A */
0N/A public final int doFinal(ByteBuffer input, ByteBuffer output)
0N/A throws ShortBufferException, IllegalBlockSizeException,
0N/A BadPaddingException {
0N/A checkCipherState();
0N/A
0N/A if ((input == null) || (output == null)) {
0N/A throw new IllegalArgumentException("Buffers must not be null");
0N/A }
0N/A if (input == output) {
0N/A throw new IllegalArgumentException("Input and output buffers must "
0N/A + "not be the same object, consider using buffer.duplicate()");
0N/A }
0N/A if (output.isReadOnly()) {
0N/A throw new ReadOnlyBufferException();
0N/A }
0N/A
0N/A chooseFirstProvider();
0N/A return spi.engineDoFinal(input, output);
0N/A }
0N/A
0N/A /**
0N/A * Wrap a key.
0N/A *
0N/A * @param key the key to be wrapped.
0N/A *
0N/A * @return the wrapped key.
0N/A *
0N/A * @exception IllegalStateException if this cipher is in a wrong
0N/A * state (e.g., has not been initialized).
0N/A *
0N/A * @exception IllegalBlockSizeException if this cipher is a block
0N/A * cipher, no padding has been requested, and the length of the
0N/A * encoding of the key to be wrapped is not a
0N/A * multiple of the block size.
0N/A *
0N/A * @exception InvalidKeyException if it is impossible or unsafe to
0N/A * wrap the key with this cipher (e.g., a hardware protected key is
0N/A * being passed to a software-only cipher).
0N/A */
0N/A public final byte[] wrap(Key key)
0N/A throws IllegalBlockSizeException, InvalidKeyException {
0N/A if (!(this instanceof NullCipher)) {
0N/A if (!initialized) {
0N/A throw new IllegalStateException("Cipher not initialized");
0N/A }
0N/A if (opmode != Cipher.WRAP_MODE) {
0N/A throw new IllegalStateException("Cipher not initialized " +
0N/A "for wrapping keys");
0N/A }
0N/A }
0N/A
0N/A chooseFirstProvider();
0N/A return spi.engineWrap(key);
0N/A }
0N/A
0N/A /**
0N/A * Unwrap a previously wrapped key.
0N/A *
0N/A * @param wrappedKey the key to be unwrapped.
0N/A *
0N/A * @param wrappedKeyAlgorithm the algorithm associated with the wrapped
0N/A * key.
0N/A *
0N/A * @param wrappedKeyType the type of the wrapped key. This must be one of
0N/A * <code>SECRET_KEY</code>, <code>PRIVATE_KEY</code>, or
0N/A * <code>PUBLIC_KEY</code>.
0N/A *
0N/A * @return the unwrapped key.
0N/A *
0N/A * @exception IllegalStateException if this cipher is in a wrong state
0N/A * (e.g., has not been initialized).
0N/A *
0N/A * @exception NoSuchAlgorithmException if no installed providers
0N/A * can create keys of type <code>wrappedKeyType</code> for the
0N/A * <code>wrappedKeyAlgorithm</code>.
0N/A *
0N/A * @exception InvalidKeyException if <code>wrappedKey</code> does not
0N/A * represent a wrapped key of type <code>wrappedKeyType</code> for
0N/A * the <code>wrappedKeyAlgorithm</code>.
0N/A */
0N/A public final Key unwrap(byte[] wrappedKey,
0N/A String wrappedKeyAlgorithm,
0N/A int wrappedKeyType)
0N/A throws InvalidKeyException, NoSuchAlgorithmException {
0N/A
0N/A if (!(this instanceof NullCipher)) {
0N/A if (!initialized) {
0N/A throw new IllegalStateException("Cipher not initialized");
0N/A }
0N/A if (opmode != Cipher.UNWRAP_MODE) {
0N/A throw new IllegalStateException("Cipher not initialized " +
0N/A "for unwrapping keys");
0N/A }
0N/A }
0N/A if ((wrappedKeyType != SECRET_KEY) &&
0N/A (wrappedKeyType != PRIVATE_KEY) &&
0N/A (wrappedKeyType != PUBLIC_KEY)) {
0N/A throw new InvalidParameterException("Invalid key type");
0N/A }
0N/A
0N/A chooseFirstProvider();
0N/A return spi.engineUnwrap(wrappedKey,
0N/A wrappedKeyAlgorithm,
0N/A wrappedKeyType);
0N/A }
0N/A
0N/A private AlgorithmParameterSpec getAlgorithmParameterSpec(
0N/A AlgorithmParameters params)
0N/A throws InvalidParameterSpecException {
0N/A if (params == null) {
0N/A return null;
0N/A }
0N/A
0N/A String alg = params.getAlgorithm().toUpperCase(Locale.ENGLISH);
0N/A
0N/A if (alg.equalsIgnoreCase("RC2")) {
0N/A return params.getParameterSpec(RC2ParameterSpec.class);
0N/A }
0N/A
0N/A if (alg.equalsIgnoreCase("RC5")) {
0N/A return params.getParameterSpec(RC5ParameterSpec.class);
0N/A }
0N/A
0N/A if (alg.startsWith("PBE")) {
0N/A return params.getParameterSpec(PBEParameterSpec.class);
0N/A }
0N/A
0N/A if (alg.startsWith("DES")) {
0N/A return params.getParameterSpec(IvParameterSpec.class);
0N/A }
0N/A return null;
0N/A }
0N/A
0N/A private static CryptoPermission getConfiguredPermission(
0N/A String transformation) throws NullPointerException,
0N/A NoSuchAlgorithmException {
0N/A if (transformation == null) throw new NullPointerException();
0N/A String[] parts = tokenizeTransformation(transformation);
0N/A return JceSecurityManager.INSTANCE.getCryptoPermission(parts[0]);
0N/A }
0N/A
0N/A /**
0N/A * Returns the maximum key length for the specified transformation
0N/A * according to the installed JCE jurisdiction policy files. If
0N/A * JCE unlimited strength jurisdiction policy files are installed,
0N/A * Integer.MAX_VALUE will be returned.
0N/A * For more information on default key size in JCE jurisdiction
0N/A * policy files, please see Appendix E in the
0N/A * <a href=
728N/A * "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppC">
0N/A * Java Cryptography Architecture Reference Guide</a>.
0N/A *
0N/A * @param transformation the cipher transformation.
0N/A * @return the maximum key length in bits or Integer.MAX_VALUE.
0N/A * @exception NullPointerException if <code>transformation</code> is null.
0N/A * @exception NoSuchAlgorithmException if <code>transformation</code>
0N/A * is not a valid transformation, i.e. in the form of "algorithm" or
0N/A * "algorithm/mode/padding".
0N/A * @since 1.5
0N/A */
0N/A public static final int getMaxAllowedKeyLength(String transformation)
0N/A throws NoSuchAlgorithmException {
0N/A CryptoPermission cp = getConfiguredPermission(transformation);
0N/A return cp.getMaxKeySize();
0N/A }
0N/A
0N/A /**
0N/A * Returns an AlgorithmParameterSpec object which contains
0N/A * the maximum cipher parameter value according to the
0N/A * jurisdiction policy file. If JCE unlimited strength jurisdiction
0N/A * policy files are installed or there is no maximum limit on the
0N/A * parameters for the specified transformation in the policy file,
0N/A * null will be returned.
0N/A *
0N/A * @param transformation the cipher transformation.
0N/A * @return an AlgorithmParameterSpec which holds the maximum
0N/A * value or null.
0N/A * @exception NullPointerException if <code>transformation</code>
0N/A * is null.
0N/A * @exception NoSuchAlgorithmException if <code>transformation</code>
0N/A * is not a valid transformation, i.e. in the form of "algorithm" or
0N/A * "algorithm/mode/padding".
0N/A * @since 1.5
0N/A */
0N/A public static final AlgorithmParameterSpec getMaxAllowedParameterSpec(
0N/A String transformation) throws NoSuchAlgorithmException {
0N/A CryptoPermission cp = getConfiguredPermission(transformation);
0N/A return cp.getAlgorithmParameterSpec();
0N/A }
4007N/A
4007N/A /**
4007N/A * Continues a multi-part update of the Additional Authentication
4007N/A * Data (AAD).
4007N/A * <p>
4007N/A * Calls to this method provide AAD to the cipher when operating in
4007N/A * modes such as AEAD (GCM/CCM). If this cipher is operating in
4007N/A * either GCM or CCM mode, all AAD must be supplied before beginning
4007N/A * operations on the ciphertext (via the {@code update} and {@code
4007N/A * doFinal} methods).
4007N/A *
4007N/A * @param src the buffer containing the Additional Authentication Data
4007N/A *
4007N/A * @throws IllegalArgumentException if the {@code src}
4007N/A * byte array is null
4007N/A * @throws IllegalStateException if this cipher is in a wrong state
4007N/A * (e.g., has not been initialized), does not accept AAD, or if
4007N/A * operating in either GCM or CCM mode and one of the {@code update}
4007N/A * methods has already been called for the active
4007N/A * encryption/decryption operation
4007N/A * @throws UnsupportedOperationException if the corresponding method
4007N/A * in the {@code CipherSpi} has not been overridden by an
4007N/A * implementation
4007N/A *
4007N/A * @since 1.7
4007N/A */
4007N/A public final void updateAAD(byte[] src) {
4007N/A if (src == null) {
4007N/A throw new IllegalArgumentException("src buffer is null");
4007N/A }
4007N/A
4007N/A updateAAD(src, 0, src.length);
4007N/A }
4007N/A
4007N/A /**
4007N/A * Continues a multi-part update of the Additional Authentication
4007N/A * Data (AAD), using a subset of the provided buffer.
4007N/A * <p>
4007N/A * Calls to this method provide AAD to the cipher when operating in
4007N/A * modes such as AEAD (GCM/CCM). If this cipher is operating in
4007N/A * either GCM or CCM mode, all AAD must be supplied before beginning
4007N/A * operations on the ciphertext (via the {@code update} and {@code
4007N/A * doFinal} methods).
4007N/A *
4007N/A * @param src the buffer containing the AAD
4007N/A * @param offset the offset in {@code src} where the AAD input starts
4007N/A * @param len the number of AAD bytes
4007N/A *
4007N/A * @throws IllegalArgumentException if the {@code src}
4007N/A * byte array is null, or the {@code offset} or {@code length}
4007N/A * is less than 0, or the sum of the {@code offset} and
4007N/A * {@code len} is greater than the length of the
4007N/A * {@code src} byte array
4007N/A * @throws IllegalStateException if this cipher is in a wrong state
4007N/A * (e.g., has not been initialized), does not accept AAD, or if
4007N/A * operating in either GCM or CCM mode and one of the {@code update}
4007N/A * methods has already been called for the active
4007N/A * encryption/decryption operation
4007N/A * @throws UnsupportedOperationException if the corresponding method
4007N/A * in the {@code CipherSpi} has not been overridden by an
4007N/A * implementation
4007N/A *
4007N/A * @since 1.7
4007N/A */
4007N/A public final void updateAAD(byte[] src, int offset, int len) {
4007N/A checkCipherState();
4007N/A
4007N/A // Input sanity check
4007N/A if ((src == null) || (offset < 0) || (len < 0)
4007N/A || ((len + offset) > src.length)) {
4007N/A throw new IllegalArgumentException("Bad arguments");
4007N/A }
4007N/A
4007N/A chooseFirstProvider();
4007N/A if (len == 0) {
4007N/A return;
4007N/A }
4007N/A spi.engineUpdateAAD(src, offset, len);
4007N/A }
4007N/A
4007N/A /**
4007N/A * Continues a multi-part update of the Additional Authentication
4007N/A * Data (AAD).
4007N/A * <p>
4007N/A * Calls to this method provide AAD to the cipher when operating in
4007N/A * modes such as AEAD (GCM/CCM). If this cipher is operating in
4007N/A * either GCM or CCM mode, all AAD must be supplied before beginning
4007N/A * operations on the ciphertext (via the {@code update} and {@code
4007N/A * doFinal} methods).
4007N/A * <p>
4007N/A * All {@code src.remaining()} bytes starting at
4007N/A * {@code src.position()} are processed.
4007N/A * Upon return, the input buffer's position will be equal
4007N/A * to its limit; its limit will not have changed.
4007N/A *
4007N/A * @param src the buffer containing the AAD
4007N/A *
4007N/A * @throws IllegalArgumentException if the {@code src ByteBuffer}
4007N/A * is null
4007N/A * @throws IllegalStateException if this cipher is in a wrong state
4007N/A * (e.g., has not been initialized), does not accept AAD, or if
4007N/A * operating in either GCM or CCM mode and one of the {@code update}
4007N/A * methods has already been called for the active
4007N/A * encryption/decryption operation
4007N/A * @throws UnsupportedOperationException if the corresponding method
4007N/A * in the {@code CipherSpi} has not been overridden by an
4007N/A * implementation
4007N/A *
4007N/A * @since 1.7
4007N/A */
4007N/A public final void updateAAD(ByteBuffer src) {
4007N/A checkCipherState();
4007N/A
4007N/A // Input sanity check
4007N/A if (src == null) {
4007N/A throw new IllegalArgumentException("src ByteBuffer is null");
4007N/A }
4007N/A
4007N/A chooseFirstProvider();
4007N/A if (src.remaining() == 0) {
4007N/A return;
4007N/A }
4007N/A spi.engineUpdateAAD(src);
4007N/A }
0N/A}