Automatic sources dropoff on 2020-06-10 18:32:38.095721
The change is generated with prebuilt drop tool.
Change-Id: I24cbf6ba6db262a1ae1445db1427a08fee35b3b4
diff --git a/javax/crypto/AEADBadTagException.java b/javax/crypto/AEADBadTagException.java
new file mode 100644
index 0000000..8587fcf
--- /dev/null
+++ b/javax/crypto/AEADBadTagException.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.crypto;
+
+/**
+ * This exception is thrown when a {@link Cipher} operating in
+ * an AEAD mode (such as GCM/CCM) is unable to verify the supplied
+ * authentication tag.
+ *
+ * @since 1.7
+ */
+public class AEADBadTagException extends BadPaddingException {
+
+ private static final long serialVersionUID = -488059093241685509L;
+
+ /**
+ * Constructs a AEADBadTagException with no detail message.
+ */
+ public AEADBadTagException() {
+ super();
+ }
+
+ /**
+ * Constructs a AEADBadTagException with the specified
+ * detail message.
+ *
+ * @param msg the detail message.
+ */
+ public AEADBadTagException(String msg) {
+ super(msg);
+ }
+}
diff --git a/javax/crypto/BadPaddingException.java b/javax/crypto/BadPaddingException.java
new file mode 100644
index 0000000..cc6455f
--- /dev/null
+++ b/javax/crypto/BadPaddingException.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.crypto;
+
+import java.security.GeneralSecurityException;
+
+/**
+ * This exception is thrown when a particular padding mechanism is
+ * expected for the input data but the data is not padded properly.
+ *
+ * @author Gigi Ankney
+ * @since 1.4
+ */
+
+public class BadPaddingException extends GeneralSecurityException {
+
+ private static final long serialVersionUID = -5315033893984728443L;
+
+ /**
+ * Constructs a BadPaddingException with no detail
+ * message. A detail message is a String that describes this
+ * particular exception.
+ */
+ public BadPaddingException() {
+ super();
+ }
+
+ /**
+ * Constructs a BadPaddingException with the specified
+ * detail message.
+ *
+ * @param msg the detail message.
+ */
+ public BadPaddingException(String msg) {
+ super(msg);
+ }
+}
diff --git a/javax/crypto/Cipher.annotated.java b/javax/crypto/Cipher.annotated.java
new file mode 100644
index 0000000..bafd946
--- /dev/null
+++ b/javax/crypto/Cipher.annotated.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package javax.crypto;
+
+import java.util.*;
+import java.util.regex.*;
+import java.security.*;
+import javax.crypto.spec.*;
+import sun.security.jca.*;
+import java.nio.ReadOnlyBufferException;
+import java.nio.ByteBuffer;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.Provider.Service;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class Cipher {
+
+protected Cipher(javax.crypto.CipherSpi cipherSpi, java.security.Provider provider, java.lang.String transformation) { throw new RuntimeException("Stub!"); }
+
+public static final javax.crypto.Cipher getInstance(java.lang.String transformation) throws java.security.NoSuchAlgorithmException, javax.crypto.NoSuchPaddingException { throw new RuntimeException("Stub!"); }
+
+public static final javax.crypto.Cipher getInstance(java.lang.String transformation, java.lang.String provider) throws java.security.NoSuchAlgorithmException, javax.crypto.NoSuchPaddingException, java.security.NoSuchProviderException { throw new RuntimeException("Stub!"); }
+
+public static final javax.crypto.Cipher getInstance(java.lang.String transformation, java.security.Provider provider) throws java.security.NoSuchAlgorithmException, javax.crypto.NoSuchPaddingException { throw new RuntimeException("Stub!"); }
+
+public final java.security.Provider getProvider() { throw new RuntimeException("Stub!"); }
+
+public final java.lang.String getAlgorithm() { throw new RuntimeException("Stub!"); }
+
+public final int getBlockSize() { throw new RuntimeException("Stub!"); }
+
+public final int getOutputSize(int inputLen) { throw new RuntimeException("Stub!"); }
+
+public final byte[] getIV() { throw new RuntimeException("Stub!"); }
+
+public final java.security.AlgorithmParameters getParameters() { throw new RuntimeException("Stub!"); }
+
+public final javax.crypto.ExemptionMechanism getExemptionMechanism() { throw new RuntimeException("Stub!"); }
+
+public final void init(int opmode, java.security.Key key) throws java.security.InvalidKeyException { throw new RuntimeException("Stub!"); }
+
+public final void init(int opmode, java.security.Key key, java.security.SecureRandom random) throws java.security.InvalidKeyException { throw new RuntimeException("Stub!"); }
+
+public final void init(int opmode, java.security.Key key, java.security.spec.AlgorithmParameterSpec params) throws java.security.InvalidAlgorithmParameterException, java.security.InvalidKeyException { throw new RuntimeException("Stub!"); }
+
+public final void init(int opmode, java.security.Key key, java.security.spec.AlgorithmParameterSpec params, java.security.SecureRandom random) throws java.security.InvalidAlgorithmParameterException, java.security.InvalidKeyException { throw new RuntimeException("Stub!"); }
+
+public final void init(int opmode, java.security.Key key, java.security.AlgorithmParameters params) throws java.security.InvalidAlgorithmParameterException, java.security.InvalidKeyException { throw new RuntimeException("Stub!"); }
+
+public final void init(int opmode, java.security.Key key, java.security.AlgorithmParameters params, java.security.SecureRandom random) throws java.security.InvalidAlgorithmParameterException, java.security.InvalidKeyException { throw new RuntimeException("Stub!"); }
+
+public final void init(int opmode, java.security.cert.Certificate certificate) throws java.security.InvalidKeyException { throw new RuntimeException("Stub!"); }
+
+public final void init(int opmode, java.security.cert.Certificate certificate, java.security.SecureRandom random) throws java.security.InvalidKeyException { throw new RuntimeException("Stub!"); }
+
+public final byte[] update(byte[] input) { throw new RuntimeException("Stub!"); }
+
+public final byte[] update(byte[] input, int inputOffset, int inputLen) { throw new RuntimeException("Stub!"); }
+
+public final int update(byte[] input, int inputOffset, int inputLen, byte[] output) throws javax.crypto.ShortBufferException { throw new RuntimeException("Stub!"); }
+
+public final int update(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws javax.crypto.ShortBufferException { throw new RuntimeException("Stub!"); }
+
+public final int update(java.nio.ByteBuffer input, java.nio.ByteBuffer output) throws javax.crypto.ShortBufferException { throw new RuntimeException("Stub!"); }
+
+public final byte[] doFinal() throws javax.crypto.BadPaddingException, javax.crypto.IllegalBlockSizeException { throw new RuntimeException("Stub!"); }
+
+public final int doFinal(byte[] output, int outputOffset) throws javax.crypto.BadPaddingException, javax.crypto.IllegalBlockSizeException, javax.crypto.ShortBufferException { throw new RuntimeException("Stub!"); }
+
+public final byte[] doFinal(byte[] input) throws javax.crypto.BadPaddingException, javax.crypto.IllegalBlockSizeException { throw new RuntimeException("Stub!"); }
+
+public final byte[] doFinal(byte[] input, int inputOffset, int inputLen) throws javax.crypto.BadPaddingException, javax.crypto.IllegalBlockSizeException { throw new RuntimeException("Stub!"); }
+
+public final int doFinal(byte[] input, int inputOffset, int inputLen, byte[] output) throws javax.crypto.BadPaddingException, javax.crypto.IllegalBlockSizeException, javax.crypto.ShortBufferException { throw new RuntimeException("Stub!"); }
+
+public final int doFinal(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws javax.crypto.BadPaddingException, javax.crypto.IllegalBlockSizeException, javax.crypto.ShortBufferException { throw new RuntimeException("Stub!"); }
+
+public final int doFinal(java.nio.ByteBuffer input, java.nio.ByteBuffer output) throws javax.crypto.BadPaddingException, javax.crypto.IllegalBlockSizeException, javax.crypto.ShortBufferException { throw new RuntimeException("Stub!"); }
+
+public final byte[] wrap(java.security.Key key) throws javax.crypto.IllegalBlockSizeException, java.security.InvalidKeyException { throw new RuntimeException("Stub!"); }
+
+public final java.security.Key unwrap(byte[] wrappedKey, java.lang.String wrappedKeyAlgorithm, int wrappedKeyType) throws java.security.InvalidKeyException, java.security.NoSuchAlgorithmException { throw new RuntimeException("Stub!"); }
+
+public static final int getMaxAllowedKeyLength(java.lang.String transformation) throws java.security.NoSuchAlgorithmException { throw new RuntimeException("Stub!"); }
+
+public static final java.security.spec.AlgorithmParameterSpec getMaxAllowedParameterSpec(java.lang.String transformation) throws java.security.NoSuchAlgorithmException { throw new RuntimeException("Stub!"); }
+
+public final void updateAAD(byte[] src) { throw new RuntimeException("Stub!"); }
+
+public final void updateAAD(byte[] src, int offset, int len) { throw new RuntimeException("Stub!"); }
+
+public final void updateAAD(java.nio.ByteBuffer src) { throw new RuntimeException("Stub!"); }
+
[email protected]
+public javax.crypto.CipherSpi getCurrentSpi() { throw new RuntimeException("Stub!"); }
+
+public static final int DECRYPT_MODE = 2; // 0x2
+
+public static final int ENCRYPT_MODE = 1; // 0x1
+
+public static final int PRIVATE_KEY = 2; // 0x2
+
+public static final int PUBLIC_KEY = 1; // 0x1
+
+public static final int SECRET_KEY = 3; // 0x3
+
+public static final int UNWRAP_MODE = 4; // 0x4
+
+public static final int WRAP_MODE = 3; // 0x3
+}
+
diff --git a/javax/crypto/Cipher.java b/javax/crypto/Cipher.java
new file mode 100644
index 0000000..7968f2f
--- /dev/null
+++ b/javax/crypto/Cipher.java
@@ -0,0 +1,2997 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.crypto;
+
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.regex.*;
+
+import static java.util.Locale.ENGLISH;
+
+import java.security.*;
+import java.security.Provider.Service;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+
+import javax.crypto.spec.*;
+
+import java.nio.ByteBuffer;
+import java.nio.ReadOnlyBufferException;
+import sun.security.jca.*;
+
+/**
+ * This class provides the functionality of a cryptographic cipher for
+ * encryption and decryption. It forms the core of the Java Cryptographic
+ * Extension (JCE) framework.
+ *
+ * <p>In order to create a Cipher object, the application calls the
+ * Cipher's <code>getInstance</code> method, and passes the name of the
+ * requested <i>transformation</i> to it. Optionally, the name of a provider
+ * may be specified.
+ *
+ * <p>A <i>transformation</i> is a string that describes the operation (or
+ * set of operations) to be performed on the given input, to produce some
+ * output. A transformation always includes the name of a cryptographic
+ * algorithm (e.g., <i>DES</i>), and may be followed by a feedback mode and
+ * padding scheme.
+ *
+ * <p> A transformation is of the form:
+ *
+ * <ul>
+ * <li>"<i>algorithm/mode/padding</i>" or
+ *
+ * <li>"<i>algorithm</i>"
+ * </ul>
+ *
+ * <P> (in the latter case,
+ * provider-specific default values for the mode and padding scheme are used).
+ * For example, the following is a valid transformation:
+ *
+ * <pre>
+ * Cipher c = Cipher.getInstance("<i>DES/CBC/PKCS5Padding</i>");
+ * </pre>
+ *
+ * Using modes such as <code>CFB</code> and <code>OFB</code>, block
+ * ciphers can encrypt data in units smaller than the cipher's actual
+ * block size. When requesting such a mode, you may optionally specify
+ * the number of bits to be processed at a time by appending this number
+ * to the mode name as shown in the "<code>DES/CFB8/NoPadding</code>" and
+ * "<code>DES/OFB32/PKCS5Padding</code>" transformations. If no such
+ * number is specified, a provider-specific default is used. (For
+ * example, the SunJCE provider uses a default of 64 bits for DES.)
+ * Thus, block ciphers can be turned into byte-oriented stream ciphers by
+ * using an 8 bit mode such as CFB8 or OFB8.
+ * <p>
+ * Modes such as Authenticated Encryption with Associated Data (AEAD)
+ * provide authenticity assurances for both confidential data and
+ * Additional Associated Data (AAD) that is not encrypted. (Please see
+ * <a href="http://www.ietf.org/rfc/rfc5116.txt"> RFC 5116 </a> for more
+ * information on AEAD and AEAD algorithms such as GCM/CCM.) Both
+ * confidential and AAD data can be used when calculating the
+ * authentication tag (similar to a {@link Mac}). This tag is appended
+ * to the ciphertext during encryption, and is verified on decryption.
+ * <p>
+ * AEAD modes such as GCM/CCM perform all AAD authenticity calculations
+ * before starting the ciphertext authenticity calculations. To avoid
+ * implementations having to internally buffer ciphertext, all AAD data
+ * must be supplied to GCM/CCM implementations (via the {@code
+ * updateAAD} methods) <b>before</b> the ciphertext is processed (via
+ * the {@code update} and {@code doFinal} methods).
+ * <p>
+ * Note that GCM mode has a uniqueness requirement on IVs used in
+ * encryption with a given key. When IVs are repeated for GCM
+ * encryption, such usages are subject to forgery attacks. Thus, after
+ * each encryption operation using GCM mode, callers should re-initialize
+ * the cipher objects with GCM parameters which has a different IV value.
+ * <pre>
+ * GCMParameterSpec s = ...;
+ * cipher.init(..., s);
+ *
+ * // If the GCM parameters were generated by the provider, it can
+ * // be retrieved by:
+ * // cipher.getParameters().getParameterSpec(GCMParameterSpec.class);
+ *
+ * cipher.updateAAD(...); // AAD
+ * cipher.update(...); // Multi-part update
+ * cipher.doFinal(...); // conclusion of operation
+ *
+ * // Use a different IV value for every encryption
+ * byte[] newIv = ...;
+ * s = new GCMParameterSpec(s.getTLen(), newIv);
+ * cipher.init(..., s);
+ * ...
+ *
+ * </pre>
+ * <p> Android provides the following <code>Cipher</code> transformations:
+ * <table>
+ * <thead>
+ * <tr>
+ * <th>Algorithm</th>
+ * <th>Modes</th>
+ * <th>Paddings</th>
+ * <th>Supported API Levels</th>
+ * <th>Notes</th>
+ * </tr>
+ * </thead>
+ * <tbody>
+ * <tr>
+ * <td rowspan="2"><span style="white-space: nowrap">AES</span></td>
+ * <td><span style="white-space: nowrap">CBC</span><br><span style="white-space: nowrap">CFB</span><br><span style="white-space: nowrap">CTR</span><br><span style="white-space: nowrap">CTS</span><br><span style="white-space: nowrap">ECB</span><br><span style="white-space: nowrap">OFB</span></td>
+ * <td><span style="white-space: nowrap">ISO10126Padding</span><br><span style="white-space: nowrap">NoPadding</span><br><span style="white-space: nowrap">PKCS5Padding</span></td>
+ * <td><span style="white-space: nowrap">1+</span></td>
+ * <td></td>
+ * </tr>
+ * <tr>
+ * <td><span style="white-space: nowrap">GCM</span></td>
+ * <td><span style="white-space: nowrap">NoPadding</span></td>
+ * <td><span style="white-space: nowrap">10+</span></td>
+ * <td></td>
+ * </tr>
+ * <tr>
+ * <td rowspan="2"><span style="white-space: nowrap">AES_128</span></td>
+ * <td><span style="white-space: nowrap">CBC</span><br><span style="white-space: nowrap">ECB</span></td>
+ * <td><span style="white-space: nowrap">NoPadding</span><br><span style="white-space: nowrap">PKCS5Padding</span></td>
+ * <td><span style="white-space: nowrap">26+</span></td>
+ * <td></td>
+ * </tr>
+ * <tr>
+ * <td><span style="white-space: nowrap">GCM</span></td>
+ * <td><span style="white-space: nowrap">NoPadding</span></td>
+ * <td><span style="white-space: nowrap">26+</span></td>
+ * <td></td>
+ * </tr>
+ * <tr>
+ * <td rowspan="2"><span style="white-space: nowrap">AES_256</span></td>
+ * <td><span style="white-space: nowrap">CBC</span><br><span style="white-space: nowrap">ECB</span></td>
+ * <td><span style="white-space: nowrap">NoPadding</span><br><span style="white-space: nowrap">PKCS5Padding</span></td>
+ * <td><span style="white-space: nowrap">26+</span></td>
+ * <td></td>
+ * </tr>
+ * <tr>
+ * <td><span style="white-space: nowrap">GCM</span></td>
+ * <td><span style="white-space: nowrap">NoPadding</span></td>
+ * <td><span style="white-space: nowrap">26+</span></td>
+ * <td></td>
+ * </tr>
+ * <tr>
+ * <td rowspan="2"><span style="white-space: nowrap">ARC4</span></td>
+ * <td><span style="white-space: nowrap">ECB</span></td>
+ * <td><span style="white-space: nowrap">NoPadding</span></td>
+ * <td><span style="white-space: nowrap">10+</span></td>
+ * <td></td>
+ * </tr>
+ * <tr>
+ * <td><span style="white-space: nowrap">NONE</span></td>
+ * <td><span style="white-space: nowrap">NoPadding</span></td>
+ * <td><span style="white-space: nowrap">28+</span></td>
+ * <td></td>
+ * </tr>
+ * <tr>
+ * <td><span style="white-space: nowrap">BLOWFISH</span></td>
+ * <td><span style="white-space: nowrap">CBC</span><br><span style="white-space: nowrap">CFB</span><br><span style="white-space: nowrap">CTR</span><br><span style="white-space: nowrap">CTS</span><br><span style="white-space: nowrap">ECB</span><br><span style="white-space: nowrap">OFB</span></td>
+ * <td><span style="white-space: nowrap">ISO10126Padding</span><br><span style="white-space: nowrap">NoPadding</span><br><span style="white-space: nowrap">PKCS5Padding</span></td>
+ * <td><span style="white-space: nowrap">10+</span></td>
+ * <td></td>
+ * </tr>
+ * <tr>
+ * <td><span style="white-space: nowrap">ChaCha20</span></td>
+ * <td><span style="white-space: nowrap">NONE</span><br><span style="white-space: nowrap">Poly1305</span></td>
+ * <td><span style="white-space: nowrap">NoPadding</span></td>
+ * <td><span style="white-space: nowrap">28+</span></td>
+ * <td>ChaCha with 20 rounds, 96-bit nonce, and 32-bit counter as described in RFC 7539.</td>
+ * </tr>
+ * <tr>
+ * <td><span style="white-space: nowrap">DES</span></td>
+ * <td><span style="white-space: nowrap">CBC</span><br><span style="white-space: nowrap">CFB</span><br><span style="white-space: nowrap">CTR</span><br><span style="white-space: nowrap">CTS</span><br><span style="white-space: nowrap">ECB</span><br><span style="white-space: nowrap">OFB</span></td>
+ * <td><span style="white-space: nowrap">ISO10126Padding</span><br><span style="white-space: nowrap">NoPadding</span><br><span style="white-space: nowrap">PKCS5Padding</span></td>
+ * <td><span style="white-space: nowrap">1+</span></td>
+ * <td></td>
+ * </tr>
+ * <tr>
+ * <td><span style="white-space: nowrap">DESede</span></td>
+ * <td><span style="white-space: nowrap">CBC</span><br><span style="white-space: nowrap">CFB</span><br><span style="white-space: nowrap">CTR</span><br><span style="white-space: nowrap">CTS</span><br><span style="white-space: nowrap">ECB</span><br><span style="white-space: nowrap">OFB</span></td>
+ * <td><span style="white-space: nowrap">ISO10126Padding</span><br><span style="white-space: nowrap">NoPadding</span><br><span style="white-space: nowrap">PKCS5Padding</span></td>
+ * <td><span style="white-space: nowrap">1+</span></td>
+ * <td></td>
+ * </tr>
+ * <tr>
+ * <td rowspan="3"><span style="white-space: nowrap">RSA</span></td>
+ * <td rowspan="3"><span style="white-space: nowrap">ECB</span><br><span style="white-space: nowrap">NONE</span></td>
+ * <td><span style="white-space: nowrap">NoPadding</span><br><span style="white-space: nowrap">OAEPPadding</span><br><span style="white-space: nowrap">PKCS1Padding</span></td>
+ * <td><span style="white-space: nowrap">1+</span></td>
+ * <td></td>
+ * </tr>
+ * <tr>
+ * <td><span style="white-space: nowrap">OAEPwithSHA-1andMGF1Padding</span><br><span style="white-space: nowrap">OAEPwithSHA-256andMGF1Padding</span></td>
+ * <td><span style="white-space: nowrap">10+</span></td>
+ * <td></td>
+ * </tr>
+ * <tr>
+ * <td><span style="white-space: nowrap">OAEPwithSHA-224andMGF1Padding</span><br><span style="white-space: nowrap">OAEPwithSHA-384andMGF1Padding</span><br><span style="white-space: nowrap">OAEPwithSHA-512andMGF1Padding</span></td>
+ * <td><span style="white-space: nowrap">23+</span></td>
+ * <td></td>
+ * </tr>
+ * </tbody>
+ * </table>
+ *
+ * These transformations are described in the
+ * <a href="{@docRoot}/../technotes/guides/security/StandardNames.html#Cipher">
+ * Cipher section</a> of the
+ * Java Cryptography Architecture Standard Algorithm Name Documentation.
+ *
+ * @author Jan Luehe
+ * @see KeyGenerator
+ * @see SecretKey
+ * @since 1.4
+ */
+
+public class Cipher {
+
+ // Android-note: Android reimplements provider selection.
+ //
+ // Android uses different provider/impl selection code than upstream does. Provider
+ // selection permeates much of this class, so this class is forked significantly
+ // from the upstream version. Not every change is marked, and any changes to upstream code
+ // should be evaluated to see if they should be merged.
+ //
+ // The changes are chiefly in construction (constructors, getInstance, and createCipher) and
+ // initialization (init and chooseProvider). Most of the actual implementation is in the
+ // classes and methods at the bottom of this file.
+
+
+ // Android-removed: this debugging mechanism is not used in Android.
+ /*
+ private static final Debug debug =
+ Debug.getInstance("jca", "Cipher");
+
+ private static final Debug pdebug =
+ Debug.getInstance("provider", "Provider");
+ private static final boolean skipDebug =
+ Debug.isOn("engine=") && !Debug.isOn("cipher");
+ */
+
+ /**
+ * Constant used to initialize cipher to encryption mode.
+ */
+ public static final int ENCRYPT_MODE = 1;
+
+ /**
+ * Constant used to initialize cipher to decryption mode.
+ */
+ public static final int DECRYPT_MODE = 2;
+
+ /**
+ * Constant used to initialize cipher to key-wrapping mode.
+ */
+ public static final int WRAP_MODE = 3;
+
+ /**
+ * Constant used to initialize cipher to key-unwrapping mode.
+ */
+ public static final int UNWRAP_MODE = 4;
+
+ /**
+ * Constant used to indicate the to-be-unwrapped key is a "public key".
+ */
+ public static final int PUBLIC_KEY = 1;
+
+ /**
+ * Constant used to indicate the to-be-unwrapped key is a "private key".
+ */
+ public static final int PRIVATE_KEY = 2;
+
+ /**
+ * Constant used to indicate the to-be-unwrapped key is a "secret key".
+ */
+ public static final int SECRET_KEY = 3;
+
+ // The provider
+ private Provider provider;
+
+ // The provider implementation (delegate)
+ private CipherSpi spi;
+
+ // The transformation
+ // Android-changed: Made final.
+ final private String transformation;
+
+ // Android-added: Added tokenizedTransformation.
+ // The tokenized version of transformation
+ final private String[] tokenizedTransformation;
+
+ // Android-removed: Removed cryptoPerm.
+ /*
+ // Crypto permission representing the maximum allowable cryptographic
+ // strength that this Cipher object can be used for. (The cryptographic
+ // strength is a function of the keysize and algorithm parameters encoded
+ // in the crypto permission.)
+ private CryptoPermission cryptoPerm;
+ */
+
+ // The exemption mechanism that needs to be enforced
+ private ExemptionMechanism exmech;
+
+ // Flag which indicates whether or not this cipher has been initialized
+ private boolean initialized = false;
+
+ // The operation mode - store the operation mode after the
+ // cipher has been initialized.
+ private int opmode = 0;
+
+ // The OID for the KeyUsage extension in an X.509 v3 certificate
+ private static final String KEY_USAGE_EXTENSION_OID = "2.5.29.15";
+
+ // BEGIN Android-changed: Reimplement provider selection.
+ // See note at top of class.
+ private final SpiAndProviderUpdater spiAndProviderUpdater;
+ /*
+ // next SPI to try in provider selection
+ // null once provider is selected
+ private CipherSpi firstSpi;
+
+ // next service to try in provider selection
+ // null once provider is selected
+ private Service firstService;
+
+ // remaining services to try in provider selection
+ // null once provider is selected
+ private Iterator<Service> serviceIterator;
+
+ // list of transform Strings to lookup in the provider
+ private List<Transform> transforms;
+
+ private final Object lock;
+ */
+ // END Android-changed: Reimplement provider selection.
+
+ /**
+ * Creates a Cipher object.
+ *
+ * @param cipherSpi the delegate
+ * @param provider the provider
+ * @param transformation the transformation
+ */
+ protected Cipher(CipherSpi cipherSpi,
+ Provider provider,
+ String transformation) {
+ if (cipherSpi == null) {
+ throw new NullPointerException("cipherSpi == null");
+ }
+ if (!(cipherSpi instanceof NullCipherSpi) && provider == null) {
+ throw new NullPointerException("provider == null");
+ }
+
+ this.spi = cipherSpi;
+ this.provider = provider;
+ this.transformation = transformation;
+ this.tokenizedTransformation = null;
+
+ this.spiAndProviderUpdater =
+ new SpiAndProviderUpdater(provider, cipherSpi);
+ }
+
+ private Cipher(CipherSpi cipherSpi,
+ Provider provider,
+ String transformation,
+ String[] tokenizedTransformation) {
+ this.spi = cipherSpi;
+ this.provider = provider;
+ this.transformation = transformation;
+ this.tokenizedTransformation = tokenizedTransformation;
+
+ this.spiAndProviderUpdater =
+ new SpiAndProviderUpdater(provider, cipherSpi);
+ }
+
+ private static String[] tokenizeTransformation(String transformation)
+ throws NoSuchAlgorithmException {
+ if (transformation == null || transformation.isEmpty()) {
+ throw new NoSuchAlgorithmException("No transformation given");
+ }
+ /*
+ * array containing the components of a Cipher transformation:
+ *
+ * index 0: algorithm component (e.g., DES)
+ * index 1: feedback component (e.g., CFB)
+ * index 2: padding component (e.g., PKCS5Padding)
+ */
+ String[] parts = new String[3];
+ int count = 0;
+ StringTokenizer parser = new StringTokenizer(transformation, "/");
+ try {
+ while (parser.hasMoreTokens() && count < 3) {
+ parts[count++] = parser.nextToken().trim();
+ }
+ if (count == 0 || count == 2 || parser.hasMoreTokens()) {
+ throw new NoSuchAlgorithmException("Invalid transformation"
+ + " format:" +
+ transformation);
+ }
+ } catch (NoSuchElementException e) {
+ throw new NoSuchAlgorithmException("Invalid transformation " +
+ "format:" + transformation);
+ }
+ if ((parts[0] == null) || (parts[0].length() == 0)) {
+ throw new NoSuchAlgorithmException("Invalid transformation:" +
+ "algorithm not specified-"
+ + transformation);
+ }
+ return parts;
+ }
+
+ // BEGIN Android-removed: Reimplement provider selection.
+ // See note at top of class.
+ /*
+ // Provider attribute name for supported chaining mode
+ private final static String ATTR_MODE = "SupportedModes";
+ // Provider attribute name for supported padding names
+ private final static String ATTR_PAD = "SupportedPaddings";
+
+ // constants indicating whether the provider supports
+ // a given mode or padding
+ private final static int S_NO = 0; // does not support
+ private final static int S_MAYBE = 1; // unable to determine
+ private final static int S_YES = 2; // does support
+
+ /**
+ * Nested class to deal with modes and paddings.
+ *
+ private static class Transform {
+ // transform string to lookup in the provider
+ final String transform;
+ // the mode/padding suffix in upper case. for example, if the algorithm
+ // to lookup is "DES/CBC/PKCS5Padding" suffix is "/CBC/PKCS5PADDING"
+ // if loopup is "DES", suffix is the empty string
+ // needed because aliases prevent straight transform.equals()
+ final String suffix;
+ // value to pass to setMode() or null if no such call required
+ final String mode;
+ // value to pass to setPadding() or null if no such call required
+ final String pad;
+ Transform(String alg, String suffix, String mode, String pad) {
+ this.transform = alg + suffix;
+ this.suffix = suffix.toUpperCase(Locale.ENGLISH);
+ this.mode = mode;
+ this.pad = pad;
+ }
+ // set mode and padding for the given SPI
+ void setModePadding(CipherSpi spi) throws NoSuchAlgorithmException,
+ NoSuchPaddingException {
+ if (mode != null) {
+ spi.engineSetMode(mode);
+ }
+ if (pad != null) {
+ spi.engineSetPadding(pad);
+ }
+ }
+ // check whether the given services supports the mode and
+ // padding described by this Transform
+ int supportsModePadding(Service s) {
+ int smode = supportsMode(s);
+ if (smode == S_NO) {
+ return smode;
+ }
+ int spad = supportsPadding(s);
+ // our constants are defined so that Math.min() is a tri-valued AND
+ return Math.min(smode, spad);
+ }
+
+ // separate methods for mode and padding
+ // called directly by Cipher only to throw the correct exception
+ int supportsMode(Service s) {
+ return supports(s, ATTR_MODE, mode);
+ }
+ int supportsPadding(Service s) {
+ return supports(s, ATTR_PAD, pad);
+ }
+
+ private static int supports(Service s, String attrName, String value) {
+ if (value == null) {
+ return S_YES;
+ }
+ String regexp = s.getAttribute(attrName);
+ if (regexp == null) {
+ return S_MAYBE;
+ }
+ return matches(regexp, value) ? S_YES : S_NO;
+ }
+
+ // ConcurrentMap<String,Pattern> for previously compiled patterns
+ private final static ConcurrentMap<String, Pattern> patternCache =
+ new ConcurrentHashMap<String, Pattern>();
+
+ private static boolean matches(String regexp, String str) {
+ Pattern pattern = patternCache.get(regexp);
+ if (pattern == null) {
+ pattern = Pattern.compile(regexp);
+ patternCache.putIfAbsent(regexp, pattern);
+ }
+ return pattern.matcher(str.toUpperCase(Locale.ENGLISH)).matches();
+ }
+
+ }
+
+ private static List<Transform> getTransforms(String transformation)
+ throws NoSuchAlgorithmException {
+ String[] parts = tokenizeTransformation(transformation);
+
+ String alg = parts[0];
+ String mode = parts[1];
+ String pad = parts[2];
+ if ((mode != null) && (mode.length() == 0)) {
+ mode = null;
+ }
+ if ((pad != null) && (pad.length() == 0)) {
+ pad = null;
+ }
+
+ if ((mode == null) && (pad == null)) {
+ // DES
+ Transform tr = new Transform(alg, "", null, null);
+ return Collections.singletonList(tr);
+ } else { // if ((mode != null) && (pad != null)) {
+ // DES/CBC/PKCS5Padding
+ List<Transform> list = new ArrayList<>(4);
+ list.add(new Transform(alg, "/" + mode + "/" + pad, null, null));
+ list.add(new Transform(alg, "/" + mode, null, pad));
+ list.add(new Transform(alg, "//" + pad, mode, null));
+ list.add(new Transform(alg, "", mode, pad));
+ return list;
+ }
+ }
+
+ // get the transform matching the specified service
+ private static Transform getTransform(Service s,
+ List<Transform> transforms) {
+ String alg = s.getAlgorithm().toUpperCase(Locale.ENGLISH);
+ for (Transform tr : transforms) {
+ if (alg.endsWith(tr.suffix)) {
+ return tr;
+ }
+ }
+ return null;
+ }
+ */
+ // END Android-removed: Reimplement provider selection.
+
+ /**
+ * Returns a <code>Cipher</code> object that implements the specified
+ * transformation.
+ *
+ * <p> This method traverses the list of registered security Providers,
+ * starting with the most preferred Provider.
+ * A new Cipher object encapsulating the
+ * CipherSpi implementation from the first
+ * Provider that supports the specified algorithm is returned.
+ *
+ * <p> Note that the list of registered providers may be retrieved via
+ * the {@link Security#getProviders() Security.getProviders()} method.
+ *
+ * @param transformation the name of the transformation, e.g.,
+ * <i>DES/CBC/PKCS5Padding</i>.
+ * See the Cipher section in the <a href=
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#Cipher">
+ * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+ * for information about standard transformation names.
+ *
+ * @return a cipher that implements the requested transformation.
+ *
+ * @exception NoSuchAlgorithmException if <code>transformation</code>
+ * is null, empty, in an invalid format,
+ * or if no Provider supports a CipherSpi implementation for the
+ * specified algorithm.
+ *
+ * @exception NoSuchPaddingException if <code>transformation</code>
+ * contains a padding scheme that is not available.
+ *
+ * @see java.security.Provider
+ */
+ public static final Cipher getInstance(String transformation)
+ throws NoSuchAlgorithmException, NoSuchPaddingException
+ {
+ return createCipher(transformation, null);
+ }
+
+ /**
+ * Returns a <code>Cipher</code> object that implements the specified
+ * transformation.
+ *
+ * <p> A new Cipher object encapsulating the
+ * CipherSpi implementation from the specified provider
+ * is returned. The specified provider must be registered
+ * in the security provider list.
+ *
+ * <p> Note that the list of registered providers may be retrieved via
+ * the {@link Security#getProviders() Security.getProviders()} method.
+ *
+ * @param transformation the name of the transformation,
+ * e.g., <i>DES/CBC/PKCS5Padding</i>.
+ * See the Cipher section in the <a href=
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#Cipher">
+ * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+ * for information about standard transformation names.
+ *
+ * @param provider the name of the provider.
+ *
+ * @return a cipher that implements the requested transformation.
+ *
+ * @exception NoSuchAlgorithmException if <code>transformation</code>
+ * is null, empty, in an invalid format,
+ * or if a CipherSpi implementation for the specified algorithm
+ * is not available from the specified provider.
+ *
+ * @exception NoSuchProviderException if the specified provider is not
+ * registered in the security provider list.
+ *
+ * @exception NoSuchPaddingException if <code>transformation</code>
+ * contains a padding scheme that is not available.
+ *
+ * @exception IllegalArgumentException if the <code>provider</code>
+ * is null or empty.
+ *
+ * @see java.security.Provider
+ */
+ public static final Cipher getInstance(String transformation,
+ String provider)
+ throws NoSuchAlgorithmException, NoSuchProviderException,
+ NoSuchPaddingException
+ {
+ if ((provider == null) || (provider.length() == 0)) {
+ throw new IllegalArgumentException("Missing provider");
+ }
+ Provider p = Security.getProvider(provider);
+ if (p == null) {
+ throw new NoSuchProviderException("No such provider: " +
+ provider);
+ }
+ return getInstance(transformation, p);
+ }
+
+ /**
+ * Returns a <code>Cipher</code> object that implements the specified
+ * transformation.
+ *
+ * <p> A new Cipher object encapsulating the
+ * CipherSpi implementation from the specified Provider
+ * object is returned. Note that the specified Provider object
+ * does not have to be registered in the provider list.
+ *
+ * @param transformation the name of the transformation,
+ * e.g., <i>DES/CBC/PKCS5Padding</i>.
+ * See the Cipher section in the <a href=
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#Cipher">
+ * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+ * for information about standard transformation names.
+ *
+ * @param provider the provider.
+ *
+ * @return a cipher that implements the requested transformation.
+ *
+ * @exception NoSuchAlgorithmException if <code>transformation</code>
+ * is null, empty, in an invalid format,
+ * or if a CipherSpi implementation for the specified algorithm
+ * is not available from the specified Provider object.
+ *
+ * @exception NoSuchPaddingException if <code>transformation</code>
+ * contains a padding scheme that is not available.
+ *
+ * @exception IllegalArgumentException if the <code>provider</code>
+ * is null.
+ *
+ * @see java.security.Provider
+ */
+ public static final Cipher getInstance(String transformation,
+ Provider provider)
+ throws NoSuchAlgorithmException, NoSuchPaddingException
+ {
+ if (provider == null) {
+ throw new IllegalArgumentException("Missing provider");
+ }
+ return createCipher(transformation, provider);
+ }
+
+ static final Cipher createCipher(String transformation, Provider provider)
+ throws NoSuchAlgorithmException, NoSuchPaddingException {
+ Providers.checkBouncyCastleDeprecation(provider, "Cipher", transformation);
+ String[] tokenizedTransformation = tokenizeTransformation(transformation);
+
+ CipherSpiAndProvider cipherSpiAndProvider = null;
+ try {
+ cipherSpiAndProvider =
+ tryCombinations(null /*params*/, provider, tokenizedTransformation);
+ } catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
+ // Shouldn't happen.
+ throw new IllegalStateException("Key/Algorithm excepton despite not passing one", e);
+ }
+
+ if (cipherSpiAndProvider == null) {
+ if (provider == null) {
+ throw new NoSuchAlgorithmException("No provider found for " + transformation);
+ } else {
+ throw new NoSuchAlgorithmException("Provider " + provider.getName()
+ + " does not provide " + transformation);
+ }
+ }
+
+ // exceptions and stuff
+ return new Cipher(null, provider, transformation, tokenizedTransformation);
+ }
+
+ /**
+ * Choose the Spi from the first provider available. Used if
+ * delayed provider selection is not possible because init()
+ * is not the first method called.
+ */
+ void updateProviderIfNeeded() {
+ try {
+ spiAndProviderUpdater.updateAndGetSpiAndProvider(null, spi, provider);
+ } catch (Exception lastException) {
+ ProviderException e = new ProviderException
+ ("Could not construct CipherSpi instance");
+ if (lastException != null) {
+ e.initCause(lastException);
+ }
+ throw e;
+ }
+ }
+
+ private void chooseProvider(InitType initType, int opmode, Key key,
+ AlgorithmParameterSpec paramSpec,
+ AlgorithmParameters params, SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException {
+
+ try {
+ final InitParams initParams = new InitParams(initType, opmode, key, random,
+ paramSpec, params);
+ spiAndProviderUpdater.updateAndGetSpiAndProvider(initParams, spi, provider);
+ } catch (Exception lastException) {
+ // no working provider found, fail
+ if (lastException instanceof InvalidKeyException) {
+ throw (InvalidKeyException)lastException;
+ }
+ if (lastException instanceof InvalidAlgorithmParameterException) {
+ throw (InvalidAlgorithmParameterException)lastException;
+ }
+ if (lastException instanceof RuntimeException) {
+ throw (RuntimeException)lastException;
+ }
+ String kName = (key != null) ? key.getClass().getName() : "(null)";
+ throw new InvalidKeyException
+ ("No installed provider supports this key: "
+ + kName, lastException);
+ }
+ }
+
+ /**
+ * Returns the provider of this <code>Cipher</code> object.
+ *
+ * @return the provider of this <code>Cipher</code> object
+ */
+ public final Provider getProvider() {
+ updateProviderIfNeeded();
+ return this.provider;
+ }
+
+ /**
+ * Returns the algorithm name of this <code>Cipher</code> object.
+ *
+ * <p>This is the same name that was specified in one of the
+ * <code>getInstance</code> calls that created this <code>Cipher</code>
+ * object..
+ *
+ * @return the algorithm name of this <code>Cipher</code> object.
+ */
+ public final String getAlgorithm() {
+ return this.transformation;
+ }
+
+ /**
+ * Returns the block size (in bytes).
+ *
+ * @return the block size (in bytes), or 0 if the underlying algorithm is
+ * not a block cipher
+ */
+ public final int getBlockSize() {
+ updateProviderIfNeeded();
+ return spi.engineGetBlockSize();
+ }
+
+ /**
+ * Returns the length in bytes that an output buffer would need to be in
+ * order to hold the result of the next <code>update</code> or
+ * <code>doFinal</code> operation, given the input length
+ * <code>inputLen</code> (in bytes).
+ *
+ * <p>This call takes into account any unprocessed (buffered) data from a
+ * previous <code>update</code> call, padding, and AEAD tagging.
+ *
+ * <p>The actual output length of the next <code>update</code> or
+ * <code>doFinal</code> call may be smaller than the length returned by
+ * this method.
+ *
+ * @param inputLen the input length (in bytes)
+ *
+ * @return the required output buffer size (in bytes)
+ *
+ * @exception IllegalStateException if this cipher is in a wrong state
+ * (e.g., has not yet been initialized)
+ */
+ public final int getOutputSize(int inputLen) {
+
+ if (!initialized && !(this instanceof NullCipher)) {
+ throw new IllegalStateException("Cipher not initialized");
+ }
+ if (inputLen < 0) {
+ throw new IllegalArgumentException("Input size must be equal " +
+ "to or greater than zero");
+ }
+ updateProviderIfNeeded();
+ return spi.engineGetOutputSize(inputLen);
+ }
+
+ /**
+ * Returns the initialization vector (IV) in a new buffer.
+ *
+ * <p>This is useful in the case where a random IV was created,
+ * or in the context of password-based encryption or
+ * decryption, where the IV is derived from a user-supplied password.
+ *
+ * @return the initialization vector in a new buffer, or null if the
+ * underlying algorithm does not use an IV, or if the IV has not yet
+ * been set.
+ */
+ public final byte[] getIV() {
+ updateProviderIfNeeded();
+ return spi.engineGetIV();
+ }
+
+ /**
+ * Returns the parameters used with this cipher.
+ *
+ * <p>The returned parameters may be the same that were used to initialize
+ * this cipher, or may contain a combination of default and random
+ * parameter values used by the underlying cipher implementation if this
+ * cipher requires algorithm parameters but was not initialized with any.
+ *
+ * @return the parameters used with this cipher, or null if this cipher
+ * does not use any parameters.
+ */
+ public final AlgorithmParameters getParameters() {
+ updateProviderIfNeeded();
+ return spi.engineGetParameters();
+ }
+
+ /**
+ * Returns the exemption mechanism object used with this cipher.
+ *
+ * @return the exemption mechanism object used with this cipher, or
+ * null if this cipher does not use any exemption mechanism.
+ */
+ public final ExemptionMechanism getExemptionMechanism() {
+ updateProviderIfNeeded();
+ return exmech;
+ }
+
+ // BEGIN Android-removed: Eliminate crypto permission checking.
+ // Android doesn't implement SecurityManager permissions.
+ /*
+ //
+ // Crypto permission check code below
+ //
+ private void checkCryptoPerm(CipherSpi checkSpi, Key key)
+ throws InvalidKeyException {
+ if (cryptoPerm == CryptoAllPermission.INSTANCE) {
+ return;
+ }
+ // Check if key size and default parameters are within legal limits
+ AlgorithmParameterSpec params;
+ try {
+ params = getAlgorithmParameterSpec(checkSpi.engineGetParameters());
+ } catch (InvalidParameterSpecException ipse) {
+ throw new InvalidKeyException
+ ("Unsupported default algorithm parameters");
+ }
+ if (!passCryptoPermCheck(checkSpi, key, params)) {
+ throw new InvalidKeyException(
+ "Illegal key size or default parameters");
+ }
+ }
+
+ private void checkCryptoPerm(CipherSpi checkSpi, Key key,
+ AlgorithmParameterSpec params) throws InvalidKeyException,
+ InvalidAlgorithmParameterException {
+ if (cryptoPerm == CryptoAllPermission.INSTANCE) {
+ return;
+ }
+ // Determine keysize and check if it is within legal limits
+ if (!passCryptoPermCheck(checkSpi, key, null)) {
+ throw new InvalidKeyException("Illegal key size");
+ }
+ if ((params != null) && (!passCryptoPermCheck(checkSpi, key, params))) {
+ throw new InvalidAlgorithmParameterException("Illegal parameters");
+ }
+ }
+
+ private void checkCryptoPerm(CipherSpi checkSpi, Key key,
+ AlgorithmParameters params)
+ throws InvalidKeyException, InvalidAlgorithmParameterException {
+ if (cryptoPerm == CryptoAllPermission.INSTANCE) {
+ return;
+ }
+ // Convert the specified parameters into specs and then delegate.
+ AlgorithmParameterSpec pSpec;
+ try {
+ pSpec = getAlgorithmParameterSpec(params);
+ } catch (InvalidParameterSpecException ipse) {
+ throw new InvalidAlgorithmParameterException
+ ("Failed to retrieve algorithm parameter specification");
+ }
+ checkCryptoPerm(checkSpi, key, pSpec);
+ }
+
+ private boolean passCryptoPermCheck(CipherSpi checkSpi, Key key,
+ AlgorithmParameterSpec params)
+ throws InvalidKeyException {
+ String em = cryptoPerm.getExemptionMechanism();
+ int keySize = checkSpi.engineGetKeySize(key);
+ // Use the "algorithm" component of the cipher
+ // transformation so that the perm check would
+ // work when the key has the "aliased" algo.
+ String algComponent;
+ int index = transformation.indexOf('/');
+ if (index != -1) {
+ algComponent = transformation.substring(0, index);
+ } else {
+ algComponent = transformation;
+ }
+ CryptoPermission checkPerm =
+ new CryptoPermission(algComponent, keySize, params, em);
+
+ if (!cryptoPerm.implies(checkPerm)) {
+ if (debug != null) {
+ debug.println("Crypto Permission check failed");
+ debug.println("granted: " + cryptoPerm);
+ debug.println("requesting: " + checkPerm);
+ }
+ return false;
+ }
+ if (exmech == null) {
+ return true;
+ }
+ try {
+ if (!exmech.isCryptoAllowed(key)) {
+ if (debug != null) {
+ debug.println(exmech.getName() + " isn't enforced");
+ }
+ return false;
+ }
+ } catch (ExemptionMechanismException eme) {
+ if (debug != null) {
+ debug.println("Cannot determine whether "+
+ exmech.getName() + " has been enforced");
+ eme.printStackTrace();
+ }
+ return false;
+ }
+ return true;
+ }
+ */
+ // END Android-removed: Eliminate crypto permission checking.
+
+ // check if opmode is one of the defined constants
+ // throw InvalidParameterExeption if not
+ private static void checkOpmode(int opmode) {
+ if ((opmode < ENCRYPT_MODE) || (opmode > UNWRAP_MODE)) {
+ throw new InvalidParameterException("Invalid operation mode");
+ }
+ }
+
+ private static String getOpmodeString(int opmode) {
+ switch (opmode) {
+ case ENCRYPT_MODE:
+ return "encryption";
+ case DECRYPT_MODE:
+ return "decryption";
+ case WRAP_MODE:
+ return "key wrapping";
+ case UNWRAP_MODE:
+ return "key unwrapping";
+ default:
+ return "";
+ }
+ }
+
+ /**
+ * Initializes this cipher with a key.
+ *
+ * <p>The cipher is initialized for one of the following four operations:
+ * encryption, decryption, key wrapping or key unwrapping, depending
+ * on the value of <code>opmode</code>.
+ *
+ * <p>If this cipher requires any algorithm parameters that cannot be
+ * derived from the given <code>key</code>, the underlying cipher
+ * implementation is supposed to generate the required parameters itself
+ * (using provider-specific default or random values) if it is being
+ * initialized for encryption or key wrapping, and raise an
+ * <code>InvalidKeyException</code> if it is being
+ * initialized for decryption or key unwrapping.
+ * The generated parameters can be retrieved using
+ * {@link #getParameters() getParameters} or
+ * {@link #getIV() getIV} (if the parameter is an IV).
+ *
+ * <p>If this cipher requires algorithm parameters that cannot be
+ * derived from the input parameters, and there are no reasonable
+ * provider-specific default values, initialization will
+ * necessarily fail.
+ *
+ * <p>If this cipher (including its underlying feedback or padding scheme)
+ * requires any random bytes (e.g., for parameter generation), it will get
+ * them using the {@link java.security.SecureRandom}
+ * implementation of the highest-priority
+ * installed provider as the source of randomness.
+ * (If none of the installed providers supply an implementation of
+ * SecureRandom, a system-provided source of randomness will be used.)
+ *
+ * <p>Note that when a Cipher object is initialized, it loses all
+ * previously-acquired state. In other words, initializing a Cipher is
+ * equivalent to creating a new instance of that Cipher and initializing
+ * it.
+ *
+ * @param opmode the operation mode of this cipher (this is one of
+ * the following:
+ * <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>,
+ * <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>)
+ * @param key the key
+ *
+ * @exception InvalidKeyException if the given key is inappropriate for
+ * initializing this cipher, or requires
+ * algorithm parameters that cannot be
+ * determined from the given key, or if the given key has a keysize that
+ * exceeds the maximum allowable keysize (as determined from the
+ * configured jurisdiction policy files).
+ * @throws UnsupportedOperationException if (@code opmode} is
+ * {@code WRAP_MODE} or {@code UNWRAP_MODE} but the mode is not implemented
+ * by the underlying {@code CipherSpi}.
+ */
+ public final void init(int opmode, Key key) throws InvalidKeyException {
+ init(opmode, key, JceSecurity.RANDOM);
+ }
+
+ /**
+ * Initializes this cipher with a key and a source of randomness.
+ *
+ * <p>The cipher is initialized for one of the following four operations:
+ * encryption, decryption, key wrapping or key unwrapping, depending
+ * on the value of <code>opmode</code>.
+ *
+ * <p>If this cipher requires any algorithm parameters that cannot be
+ * derived from the given <code>key</code>, the underlying cipher
+ * implementation is supposed to generate the required parameters itself
+ * (using provider-specific default or random values) if it is being
+ * initialized for encryption or key wrapping, and raise an
+ * <code>InvalidKeyException</code> if it is being
+ * initialized for decryption or key unwrapping.
+ * The generated parameters can be retrieved using
+ * {@link #getParameters() getParameters} or
+ * {@link #getIV() getIV} (if the parameter is an IV).
+ *
+ * <p>If this cipher requires algorithm parameters that cannot be
+ * derived from the input parameters, and there are no reasonable
+ * provider-specific default values, initialization will
+ * necessarily fail.
+ *
+ * <p>If this cipher (including its underlying feedback or padding scheme)
+ * requires any random bytes (e.g., for parameter generation), it will get
+ * them from <code>random</code>.
+ *
+ * <p>Note that when a Cipher object is initialized, it loses all
+ * previously-acquired state. In other words, initializing a Cipher is
+ * equivalent to creating a new instance of that Cipher and initializing
+ * it.
+ *
+ * @param opmode the operation mode of this cipher (this is one of the
+ * following:
+ * <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>,
+ * <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>)
+ * @param key the encryption key
+ * @param random the source of randomness
+ *
+ * @exception InvalidKeyException if the given key is inappropriate for
+ * initializing this cipher, or requires
+ * algorithm parameters that cannot be
+ * determined from the given key, or if the given key has a keysize that
+ * exceeds the maximum allowable keysize (as determined from the
+ * configured jurisdiction policy files).
+ * @throws UnsupportedOperationException if (@code opmode} is
+ * {@code WRAP_MODE} or {@code UNWRAP_MODE} but the mode is not implemented
+ * by the underlying {@code CipherSpi}.
+ */
+ public final void init(int opmode, Key key, SecureRandom random)
+ throws InvalidKeyException
+ {
+ initialized = false;
+ checkOpmode(opmode);
+
+ try {
+ chooseProvider(InitType.KEY, opmode, key, null, null, random);
+ } catch (InvalidAlgorithmParameterException e) {
+ // should never occur
+ throw new InvalidKeyException(e);
+ }
+
+ initialized = true;
+ this.opmode = opmode;
+
+ // Android-removed: this debugging mechanism is not used in Android.
+ /*
+ if (!skipDebug && pdebug != null) {
+ pdebug.println("Cipher." + transformation + " " +
+ getOpmodeString(opmode) + " algorithm from: " +
+ this.provider.getName());
+ }
+ */
+ }
+
+ /**
+ * Initializes this cipher with a key and a set of algorithm
+ * parameters.
+ *
+ * <p>The cipher is initialized for one of the following four operations:
+ * encryption, decryption, key wrapping or key unwrapping, depending
+ * on the value of <code>opmode</code>.
+ *
+ * <p>If this cipher requires any algorithm parameters and
+ * <code>params</code> is null, the underlying cipher implementation is
+ * supposed to generate the required parameters itself (using
+ * provider-specific default or random values) if it is being
+ * initialized for encryption or key wrapping, and raise an
+ * <code>InvalidAlgorithmParameterException</code> if it is being
+ * initialized for decryption or key unwrapping.
+ * The generated parameters can be retrieved using
+ * {@link #getParameters() getParameters} or
+ * {@link #getIV() getIV} (if the parameter is an IV).
+ *
+ * <p>If this cipher requires algorithm parameters that cannot be
+ * derived from the input parameters, and there are no reasonable
+ * provider-specific default values, initialization will
+ * necessarily fail.
+ *
+ * <p>If this cipher (including its underlying feedback or padding scheme)
+ * requires any random bytes (e.g., for parameter generation), it will get
+ * them using the {@link java.security.SecureRandom}
+ * implementation of the highest-priority
+ * installed provider as the source of randomness.
+ * (If none of the installed providers supply an implementation of
+ * SecureRandom, a system-provided source of randomness will be used.)
+ *
+ * <p>Note that when a Cipher object is initialized, it loses all
+ * previously-acquired state. In other words, initializing a Cipher is
+ * equivalent to creating a new instance of that Cipher and initializing
+ * it.
+ *
+ * @param opmode the operation mode of this cipher (this is one of the
+ * following:
+ * <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>,
+ * <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>)
+ * @param key the encryption key
+ * @param params the algorithm parameters
+ *
+ * @exception InvalidKeyException if the given key is inappropriate for
+ * initializing this cipher, or its keysize exceeds the maximum allowable
+ * keysize (as determined from the configured jurisdiction policy files).
+ * @exception InvalidAlgorithmParameterException if the given algorithm
+ * parameters are inappropriate for this cipher,
+ * or this cipher requires
+ * algorithm parameters and <code>params</code> is null, or the given
+ * algorithm parameters imply a cryptographic strength that would exceed
+ * the legal limits (as determined from the configured jurisdiction
+ * policy files).
+ * @throws UnsupportedOperationException if (@code opmode} is
+ * {@code WRAP_MODE} or {@code UNWRAP_MODE} but the mode is not implemented
+ * by the underlying {@code CipherSpi}.
+ */
+ public final void init(int opmode, Key key, AlgorithmParameterSpec params)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ init(opmode, key, params, JceSecurity.RANDOM);
+ }
+
+ /**
+ * Initializes this cipher with a key, a set of algorithm
+ * parameters, and a source of randomness.
+ *
+ * <p>The cipher is initialized for one of the following four operations:
+ * encryption, decryption, key wrapping or key unwrapping, depending
+ * on the value of <code>opmode</code>.
+ *
+ * <p>If this cipher requires any algorithm parameters and
+ * <code>params</code> is null, the underlying cipher implementation is
+ * supposed to generate the required parameters itself (using
+ * provider-specific default or random values) if it is being
+ * initialized for encryption or key wrapping, and raise an
+ * <code>InvalidAlgorithmParameterException</code> if it is being
+ * initialized for decryption or key unwrapping.
+ * The generated parameters can be retrieved using
+ * {@link #getParameters() getParameters} or
+ * {@link #getIV() getIV} (if the parameter is an IV).
+ *
+ * <p>If this cipher requires algorithm parameters that cannot be
+ * derived from the input parameters, and there are no reasonable
+ * provider-specific default values, initialization will
+ * necessarily fail.
+ *
+ * <p>If this cipher (including its underlying feedback or padding scheme)
+ * requires any random bytes (e.g., for parameter generation), it will get
+ * them from <code>random</code>.
+ *
+ * <p>Note that when a Cipher object is initialized, it loses all
+ * previously-acquired state. In other words, initializing a Cipher is
+ * equivalent to creating a new instance of that Cipher and initializing
+ * it.
+ *
+ * @param opmode the operation mode of this cipher (this is one of the
+ * following:
+ * <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>,
+ * <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>)
+ * @param key the encryption key
+ * @param params the algorithm parameters
+ * @param random the source of randomness
+ *
+ * @exception InvalidKeyException if the given key is inappropriate for
+ * initializing this cipher, or its keysize exceeds the maximum allowable
+ * keysize (as determined from the configured jurisdiction policy files).
+ * @exception InvalidAlgorithmParameterException if the given algorithm
+ * parameters are inappropriate for this cipher,
+ * or this cipher requires
+ * algorithm parameters and <code>params</code> is null, or the given
+ * algorithm parameters imply a cryptographic strength that would exceed
+ * the legal limits (as determined from the configured jurisdiction
+ * policy files).
+ * @throws UnsupportedOperationException if (@code opmode} is
+ * {@code WRAP_MODE} or {@code UNWRAP_MODE} but the mode is not implemented
+ * by the underlying {@code CipherSpi}.
+ */
+ public final void init(int opmode, Key key, AlgorithmParameterSpec params,
+ SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ initialized = false;
+ checkOpmode(opmode);
+
+ chooseProvider(InitType.ALGORITHM_PARAM_SPEC, opmode, key, params, null, random);
+
+ initialized = true;
+ this.opmode = opmode;
+
+ // Android-removed: this debugging mechanism is not used in Android.
+ /*
+ if (!skipDebug && pdebug != null) {
+ pdebug.println("Cipher." + transformation + " " +
+ getOpmodeString(opmode) + " algorithm from: " +
+ this.provider.getName());
+ }
+ */
+ }
+
+ /**
+ * Initializes this cipher with a key and a set of algorithm
+ * parameters.
+ *
+ * <p>The cipher is initialized for one of the following four operations:
+ * encryption, decryption, key wrapping or key unwrapping, depending
+ * on the value of <code>opmode</code>.
+ *
+ * <p>If this cipher requires any algorithm parameters and
+ * <code>params</code> is null, the underlying cipher implementation is
+ * supposed to generate the required parameters itself (using
+ * provider-specific default or random values) if it is being
+ * initialized for encryption or key wrapping, and raise an
+ * <code>InvalidAlgorithmParameterException</code> if it is being
+ * initialized for decryption or key unwrapping.
+ * The generated parameters can be retrieved using
+ * {@link #getParameters() getParameters} or
+ * {@link #getIV() getIV} (if the parameter is an IV).
+ *
+ * <p>If this cipher requires algorithm parameters that cannot be
+ * derived from the input parameters, and there are no reasonable
+ * provider-specific default values, initialization will
+ * necessarily fail.
+ *
+ * <p>If this cipher (including its underlying feedback or padding scheme)
+ * requires any random bytes (e.g., for parameter generation), it will get
+ * them using the {@link java.security.SecureRandom}
+ * implementation of the highest-priority
+ * installed provider as the source of randomness.
+ * (If none of the installed providers supply an implementation of
+ * SecureRandom, a system-provided source of randomness will be used.)
+ *
+ * <p>Note that when a Cipher object is initialized, it loses all
+ * previously-acquired state. In other words, initializing a Cipher is
+ * equivalent to creating a new instance of that Cipher and initializing
+ * it.
+ *
+ * @param opmode the operation mode of this cipher (this is one of the
+ * following: <code>ENCRYPT_MODE</code>,
+ * <code>DECRYPT_MODE</code>, <code>WRAP_MODE</code>
+ * or <code>UNWRAP_MODE</code>)
+ * @param key the encryption key
+ * @param params the algorithm parameters
+ *
+ * @exception InvalidKeyException if the given key is inappropriate for
+ * initializing this cipher, or its keysize exceeds the maximum allowable
+ * keysize (as determined from the configured jurisdiction policy files).
+ * @exception InvalidAlgorithmParameterException if the given algorithm
+ * parameters are inappropriate for this cipher,
+ * or this cipher requires
+ * algorithm parameters and <code>params</code> is null, or the given
+ * algorithm parameters imply a cryptographic strength that would exceed
+ * the legal limits (as determined from the configured jurisdiction
+ * policy files).
+ * @throws UnsupportedOperationException if (@code opmode} is
+ * {@code WRAP_MODE} or {@code UNWRAP_MODE} but the mode is not implemented
+ * by the underlying {@code CipherSpi}.
+ */
+ public final void init(int opmode, Key key, AlgorithmParameters params)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ init(opmode, key, params, JceSecurity.RANDOM);
+ }
+
+ /**
+ * Initializes this cipher with a key, a set of algorithm
+ * parameters, and a source of randomness.
+ *
+ * <p>The cipher is initialized for one of the following four operations:
+ * encryption, decryption, key wrapping or key unwrapping, depending
+ * on the value of <code>opmode</code>.
+ *
+ * <p>If this cipher requires any algorithm parameters and
+ * <code>params</code> is null, the underlying cipher implementation is
+ * supposed to generate the required parameters itself (using
+ * provider-specific default or random values) if it is being
+ * initialized for encryption or key wrapping, and raise an
+ * <code>InvalidAlgorithmParameterException</code> if it is being
+ * initialized for decryption or key unwrapping.
+ * The generated parameters can be retrieved using
+ * {@link #getParameters() getParameters} or
+ * {@link #getIV() getIV} (if the parameter is an IV).
+ *
+ * <p>If this cipher requires algorithm parameters that cannot be
+ * derived from the input parameters, and there are no reasonable
+ * provider-specific default values, initialization will
+ * necessarily fail.
+ *
+ * <p>If this cipher (including its underlying feedback or padding scheme)
+ * requires any random bytes (e.g., for parameter generation), it will get
+ * them from <code>random</code>.
+ *
+ * <p>Note that when a Cipher object is initialized, it loses all
+ * previously-acquired state. In other words, initializing a Cipher is
+ * equivalent to creating a new instance of that Cipher and initializing
+ * it.
+ *
+ * @param opmode the operation mode of this cipher (this is one of the
+ * following: <code>ENCRYPT_MODE</code>,
+ * <code>DECRYPT_MODE</code>, <code>WRAP_MODE</code>
+ * or <code>UNWRAP_MODE</code>)
+ * @param key the encryption key
+ * @param params the algorithm parameters
+ * @param random the source of randomness
+ *
+ * @exception InvalidKeyException if the given key is inappropriate for
+ * initializing this cipher, or its keysize exceeds the maximum allowable
+ * keysize (as determined from the configured jurisdiction policy files).
+ * @exception InvalidAlgorithmParameterException if the given algorithm
+ * parameters are inappropriate for this cipher,
+ * or this cipher requires
+ * algorithm parameters and <code>params</code> is null, or the given
+ * algorithm parameters imply a cryptographic strength that would exceed
+ * the legal limits (as determined from the configured jurisdiction
+ * policy files).
+ * @throws UnsupportedOperationException if (@code opmode} is
+ * {@code WRAP_MODE} or {@code UNWRAP_MODE} but the mode is not implemented
+ * by the underlying {@code CipherSpi}.
+ */
+ public final void init(int opmode, Key key, AlgorithmParameters params,
+ SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ initialized = false;
+ checkOpmode(opmode);
+
+ chooseProvider(InitType.ALGORITHM_PARAMS, opmode, key, null, params, random);
+
+ initialized = true;
+ this.opmode = opmode;
+
+ // Android-removed: this debugging mechanism is not used in Android.
+ /*
+ if (!skipDebug && pdebug != null) {
+ pdebug.println("Cipher." + transformation + " " +
+ getOpmodeString(opmode) + " algorithm from: " +
+ this.provider.getName());
+ }
+ */
+ }
+
+ /**
+ * Initializes this cipher with the public key from the given certificate.
+ * <p> The cipher is initialized for one of the following four operations:
+ * encryption, decryption, key wrapping or key unwrapping, depending
+ * on the value of <code>opmode</code>.
+ *
+ * <p>If the certificate is of type X.509 and has a <i>key usage</i>
+ * extension field marked as critical, and the value of the <i>key usage</i>
+ * extension field implies that the public key in
+ * the certificate and its corresponding private key are not
+ * supposed to be used for the operation represented by the value
+ * of <code>opmode</code>,
+ * an <code>InvalidKeyException</code>
+ * is thrown.
+ *
+ * <p> If this cipher requires any algorithm parameters that cannot be
+ * derived from the public key in the given certificate, the underlying
+ * cipher
+ * implementation is supposed to generate the required parameters itself
+ * (using provider-specific default or random values) if it is being
+ * initialized for encryption or key wrapping, and raise an <code>
+ * InvalidKeyException</code> if it is being initialized for decryption or
+ * key unwrapping.
+ * The generated parameters can be retrieved using
+ * {@link #getParameters() getParameters} or
+ * {@link #getIV() getIV} (if the parameter is an IV).
+ *
+ * <p>If this cipher requires algorithm parameters that cannot be
+ * derived from the input parameters, and there are no reasonable
+ * provider-specific default values, initialization will
+ * necessarily fail.
+ *
+ * <p>If this cipher (including its underlying feedback or padding scheme)
+ * requires any random bytes (e.g., for parameter generation), it will get
+ * them using the
+ * <code>SecureRandom</code>
+ * implementation of the highest-priority
+ * installed provider as the source of randomness.
+ * (If none of the installed providers supply an implementation of
+ * SecureRandom, a system-provided source of randomness will be used.)
+ *
+ * <p>Note that when a Cipher object is initialized, it loses all
+ * previously-acquired state. In other words, initializing a Cipher is
+ * equivalent to creating a new instance of that Cipher and initializing
+ * it.
+ *
+ * @param opmode the operation mode of this cipher (this is one of the
+ * following:
+ * <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>,
+ * <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>)
+ * @param certificate the certificate
+ *
+ * @exception InvalidKeyException if the public key in the given
+ * certificate is inappropriate for initializing this cipher, or this
+ * cipher requires algorithm parameters that cannot be determined from the
+ * public key in the given certificate, or the keysize of the public key
+ * in the given certificate has a keysize that exceeds the maximum
+ * allowable keysize (as determined by the configured jurisdiction policy
+ * files).
+ * @throws UnsupportedOperationException if (@code opmode} is
+ * {@code WRAP_MODE} or {@code UNWRAP_MODE} but the mode is not implemented
+ * by the underlying {@code CipherSpi}.
+ */
+ public final void init(int opmode, Certificate certificate)
+ throws InvalidKeyException
+ {
+ init(opmode, certificate, JceSecurity.RANDOM);
+ }
+
+ /**
+ * Initializes this cipher with the public key from the given certificate
+ * and
+ * a source of randomness.
+ *
+ * <p>The cipher is initialized for one of the following four operations:
+ * encryption, decryption, key wrapping
+ * or key unwrapping, depending on
+ * the value of <code>opmode</code>.
+ *
+ * <p>If the certificate is of type X.509 and has a <i>key usage</i>
+ * extension field marked as critical, and the value of the <i>key usage</i>
+ * extension field implies that the public key in
+ * the certificate and its corresponding private key are not
+ * supposed to be used for the operation represented by the value of
+ * <code>opmode</code>,
+ * an <code>InvalidKeyException</code>
+ * is thrown.
+ *
+ * <p>If this cipher requires any algorithm parameters that cannot be
+ * derived from the public key in the given <code>certificate</code>,
+ * the underlying cipher
+ * implementation is supposed to generate the required parameters itself
+ * (using provider-specific default or random values) if it is being
+ * initialized for encryption or key wrapping, and raise an
+ * <code>InvalidKeyException</code> if it is being
+ * initialized for decryption or key unwrapping.
+ * The generated parameters can be retrieved using
+ * {@link #getParameters() getParameters} or
+ * {@link #getIV() getIV} (if the parameter is an IV).
+ *
+ * <p>If this cipher requires algorithm parameters that cannot be
+ * derived from the input parameters, and there are no reasonable
+ * provider-specific default values, initialization will
+ * necessarily fail.
+ *
+ * <p>If this cipher (including its underlying feedback or padding scheme)
+ * requires any random bytes (e.g., for parameter generation), it will get
+ * them from <code>random</code>.
+ *
+ * <p>Note that when a Cipher object is initialized, it loses all
+ * previously-acquired state. In other words, initializing a Cipher is
+ * equivalent to creating a new instance of that Cipher and initializing
+ * it.
+ *
+ * @param opmode the operation mode of this cipher (this is one of the
+ * following:
+ * <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>,
+ * <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>)
+ * @param certificate the certificate
+ * @param random the source of randomness
+ *
+ * @exception InvalidKeyException if the public key in the given
+ * certificate is inappropriate for initializing this cipher, or this
+ * cipher
+ * requires algorithm parameters that cannot be determined from the
+ * public key in the given certificate, or the keysize of the public key
+ * in the given certificate has a keysize that exceeds the maximum
+ * allowable keysize (as determined by the configured jurisdiction policy
+ * files).
+ * @throws UnsupportedOperationException if (@code opmode} is
+ * {@code WRAP_MODE} or {@code UNWRAP_MODE} but the mode is not implemented
+ * by the underlying {@code CipherSpi}.
+ */
+ public final void init(int opmode, Certificate certificate,
+ SecureRandom random)
+ throws InvalidKeyException
+ {
+ initialized = false;
+ checkOpmode(opmode);
+
+ // Check key usage if the certificate is of
+ // type X.509.
+ if (certificate instanceof java.security.cert.X509Certificate) {
+ // Check whether the cert has a key usage extension
+ // marked as a critical extension.
+ X509Certificate cert = (X509Certificate)certificate;
+ Set<String> critSet = cert.getCriticalExtensionOIDs();
+
+ if (critSet != null && !critSet.isEmpty()
+ && critSet.contains(KEY_USAGE_EXTENSION_OID)) {
+ boolean[] keyUsageInfo = cert.getKeyUsage();
+ // keyUsageInfo[2] is for keyEncipherment;
+ // keyUsageInfo[3] is for dataEncipherment.
+ if ((keyUsageInfo != null) &&
+ (((opmode == Cipher.ENCRYPT_MODE) &&
+ (keyUsageInfo.length > 3) &&
+ (keyUsageInfo[3] == false)) ||
+ ((opmode == Cipher.WRAP_MODE) &&
+ (keyUsageInfo.length > 2) &&
+ (keyUsageInfo[2] == false)))) {
+ throw new InvalidKeyException("Wrong key usage");
+ }
+ }
+ }
+
+ PublicKey publicKey =
+ (certificate==null? null:certificate.getPublicKey());
+
+ try {
+ chooseProvider(InitType.KEY, opmode, (Key) publicKey, null, null, random);
+ } catch (InvalidAlgorithmParameterException e) {
+ // should never occur
+ throw new InvalidKeyException(e);
+ }
+
+ initialized = true;
+ this.opmode = opmode;
+
+ // Android-removed: this debugging mechanism is not used in Android.
+ /*
+ if (!skipDebug && pdebug != null) {
+ pdebug.println("Cipher." + transformation + " " +
+ getOpmodeString(opmode) + " algorithm from: " +
+ this.provider.getName());
+ }
+ */
+ }
+
+ /**
+ * Ensures that Cipher is in a valid state for update() and doFinal()
+ * calls - should be initialized and in ENCRYPT_MODE or DECRYPT_MODE.
+ * @throws IllegalStateException if Cipher object is not in valid state.
+ */
+ private void checkCipherState() {
+ if (!(this instanceof NullCipher)) {
+ if (!initialized) {
+ throw new IllegalStateException("Cipher not initialized");
+ }
+ if ((opmode != Cipher.ENCRYPT_MODE) &&
+ (opmode != Cipher.DECRYPT_MODE)) {
+ throw new IllegalStateException("Cipher not initialized " +
+ "for encryption/decryption");
+ }
+ }
+ }
+
+ /**
+ * Continues a multiple-part encryption or decryption operation
+ * (depending on how this cipher was initialized), processing another data
+ * part.
+ *
+ * <p>The bytes in the <code>input</code> buffer are processed, and the
+ * result is stored in a new buffer.
+ *
+ * <p>If <code>input</code> has a length of zero, this method returns
+ * <code>null</code>.
+ *
+ * @param input the input buffer
+ *
+ * @return the new buffer with the result, or null if the underlying
+ * cipher is a block cipher and the input data is too short to result in a
+ * new block.
+ *
+ * @exception IllegalStateException if this cipher is in a wrong state
+ * (e.g., has not been initialized)
+ */
+ public final byte[] update(byte[] input) {
+ checkCipherState();
+
+ // Input sanity check
+ if (input == null) {
+ throw new IllegalArgumentException("Null input buffer");
+ }
+
+ updateProviderIfNeeded();
+ if (input.length == 0) {
+ return null;
+ }
+ return spi.engineUpdate(input, 0, input.length);
+ }
+
+ /**
+ * Continues a multiple-part encryption or decryption operation
+ * (depending on how this cipher was initialized), processing another data
+ * part.
+ *
+ * <p>The first <code>inputLen</code> bytes in the <code>input</code>
+ * buffer, starting at <code>inputOffset</code> inclusive, are processed,
+ * and the result is stored in a new buffer.
+ *
+ * <p>If <code>inputLen</code> is zero, this method returns
+ * <code>null</code>.
+ *
+ * @param input the input buffer
+ * @param inputOffset the offset in <code>input</code> where the input
+ * starts
+ * @param inputLen the input length
+ *
+ * @return the new buffer with the result, or null if the underlying
+ * cipher is a block cipher and the input data is too short to result in a
+ * new block.
+ *
+ * @exception IllegalStateException if this cipher is in a wrong state
+ * (e.g., has not been initialized)
+ */
+ public final byte[] update(byte[] input, int inputOffset, int inputLen) {
+ checkCipherState();
+
+ // Input sanity check
+ if (input == null || inputOffset < 0
+ || inputLen > (input.length - inputOffset) || inputLen < 0) {
+ throw new IllegalArgumentException("Bad arguments");
+ }
+
+ updateProviderIfNeeded();
+ if (inputLen == 0) {
+ return null;
+ }
+ return spi.engineUpdate(input, inputOffset, inputLen);
+ }
+
+ /**
+ * Continues a multiple-part encryption or decryption operation
+ * (depending on how this cipher was initialized), processing another data
+ * part.
+ *
+ * <p>The first <code>inputLen</code> bytes in the <code>input</code>
+ * buffer, starting at <code>inputOffset</code> inclusive, are processed,
+ * and the result is stored in the <code>output</code> buffer.
+ *
+ * <p>If the <code>output</code> buffer is too small to hold the result,
+ * a <code>ShortBufferException</code> is thrown. In this case, repeat this
+ * call with a larger output buffer. Use
+ * {@link #getOutputSize(int) getOutputSize} to determine how big
+ * the output buffer should be.
+ *
+ * <p>If <code>inputLen</code> is zero, this method returns
+ * a length of zero.
+ *
+ * <p>Note: this method should be copy-safe, which means the
+ * <code>input</code> and <code>output</code> buffers can reference
+ * the same byte array and no unprocessed input data is overwritten
+ * when the result is copied into the output buffer.
+ *
+ * @param input the input buffer
+ * @param inputOffset the offset in <code>input</code> where the input
+ * starts
+ * @param inputLen the input length
+ * @param output the buffer for the result
+ *
+ * @return the number of bytes stored in <code>output</code>
+ *
+ * @exception IllegalStateException if this cipher is in a wrong state
+ * (e.g., has not been initialized)
+ * @exception ShortBufferException if the given output buffer is too small
+ * to hold the result
+ */
+ public final int update(byte[] input, int inputOffset, int inputLen,
+ byte[] output)
+ throws ShortBufferException {
+ checkCipherState();
+
+ // Input sanity check
+ if (input == null || inputOffset < 0
+ || inputLen > (input.length - inputOffset) || inputLen < 0) {
+ throw new IllegalArgumentException("Bad arguments");
+ }
+
+ updateProviderIfNeeded();
+ if (inputLen == 0) {
+ return 0;
+ }
+ return spi.engineUpdate(input, inputOffset, inputLen,
+ output, 0);
+ }
+
+ /**
+ * Continues a multiple-part encryption or decryption operation
+ * (depending on how this cipher was initialized), processing another data
+ * part.
+ *
+ * <p>The first <code>inputLen</code> bytes in the <code>input</code>
+ * buffer, starting at <code>inputOffset</code> inclusive, are processed,
+ * and the result is stored in the <code>output</code> buffer, starting at
+ * <code>outputOffset</code> inclusive.
+ *
+ * <p>If the <code>output</code> buffer is too small to hold the result,
+ * a <code>ShortBufferException</code> is thrown. In this case, repeat this
+ * call with a larger output buffer. Use
+ * {@link #getOutputSize(int) getOutputSize} to determine how big
+ * the output buffer should be.
+ *
+ * <p>If <code>inputLen</code> is zero, this method returns
+ * a length of zero.
+ *
+ * <p>Note: this method should be copy-safe, which means the
+ * <code>input</code> and <code>output</code> buffers can reference
+ * the same byte array and no unprocessed input data is overwritten
+ * when the result is copied into the output buffer.
+ *
+ * @param input the input buffer
+ * @param inputOffset the offset in <code>input</code> where the input
+ * starts
+ * @param inputLen the input length
+ * @param output the buffer for the result
+ * @param outputOffset the offset in <code>output</code> where the result
+ * is stored
+ *
+ * @return the number of bytes stored in <code>output</code>
+ *
+ * @exception IllegalStateException if this cipher is in a wrong state
+ * (e.g., has not been initialized)
+ * @exception ShortBufferException if the given output buffer is too small
+ * to hold the result
+ */
+ public final int update(byte[] input, int inputOffset, int inputLen,
+ byte[] output, int outputOffset)
+ throws ShortBufferException {
+ checkCipherState();
+
+ // Input sanity check
+ if (input == null || inputOffset < 0
+ || inputLen > (input.length - inputOffset) || inputLen < 0
+ || outputOffset < 0) {
+ throw new IllegalArgumentException("Bad arguments");
+ }
+
+ updateProviderIfNeeded();
+ if (inputLen == 0) {
+ return 0;
+ }
+ return spi.engineUpdate(input, inputOffset, inputLen,
+ output, outputOffset);
+ }
+
+ /**
+ * Continues a multiple-part encryption or decryption operation
+ * (depending on how this cipher was initialized), processing another data
+ * part.
+ *
+ * <p>All <code>input.remaining()</code> bytes starting at
+ * <code>input.position()</code> are processed. The result is stored
+ * in the output buffer.
+ * Upon return, the input buffer's position will be equal
+ * to its limit; its limit will not have changed. The output buffer's
+ * position will have advanced by n, where n is the value returned
+ * by this method; the output buffer's limit will not have changed.
+ *
+ * <p>If <code>output.remaining()</code> bytes are insufficient to
+ * hold the result, a <code>ShortBufferException</code> is thrown.
+ * In this case, repeat this call with a larger output buffer. Use
+ * {@link #getOutputSize(int) getOutputSize} to determine how big
+ * the output buffer should be.
+ *
+ * <p>Note: this method should be copy-safe, which means the
+ * <code>input</code> and <code>output</code> buffers can reference
+ * the same block of memory and no unprocessed input data is overwritten
+ * when the result is copied into the output buffer.
+ *
+ * @param input the input ByteBuffer
+ * @param output the output ByteByffer
+ *
+ * @return the number of bytes stored in <code>output</code>
+ *
+ * @exception IllegalStateException if this cipher is in a wrong state
+ * (e.g., has not been initialized)
+ * @exception IllegalArgumentException if input and output are the
+ * same object
+ * @exception ReadOnlyBufferException if the output buffer is read-only
+ * @exception ShortBufferException if there is insufficient space in the
+ * output buffer
+ * @since 1.5
+ */
+ public final int update(ByteBuffer input, ByteBuffer output)
+ throws ShortBufferException {
+ checkCipherState();
+
+ if ((input == null) || (output == null)) {
+ throw new IllegalArgumentException("Buffers must not be null");
+ }
+ if (input == output) {
+ throw new IllegalArgumentException("Input and output buffers must "
+ + "not be the same object, consider using buffer.duplicate()");
+ }
+ if (output.isReadOnly()) {
+ throw new ReadOnlyBufferException();
+ }
+
+ updateProviderIfNeeded();
+ return spi.engineUpdate(input, output);
+ }
+
+ /**
+ * Finishes a multiple-part encryption or decryption operation, depending
+ * on how this cipher was initialized.
+ *
+ * <p>Input data that may have been buffered during a previous
+ * <code>update</code> operation is processed, with padding (if requested)
+ * being applied.
+ * If an AEAD mode such as GCM/CCM is being used, the authentication
+ * tag is appended in the case of encryption, or verified in the
+ * case of decryption.
+ * The result is stored in a new buffer.
+ *
+ * <p>Upon finishing, this method resets this cipher object to the state
+ * it was in when previously initialized via a call to <code>init</code>.
+ * That is, the object is reset and available to encrypt or decrypt
+ * (depending on the operation mode that was specified in the call to
+ * <code>init</code>) more data.
+ *
+ * <p>Note: if any exception is thrown, this cipher object may need to
+ * be reset before it can be used again.
+ *
+ * @return the new buffer with the result
+ *
+ * @exception IllegalStateException if this cipher is in a wrong state
+ * (e.g., has not been initialized)
+ * @exception IllegalBlockSizeException if this cipher is a block cipher,
+ * no padding has been requested (only in encryption mode), and the total
+ * input length of the data processed by this cipher is not a multiple of
+ * block size; or if this encryption algorithm is unable to
+ * process the input data provided.
+ * @exception BadPaddingException if this cipher is in decryption mode,
+ * and (un)padding has been requested, but the decrypted data is not
+ * bounded by the appropriate padding bytes
+ * @exception AEADBadTagException if this cipher is decrypting in an
+ * AEAD mode (such as GCM/CCM), and the received authentication tag
+ * does not match the calculated value
+ */
+ public final byte[] doFinal()
+ throws IllegalBlockSizeException, BadPaddingException {
+ checkCipherState();
+
+ updateProviderIfNeeded();
+ return spi.engineDoFinal(null, 0, 0);
+ }
+
+ /**
+ * Finishes a multiple-part encryption or decryption operation, depending
+ * on how this cipher was initialized.
+ *
+ * <p>Input data that may have been buffered during a previous
+ * <code>update</code> operation is processed, with padding (if requested)
+ * being applied.
+ * If an AEAD mode such as GCM/CCM is being used, the authentication
+ * tag is appended in the case of encryption, or verified in the
+ * case of decryption.
+ * The result is stored in the <code>output</code> buffer, starting at
+ * <code>outputOffset</code> inclusive.
+ *
+ * <p>If the <code>output</code> buffer is too small to hold the result,
+ * a <code>ShortBufferException</code> is thrown. In this case, repeat this
+ * call with a larger output buffer. Use
+ * {@link #getOutputSize(int) getOutputSize} to determine how big
+ * the output buffer should be.
+ *
+ * <p>Upon finishing, this method resets this cipher object to the state
+ * it was in when previously initialized via a call to <code>init</code>.
+ * That is, the object is reset and available to encrypt or decrypt
+ * (depending on the operation mode that was specified in the call to
+ * <code>init</code>) more data.
+ *
+ * <p>Note: if any exception is thrown, this cipher object may need to
+ * be reset before it can be used again.
+ *
+ * @param output the buffer for the result
+ * @param outputOffset the offset in <code>output</code> where the result
+ * is stored
+ *
+ * @return the number of bytes stored in <code>output</code>
+ *
+ * @exception IllegalStateException if this cipher is in a wrong state
+ * (e.g., has not been initialized)
+ * @exception IllegalBlockSizeException if this cipher is a block cipher,
+ * no padding has been requested (only in encryption mode), and the total
+ * input length of the data processed by this cipher is not a multiple of
+ * block size; or if this encryption algorithm is unable to
+ * process the input data provided.
+ * @exception ShortBufferException if the given output buffer is too small
+ * to hold the result
+ * @exception BadPaddingException if this cipher is in decryption mode,
+ * and (un)padding has been requested, but the decrypted data is not
+ * bounded by the appropriate padding bytes
+ * @exception AEADBadTagException if this cipher is decrypting in an
+ * AEAD mode (such as GCM/CCM), and the received authentication tag
+ * does not match the calculated value
+ */
+ public final int doFinal(byte[] output, int outputOffset)
+ throws IllegalBlockSizeException, ShortBufferException,
+ BadPaddingException {
+ checkCipherState();
+
+ // Input sanity check
+ if ((output == null) || (outputOffset < 0)) {
+ throw new IllegalArgumentException("Bad arguments");
+ }
+
+ updateProviderIfNeeded();
+ return spi.engineDoFinal(null, 0, 0, output, outputOffset);
+ }
+
+ /**
+ * Encrypts or decrypts data in a single-part operation, or finishes a
+ * multiple-part operation. The data is encrypted or decrypted,
+ * depending on how this cipher was initialized.
+ *
+ * <p>The bytes in the <code>input</code> buffer, and any input bytes that
+ * may have been buffered during a previous <code>update</code> operation,
+ * are processed, with padding (if requested) being applied.
+ * If an AEAD mode such as GCM/CCM is being used, the authentication
+ * tag is appended in the case of encryption, or verified in the
+ * case of decryption.
+ * The result is stored in a new buffer.
+ *
+ * <p>Upon finishing, this method resets this cipher object to the state
+ * it was in when previously initialized via a call to <code>init</code>.
+ * That is, the object is reset and available to encrypt or decrypt
+ * (depending on the operation mode that was specified in the call to
+ * <code>init</code>) more data.
+ *
+ * <p>Note: if any exception is thrown, this cipher object may need to
+ * be reset before it can be used again.
+ *
+ * @param input the input buffer
+ *
+ * @return the new buffer with the result
+ *
+ * @exception IllegalStateException if this cipher is in a wrong state
+ * (e.g., has not been initialized)
+ * @exception IllegalBlockSizeException if this cipher is a block cipher,
+ * no padding has been requested (only in encryption mode), and the total
+ * input length of the data processed by this cipher is not a multiple of
+ * block size; or if this encryption algorithm is unable to
+ * process the input data provided.
+ * @exception BadPaddingException if this cipher is in decryption mode,
+ * and (un)padding has been requested, but the decrypted data is not
+ * bounded by the appropriate padding bytes
+ * @exception AEADBadTagException if this cipher is decrypting in an
+ * AEAD mode (such as GCM/CCM), and the received authentication tag
+ * does not match the calculated value
+ */
+ public final byte[] doFinal(byte[] input)
+ throws IllegalBlockSizeException, BadPaddingException {
+ checkCipherState();
+
+ // Input sanity check
+ if (input == null) {
+ throw new IllegalArgumentException("Null input buffer");
+ }
+
+ updateProviderIfNeeded();
+ return spi.engineDoFinal(input, 0, input.length);
+ }
+
+ /**
+ * Encrypts or decrypts data in a single-part operation, or finishes a
+ * multiple-part operation. The data is encrypted or decrypted,
+ * depending on how this cipher was initialized.
+ *
+ * <p>The first <code>inputLen</code> bytes in the <code>input</code>
+ * buffer, starting at <code>inputOffset</code> inclusive, and any input
+ * bytes that may have been buffered during a previous <code>update</code>
+ * operation, are processed, with padding (if requested) being applied.
+ * If an AEAD mode such as GCM/CCM is being used, the authentication
+ * tag is appended in the case of encryption, or verified in the
+ * case of decryption.
+ * The result is stored in a new buffer.
+ *
+ * <p>Upon finishing, this method resets this cipher object to the state
+ * it was in when previously initialized via a call to <code>init</code>.
+ * That is, the object is reset and available to encrypt or decrypt
+ * (depending on the operation mode that was specified in the call to
+ * <code>init</code>) more data.
+ *
+ * <p>Note: if any exception is thrown, this cipher object may need to
+ * be reset before it can be used again.
+ *
+ * @param input the input buffer
+ * @param inputOffset the offset in <code>input</code> where the input
+ * starts
+ * @param inputLen the input length
+ *
+ * @return the new buffer with the result
+ *
+ * @exception IllegalStateException if this cipher is in a wrong state
+ * (e.g., has not been initialized)
+ * @exception IllegalBlockSizeException if this cipher is a block cipher,
+ * no padding has been requested (only in encryption mode), and the total
+ * input length of the data processed by this cipher is not a multiple of
+ * block size; or if this encryption algorithm is unable to
+ * process the input data provided.
+ * @exception BadPaddingException if this cipher is in decryption mode,
+ * and (un)padding has been requested, but the decrypted data is not
+ * bounded by the appropriate padding bytes
+ * @exception AEADBadTagException if this cipher is decrypting in an
+ * AEAD mode (such as GCM/CCM), and the received authentication tag
+ * does not match the calculated value
+ */
+ public final byte[] doFinal(byte[] input, int inputOffset, int inputLen)
+ throws IllegalBlockSizeException, BadPaddingException {
+ checkCipherState();
+
+ // Input sanity check
+ if (input == null || inputOffset < 0
+ || inputLen > (input.length - inputOffset) || inputLen < 0) {
+ throw new IllegalArgumentException("Bad arguments");
+ }
+
+ updateProviderIfNeeded();
+ return spi.engineDoFinal(input, inputOffset, inputLen);
+ }
+
+ /**
+ * Encrypts or decrypts data in a single-part operation, or finishes a
+ * multiple-part operation. The data is encrypted or decrypted,
+ * depending on how this cipher was initialized.
+ *
+ * <p>The first <code>inputLen</code> bytes in the <code>input</code>
+ * buffer, starting at <code>inputOffset</code> inclusive, and any input
+ * bytes that may have been buffered during a previous <code>update</code>
+ * operation, are processed, with padding (if requested) being applied.
+ * If an AEAD mode such as GCM/CCM is being used, the authentication
+ * tag is appended in the case of encryption, or verified in the
+ * case of decryption.
+ * The result is stored in the <code>output</code> buffer.
+ *
+ * <p>If the <code>output</code> buffer is too small to hold the result,
+ * a <code>ShortBufferException</code> is thrown. In this case, repeat this
+ * call with a larger output buffer. Use
+ * {@link #getOutputSize(int) getOutputSize} to determine how big
+ * the output buffer should be.
+ *
+ * <p>Upon finishing, this method resets this cipher object to the state
+ * it was in when previously initialized via a call to <code>init</code>.
+ * That is, the object is reset and available to encrypt or decrypt
+ * (depending on the operation mode that was specified in the call to
+ * <code>init</code>) more data.
+ *
+ * <p>Note: if any exception is thrown, this cipher object may need to
+ * be reset before it can be used again.
+ *
+ * <p>Note: this method should be copy-safe, which means the
+ * <code>input</code> and <code>output</code> buffers can reference
+ * the same byte array and no unprocessed input data is overwritten
+ * when the result is copied into the output buffer.
+ *
+ * @param input the input buffer
+ * @param inputOffset the offset in <code>input</code> where the input
+ * starts
+ * @param inputLen the input length
+ * @param output the buffer for the result
+ *
+ * @return the number of bytes stored in <code>output</code>
+ *
+ * @exception IllegalStateException if this cipher is in a wrong state
+ * (e.g., has not been initialized)
+ * @exception IllegalBlockSizeException if this cipher is a block cipher,
+ * no padding has been requested (only in encryption mode), and the total
+ * input length of the data processed by this cipher is not a multiple of
+ * block size; or if this encryption algorithm is unable to
+ * process the input data provided.
+ * @exception ShortBufferException if the given output buffer is too small
+ * to hold the result
+ * @exception BadPaddingException if this cipher is in decryption mode,
+ * and (un)padding has been requested, but the decrypted data is not
+ * bounded by the appropriate padding bytes
+ * @exception AEADBadTagException if this cipher is decrypting in an
+ * AEAD mode (such as GCM/CCM), and the received authentication tag
+ * does not match the calculated value
+ */
+ public final int doFinal(byte[] input, int inputOffset, int inputLen,
+ byte[] output)
+ throws ShortBufferException, IllegalBlockSizeException,
+ BadPaddingException {
+ checkCipherState();
+
+ // Input sanity check
+ if (input == null || inputOffset < 0
+ || inputLen > (input.length - inputOffset) || inputLen < 0) {
+ throw new IllegalArgumentException("Bad arguments");
+ }
+
+ updateProviderIfNeeded();
+ return spi.engineDoFinal(input, inputOffset, inputLen,
+ output, 0);
+ }
+
+ /**
+ * Encrypts or decrypts data in a single-part operation, or finishes a
+ * multiple-part operation. The data is encrypted or decrypted,
+ * depending on how this cipher was initialized.
+ *
+ * <p>The first <code>inputLen</code> bytes in the <code>input</code>
+ * buffer, starting at <code>inputOffset</code> inclusive, and any input
+ * bytes that may have been buffered during a previous
+ * <code>update</code> operation, are processed, with padding
+ * (if requested) being applied.
+ * If an AEAD mode such as GCM/CCM is being used, the authentication
+ * tag is appended in the case of encryption, or verified in the
+ * case of decryption.
+ * The result is stored in the <code>output</code> buffer, starting at
+ * <code>outputOffset</code> inclusive.
+ *
+ * <p>If the <code>output</code> buffer is too small to hold the result,
+ * a <code>ShortBufferException</code> is thrown. In this case, repeat this
+ * call with a larger output buffer. Use
+ * {@link #getOutputSize(int) getOutputSize} to determine how big
+ * the output buffer should be.
+ *
+ * <p>Upon finishing, this method resets this cipher object to the state
+ * it was in when previously initialized via a call to <code>init</code>.
+ * That is, the object is reset and available to encrypt or decrypt
+ * (depending on the operation mode that was specified in the call to
+ * <code>init</code>) more data.
+ *
+ * <p>Note: if any exception is thrown, this cipher object may need to
+ * be reset before it can be used again.
+ *
+ * <p>Note: this method should be copy-safe, which means the
+ * <code>input</code> and <code>output</code> buffers can reference
+ * the same byte array and no unprocessed input data is overwritten
+ * when the result is copied into the output buffer.
+ *
+ * @param input the input buffer
+ * @param inputOffset the offset in <code>input</code> where the input
+ * starts
+ * @param inputLen the input length
+ * @param output the buffer for the result
+ * @param outputOffset the offset in <code>output</code> where the result
+ * is stored
+ *
+ * @return the number of bytes stored in <code>output</code>
+ *
+ * @exception IllegalStateException if this cipher is in a wrong state
+ * (e.g., has not been initialized)
+ * @exception IllegalBlockSizeException if this cipher is a block cipher,
+ * no padding has been requested (only in encryption mode), and the total
+ * input length of the data processed by this cipher is not a multiple of
+ * block size; or if this encryption algorithm is unable to
+ * process the input data provided.
+ * @exception ShortBufferException if the given output buffer is too small
+ * to hold the result
+ * @exception BadPaddingException if this cipher is in decryption mode,
+ * and (un)padding has been requested, but the decrypted data is not
+ * bounded by the appropriate padding bytes
+ * @exception AEADBadTagException if this cipher is decrypting in an
+ * AEAD mode (such as GCM/CCM), and the received authentication tag
+ * does not match the calculated value
+ */
+ public final int doFinal(byte[] input, int inputOffset, int inputLen,
+ byte[] output, int outputOffset)
+ throws ShortBufferException, IllegalBlockSizeException,
+ BadPaddingException {
+ checkCipherState();
+
+ // Input sanity check
+ if (input == null || inputOffset < 0
+ || inputLen > (input.length - inputOffset) || inputLen < 0
+ || outputOffset < 0) {
+ throw new IllegalArgumentException("Bad arguments");
+ }
+
+ updateProviderIfNeeded();
+ return spi.engineDoFinal(input, inputOffset, inputLen,
+ output, outputOffset);
+ }
+
+ /**
+ * Encrypts or decrypts data in a single-part operation, or finishes a
+ * multiple-part operation. The data is encrypted or decrypted,
+ * depending on how this cipher was initialized.
+ *
+ * <p>All <code>input.remaining()</code> bytes starting at
+ * <code>input.position()</code> are processed.
+ * If an AEAD mode such as GCM/CCM is being used, the authentication
+ * tag is appended in the case of encryption, or verified in the
+ * case of decryption.
+ * The result is stored in the output buffer.
+ * Upon return, the input buffer's position will be equal
+ * to its limit; its limit will not have changed. The output buffer's
+ * position will have advanced by n, where n is the value returned
+ * by this method; the output buffer's limit will not have changed.
+ *
+ * <p>If <code>output.remaining()</code> bytes are insufficient to
+ * hold the result, a <code>ShortBufferException</code> is thrown.
+ * In this case, repeat this call with a larger output buffer. Use
+ * {@link #getOutputSize(int) getOutputSize} to determine how big
+ * the output buffer should be.
+ *
+ * <p>Upon finishing, this method resets this cipher object to the state
+ * it was in when previously initialized via a call to <code>init</code>.
+ * That is, the object is reset and available to encrypt or decrypt
+ * (depending on the operation mode that was specified in the call to
+ * <code>init</code>) more data.
+ *
+ * <p>Note: if any exception is thrown, this cipher object may need to
+ * be reset before it can be used again.
+ *
+ * <p>Note: this method should be copy-safe, which means the
+ * <code>input</code> and <code>output</code> buffers can reference
+ * the same byte array and no unprocessed input data is overwritten
+ * when the result is copied into the output buffer.
+ *
+ * @param input the input ByteBuffer
+ * @param output the output ByteBuffer
+ *
+ * @return the number of bytes stored in <code>output</code>
+ *
+ * @exception IllegalStateException if this cipher is in a wrong state
+ * (e.g., has not been initialized)
+ * @exception IllegalArgumentException if input and output are the
+ * same object
+ * @exception ReadOnlyBufferException if the output buffer is read-only
+ * @exception IllegalBlockSizeException if this cipher is a block cipher,
+ * no padding has been requested (only in encryption mode), and the total
+ * input length of the data processed by this cipher is not a multiple of
+ * block size; or if this encryption algorithm is unable to
+ * process the input data provided.
+ * @exception ShortBufferException if there is insufficient space in the
+ * output buffer
+ * @exception BadPaddingException if this cipher is in decryption mode,
+ * and (un)padding has been requested, but the decrypted data is not
+ * bounded by the appropriate padding bytes
+ * @exception AEADBadTagException if this cipher is decrypting in an
+ * AEAD mode (such as GCM/CCM), and the received authentication tag
+ * does not match the calculated value
+ *
+ * @since 1.5
+ */
+ public final int doFinal(ByteBuffer input, ByteBuffer output)
+ throws ShortBufferException, IllegalBlockSizeException,
+ BadPaddingException {
+ checkCipherState();
+
+ if ((input == null) || (output == null)) {
+ throw new IllegalArgumentException("Buffers must not be null");
+ }
+ if (input == output) {
+ throw new IllegalArgumentException("Input and output buffers must "
+ + "not be the same object, consider using buffer.duplicate()");
+ }
+ if (output.isReadOnly()) {
+ throw new ReadOnlyBufferException();
+ }
+
+ updateProviderIfNeeded();
+ return spi.engineDoFinal(input, output);
+ }
+
+ /**
+ * Wrap a key.
+ *
+ * @param key the key to be wrapped.
+ *
+ * @return the wrapped key.
+ *
+ * @exception IllegalStateException if this cipher is in a wrong
+ * state (e.g., has not been initialized).
+ *
+ * @exception IllegalBlockSizeException if this cipher is a block
+ * cipher, no padding has been requested, and the length of the
+ * encoding of the key to be wrapped is not a
+ * multiple of the block size.
+ *
+ * @exception InvalidKeyException if it is impossible or unsafe to
+ * wrap the key with this cipher (e.g., a hardware protected key is
+ * being passed to a software-only cipher).
+ *
+ * @throws UnsupportedOperationException if the corresponding method in the
+ * {@code CipherSpi} is not supported.
+ */
+ public final byte[] wrap(Key key)
+ throws IllegalBlockSizeException, InvalidKeyException {
+ if (!(this instanceof NullCipher)) {
+ if (!initialized) {
+ throw new IllegalStateException("Cipher not initialized");
+ }
+ if (opmode != Cipher.WRAP_MODE) {
+ throw new IllegalStateException("Cipher not initialized " +
+ "for wrapping keys");
+ }
+ }
+
+ updateProviderIfNeeded();
+ return spi.engineWrap(key);
+ }
+
+ /**
+ * Unwrap a previously wrapped key.
+ *
+ * @param wrappedKey the key to be unwrapped.
+ *
+ * @param wrappedKeyAlgorithm the algorithm associated with the wrapped
+ * key.
+ *
+ * @param wrappedKeyType the type of the wrapped key. This must be one of
+ * <code>SECRET_KEY</code>, <code>PRIVATE_KEY</code>, or
+ * <code>PUBLIC_KEY</code>.
+ *
+ * @return the unwrapped key.
+ *
+ * @exception IllegalStateException if this cipher is in a wrong state
+ * (e.g., has not been initialized).
+ *
+ * @exception NoSuchAlgorithmException if no installed providers
+ * can create keys of type <code>wrappedKeyType</code> for the
+ * <code>wrappedKeyAlgorithm</code>.
+ *
+ * @exception InvalidKeyException if <code>wrappedKey</code> does not
+ * represent a wrapped key of type <code>wrappedKeyType</code> for
+ * the <code>wrappedKeyAlgorithm</code>.
+ *
+ * @throws UnsupportedOperationException if the corresponding method in the
+ * {@code CipherSpi} is not supported.
+ */
+ public final Key unwrap(byte[] wrappedKey,
+ String wrappedKeyAlgorithm,
+ int wrappedKeyType)
+ throws InvalidKeyException, NoSuchAlgorithmException {
+
+ if (!(this instanceof NullCipher)) {
+ if (!initialized) {
+ throw new IllegalStateException("Cipher not initialized");
+ }
+ if (opmode != Cipher.UNWRAP_MODE) {
+ throw new IllegalStateException("Cipher not initialized " +
+ "for unwrapping keys");
+ }
+ }
+ if ((wrappedKeyType != SECRET_KEY) &&
+ (wrappedKeyType != PRIVATE_KEY) &&
+ (wrappedKeyType != PUBLIC_KEY)) {
+ throw new InvalidParameterException("Invalid key type");
+ }
+
+ updateProviderIfNeeded();
+ return spi.engineUnwrap(wrappedKey,
+ wrappedKeyAlgorithm,
+ wrappedKeyType);
+ }
+
+ private AlgorithmParameterSpec getAlgorithmParameterSpec(
+ AlgorithmParameters params)
+ throws InvalidParameterSpecException {
+ if (params == null) {
+ return null;
+ }
+
+ String alg = params.getAlgorithm().toUpperCase(Locale.ENGLISH);
+
+ if (alg.equalsIgnoreCase("RC2")) {
+ return params.getParameterSpec(RC2ParameterSpec.class);
+ }
+
+ if (alg.equalsIgnoreCase("RC5")) {
+ return params.getParameterSpec(RC5ParameterSpec.class);
+ }
+
+ if (alg.startsWith("PBE")) {
+ return params.getParameterSpec(PBEParameterSpec.class);
+ }
+
+ if (alg.startsWith("DES")) {
+ return params.getParameterSpec(IvParameterSpec.class);
+ }
+ return null;
+ }
+
+ /**
+ * Returns the maximum key length for the specified transformation
+ * according to the installed JCE jurisdiction policy files. If
+ * JCE unlimited strength jurisdiction policy files are installed,
+ * Integer.MAX_VALUE will be returned.
+ * For more information on default key size in JCE jurisdiction
+ * policy files, please see Appendix E in the
+ * <a href=
+ * "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppC">
+ * Java Cryptography Architecture Reference Guide</a>.
+ *
+ * @param transformation the cipher transformation.
+ * @return the maximum key length in bits or Integer.MAX_VALUE.
+ * @exception NullPointerException if <code>transformation</code> is null.
+ * @exception NoSuchAlgorithmException if <code>transformation</code>
+ * is not a valid transformation, i.e. in the form of "algorithm" or
+ * "algorithm/mode/padding".
+ * @since 1.5
+ */
+ public static final int getMaxAllowedKeyLength(String transformation)
+ throws NoSuchAlgorithmException {
+ // Android-changed: Remove references to CryptoPermission.
+ // Throw early if transformation == null or isn't valid.
+ //
+ // CryptoPermission cp = getConfiguredPermission(transformation);
+ // return cp.getMaxAllowedKeyLength();
+ if (transformation == null) {
+ throw new NullPointerException("transformation == null");
+ }
+ // Throws NoSuchAlgorithmException if necessary.
+ tokenizeTransformation(transformation);
+ return Integer.MAX_VALUE;
+ }
+
+ /**
+ * Returns an AlgorithmParameterSpec object which contains
+ * the maximum cipher parameter value according to the
+ * jurisdiction policy file. If JCE unlimited strength jurisdiction
+ * policy files are installed or there is no maximum limit on the
+ * parameters for the specified transformation in the policy file,
+ * null will be returned.
+ *
+ * @param transformation the cipher transformation.
+ * @return an AlgorithmParameterSpec which holds the maximum
+ * value or null.
+ * @exception NullPointerException if <code>transformation</code>
+ * is null.
+ * @exception NoSuchAlgorithmException if <code>transformation</code>
+ * is not a valid transformation, i.e. in the form of "algorithm" or
+ * "algorithm/mode/padding".
+ * @since 1.5
+ */
+ public static final AlgorithmParameterSpec getMaxAllowedParameterSpec(
+ String transformation) throws NoSuchAlgorithmException {
+ // Android-changed: Remove references to CryptoPermission.
+ // Throw early if transformation == null or isn't valid.
+ //
+ // CryptoPermission cp = getConfiguredPermission(transformation);
+ // return cp.getAlgorithmParameterSpec();
+ if (transformation == null) {
+ throw new NullPointerException("transformation == null");
+ }
+ // Throws NoSuchAlgorithmException if necessary.
+ tokenizeTransformation(transformation);
+ return null;
+ }
+
+ /**
+ * Continues a multi-part update of the Additional Authentication
+ * Data (AAD).
+ * <p>
+ * Calls to this method provide AAD to the cipher when operating in
+ * modes such as AEAD (GCM/CCM). If this cipher is operating in
+ * either GCM or CCM mode, all AAD must be supplied before beginning
+ * operations on the ciphertext (via the {@code update} and {@code
+ * doFinal} methods).
+ *
+ * @param src the buffer containing the Additional Authentication Data
+ *
+ * @throws IllegalArgumentException if the {@code src}
+ * byte array is null
+ * @throws IllegalStateException if this cipher is in a wrong state
+ * (e.g., has not been initialized), does not accept AAD, or if
+ * operating in either GCM or CCM mode and one of the {@code update}
+ * methods has already been called for the active
+ * encryption/decryption operation
+ * @throws UnsupportedOperationException if the corresponding method
+ * in the {@code CipherSpi} has not been overridden by an
+ * implementation
+ *
+ * @since 1.7
+ */
+ public final void updateAAD(byte[] src) {
+ if (src == null) {
+ throw new IllegalArgumentException("src buffer is null");
+ }
+
+ updateAAD(src, 0, src.length);
+ }
+
+ /**
+ * Continues a multi-part update of the Additional Authentication
+ * Data (AAD), using a subset of the provided buffer.
+ * <p>
+ * Calls to this method provide AAD to the cipher when operating in
+ * modes such as AEAD (GCM/CCM). If this cipher is operating in
+ * either GCM or CCM mode, all AAD must be supplied before beginning
+ * operations on the ciphertext (via the {@code update} and {@code
+ * doFinal} methods).
+ *
+ * @param src the buffer containing the AAD
+ * @param offset the offset in {@code src} where the AAD input starts
+ * @param len the number of AAD bytes
+ *
+ * @throws IllegalArgumentException if the {@code src}
+ * byte array is null, or the {@code offset} or {@code length}
+ * is less than 0, or the sum of the {@code offset} and
+ * {@code len} is greater than the length of the
+ * {@code src} byte array
+ * @throws IllegalStateException if this cipher is in a wrong state
+ * (e.g., has not been initialized), does not accept AAD, or if
+ * operating in either GCM or CCM mode and one of the {@code update}
+ * methods has already been called for the active
+ * encryption/decryption operation
+ * @throws UnsupportedOperationException if the corresponding method
+ * in the {@code CipherSpi} has not been overridden by an
+ * implementation
+ *
+ * @since 1.7
+ */
+ public final void updateAAD(byte[] src, int offset, int len) {
+ checkCipherState();
+
+ // Input sanity check
+ if ((src == null) || (offset < 0) || (len < 0)
+ || ((len + offset) > src.length)) {
+ throw new IllegalArgumentException("Bad arguments");
+ }
+
+ updateProviderIfNeeded();
+ if (len == 0) {
+ return;
+ }
+ spi.engineUpdateAAD(src, offset, len);
+ }
+
+ /**
+ * Continues a multi-part update of the Additional Authentication
+ * Data (AAD).
+ * <p>
+ * Calls to this method provide AAD to the cipher when operating in
+ * modes such as AEAD (GCM/CCM). If this cipher is operating in
+ * either GCM or CCM mode, all AAD must be supplied before beginning
+ * operations on the ciphertext (via the {@code update} and {@code
+ * doFinal} methods).
+ * <p>
+ * All {@code src.remaining()} bytes starting at
+ * {@code src.position()} are processed.
+ * Upon return, the input buffer's position will be equal
+ * to its limit; its limit will not have changed.
+ *
+ * @param src the buffer containing the AAD
+ *
+ * @throws IllegalArgumentException if the {@code src ByteBuffer}
+ * is null
+ * @throws IllegalStateException if this cipher is in a wrong state
+ * (e.g., has not been initialized), does not accept AAD, or if
+ * operating in either GCM or CCM mode and one of the {@code update}
+ * methods has already been called for the active
+ * encryption/decryption operation
+ * @throws UnsupportedOperationException if the corresponding method
+ * in the {@code CipherSpi} has not been overridden by an
+ * implementation
+ *
+ * @since 1.7
+ */
+ public final void updateAAD(ByteBuffer src) {
+ checkCipherState();
+
+ // Input sanity check
+ if (src == null) {
+ throw new IllegalArgumentException("src ByteBuffer is null");
+ }
+
+ updateProviderIfNeeded();
+ if (src.remaining() == 0) {
+ return;
+ }
+ spi.engineUpdateAAD(src);
+ }
+
+ // BEGIN Android-added: Bulk of the new provider implementation.
+ // See note at top of class.
+ /**
+ * Returns the {@code CipherSpi} backing this {@code Cipher} or {@code null} if no
+ * {@code CipherSpi} is backing this {@code Cipher}.
+ *
+ * @hide
+ */
+ public CipherSpi getCurrentSpi() {
+ return spi;
+ }
+
+ /** The attribute used for supported paddings. */
+ private static final String ATTRIBUTE_PADDINGS = "SupportedPaddings";
+
+ /** The attribute used for supported modes. */
+ private static final String ATTRIBUTE_MODES = "SupportedModes";
+
+ /**
+ * If the attribute listed exists, check that it matches the regular
+ * expression.
+ */
+ static boolean matchAttribute(Provider.Service service, String attr, String value) {
+ if (value == null) {
+ return true;
+ }
+ final String pattern = service.getAttribute(attr);
+ if (pattern == null) {
+ return true;
+ }
+ final String valueUc = value.toUpperCase(Locale.US);
+ return valueUc.matches(pattern.toUpperCase(Locale.US));
+ }
+
+ /** Items that need to be set on the Cipher instance. */
+ enum NeedToSet {
+ NONE, MODE, PADDING, BOTH,
+ }
+
+ /**
+ * Expresses the various types of transforms that may be used during
+ * initialization.
+ */
+ static class Transform {
+ private final String name;
+ private final NeedToSet needToSet;
+
+ public Transform(String name, NeedToSet needToSet) {
+ this.name = name;
+ this.needToSet = needToSet;
+ }
+ }
+
+ /**
+ * Keeps track of the possible arguments to {@code Cipher#init(...)}.
+ */
+ static class InitParams {
+ final InitType initType;
+ final int opmode;
+ final Key key;
+ final SecureRandom random;
+ final AlgorithmParameterSpec spec;
+ final AlgorithmParameters params;
+
+ InitParams(InitType initType, int opmode, Key key, SecureRandom random,
+ AlgorithmParameterSpec spec, AlgorithmParameters params) {
+ this.initType = initType;
+ this.opmode = opmode;
+ this.key = key;
+ this.random = random;
+ this.spec = spec;
+ this.params = params;
+ }
+ }
+
+ /**
+ * Used to keep track of which underlying {@code CipherSpi#engineInit(...)}
+ * variant to call when testing suitability.
+ */
+ static enum InitType {
+ KEY, ALGORITHM_PARAMS, ALGORITHM_PARAM_SPEC,
+ }
+
+ class SpiAndProviderUpdater {
+ /**
+ * Lock held while the SPI is initializing.
+ */
+ private final Object initSpiLock = new Object();
+
+ /**
+ * The provider specified when instance created.
+ */
+ private final Provider specifiedProvider;
+
+ /**
+ * The SPI implementation.
+ */
+ private final CipherSpi specifiedSpi;
+
+ SpiAndProviderUpdater(Provider specifiedProvider, CipherSpi specifiedSpi) {
+ this.specifiedProvider = specifiedProvider;
+ this.specifiedSpi = specifiedSpi;
+ }
+
+ void setCipherSpiImplAndProvider(CipherSpi cipherSpi, Provider provider) {
+ Cipher.this.spi = cipherSpi;
+ Cipher.this.provider = provider;
+ }
+
+ /**
+ * Makes sure a CipherSpi that matches this type is selected. If
+ * {@code key != null} then it assumes that a suitable provider exists for
+ * this instance (used by {@link Cipher#init}. If the {@code initParams} is passed
+ * in, then the {@code CipherSpi} returned will be initialized.
+ *
+ * @throws InvalidKeyException if the specified key cannot be used to
+ * initialize this cipher.
+ */
+ CipherSpiAndProvider updateAndGetSpiAndProvider(
+ InitParams initParams,
+ CipherSpi spiImpl,
+ Provider provider)
+ throws InvalidKeyException, InvalidAlgorithmParameterException {
+ if (specifiedSpi != null) {
+ return new CipherSpiAndProvider(specifiedSpi, provider);
+ }
+ synchronized (initSpiLock) {
+ // This is not only a matter of performance. Many methods like update, doFinal, etc.
+ // call {@code #getSpi()} (ie, {@code #getSpi(null /* params */)}) and without this
+ // shortcut they would override an spi that was chosen using the key.
+ if (spiImpl != null && initParams == null) {
+ return new CipherSpiAndProvider(spiImpl, provider);
+ }
+ final CipherSpiAndProvider sap = tryCombinations(
+ initParams, specifiedProvider, tokenizedTransformation);
+ if (sap == null) {
+ throw new ProviderException("No provider found for "
+ + Arrays.toString(tokenizedTransformation));
+ }
+ setCipherSpiImplAndProvider(sap.cipherSpi, sap.provider);
+ return new CipherSpiAndProvider(sap.cipherSpi, sap.provider);
+ }
+ }
+
+ /**
+ * Convenience call when the Key is not available.
+ */
+ CipherSpiAndProvider updateAndGetSpiAndProvider(CipherSpi spiImpl, Provider provider) {
+ try {
+ return updateAndGetSpiAndProvider(null, spiImpl, provider);
+ } catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
+ throw new ProviderException("Exception thrown when params == null", e);
+ }
+ }
+
+ CipherSpi getCurrentSpi(CipherSpi spiImpl) {
+ if (specifiedSpi != null) {
+ return specifiedSpi;
+ }
+
+ synchronized (initSpiLock) {
+ return spiImpl;
+ }
+ }
+ }
+
+ /**
+ * Tries to find the correct {@code Cipher} transform to use. Returns a
+ * {@link org.apache.harmony.security.fortress.Engine.SpiAndProvider}, throws the first exception that was
+ * encountered during attempted initialization, or {@code null} if there are
+ * no providers that support the {@code initParams}.
+ * <p>
+ * {@code tokenizedTransformation} must be in the format returned by
+ * {@link Cipher#checkTransformation(String)}. The combinations of mode strings
+ * tried are as follows:
+ * <ul>
+ * <li><code>[cipher]/[mode]/[padding]</code>
+ * <li><code>[cipher]/[mode]</code>
+ * <li><code>[cipher]//[padding]</code>
+ * <li><code>[cipher]</code>
+ * </ul>
+ * {@code services} is a list of cipher services. Needs to be non-null only if
+ * {@code provider != null}
+ */
+ static CipherSpiAndProvider tryCombinations(InitParams initParams, Provider provider,
+ String[] tokenizedTransformation)
+ throws InvalidKeyException,
+ InvalidAlgorithmParameterException {
+ // Enumerate all the transforms we need to try
+ ArrayList<Transform> transforms = new ArrayList<Transform>();
+ if (tokenizedTransformation[1] != null && tokenizedTransformation[2] != null) {
+ transforms.add(new Transform(tokenizedTransformation[0] + "/" + tokenizedTransformation[1] + "/"
+ + tokenizedTransformation[2], NeedToSet.NONE));
+ }
+ if (tokenizedTransformation[1] != null) {
+ transforms.add(new Transform(tokenizedTransformation[0] + "/" + tokenizedTransformation[1],
+ NeedToSet.PADDING));
+ }
+ if (tokenizedTransformation[2] != null) {
+ transforms.add(new Transform(tokenizedTransformation[0] + "//" + tokenizedTransformation[2],
+ NeedToSet.MODE));
+ }
+ transforms.add(new Transform(tokenizedTransformation[0], NeedToSet.BOTH));
+
+ // Try each of the transforms and keep track of the first exception
+ // encountered.
+ Exception cause = null;
+
+ if (provider != null) {
+ for (Transform transform : transforms) {
+ Provider.Service service = provider.getService("Cipher", transform.name);
+ if (service == null) {
+ continue;
+ }
+ return tryTransformWithProvider(initParams, tokenizedTransformation, transform.needToSet,
+ service);
+ }
+ } else {
+ for (Provider prov : Security.getProviders()) {
+ for (Transform transform : transforms) {
+ Provider.Service service = prov.getService("Cipher", transform.name);
+ if (service == null) {
+ continue;
+ }
+
+ if (initParams == null || initParams.key == null
+ || service.supportsParameter(initParams.key)) {
+ try {
+ CipherSpiAndProvider sap = tryTransformWithProvider(initParams,
+ tokenizedTransformation, transform.needToSet, service);
+ if (sap != null) {
+ return sap;
+ }
+ } catch (Exception e) {
+ if (cause == null) {
+ cause = e;
+ }
+ }
+ }
+ }
+ }
+ }
+ if (cause instanceof InvalidKeyException) {
+ throw (InvalidKeyException) cause;
+ } else if (cause instanceof InvalidAlgorithmParameterException) {
+ throw (InvalidAlgorithmParameterException) cause;
+ } else if (cause instanceof RuntimeException) {
+ throw (RuntimeException) cause;
+ } else if (cause != null) {
+ throw new InvalidKeyException("No provider can be initialized with given key", cause);
+ } else if (initParams == null || initParams.key == null) {
+ return null;
+ } else {
+ // Since the key is not null, a suitable provider exists,
+ // and it is an InvalidKeyException.
+ throw new InvalidKeyException(
+ "No provider offers " + Arrays.toString(tokenizedTransformation) + " for "
+ + initParams.key.getAlgorithm() + " key of class "
+ + initParams.key.getClass().getName() + " and export format "
+ + initParams.key.getFormat());
+ }
+ }
+
+ static class CipherSpiAndProvider {
+ CipherSpi cipherSpi;
+ Provider provider;
+
+ CipherSpiAndProvider(CipherSpi cipherSpi, Provider provider) {
+ this.cipherSpi = cipherSpi;
+ this.provider = provider;
+ }
+ }
+
+ /**
+ * Tries to initialize the {@code Cipher} from a given {@code service}. If
+ * initialization is successful, the initialized {@code spi} is returned. If
+ * the {@code service} cannot be initialized with the specified
+ * {@code initParams}, then it's expected to throw
+ * {@code InvalidKeyException} or {@code InvalidAlgorithmParameterException}
+ * as a hint to the caller that it should continue searching for a
+ * {@code Service} that will work.
+ */
+ static CipherSpiAndProvider tryTransformWithProvider(InitParams initParams,
+ String[] tokenizedTransformation, NeedToSet type, Provider.Service service)
+ throws InvalidKeyException, InvalidAlgorithmParameterException {
+ try {
+ /*
+ * Check to see if the Cipher even supports the attributes before
+ * trying to instantiate it.
+ */
+ if (!matchAttribute(service, ATTRIBUTE_MODES, tokenizedTransformation[1])
+ || !matchAttribute(service, ATTRIBUTE_PADDINGS, tokenizedTransformation[2])) {
+ return null;
+ }
+
+ CipherSpiAndProvider sap = new CipherSpiAndProvider(
+ (CipherSpi) service.newInstance(null), service.getProvider());
+ if (sap.cipherSpi == null || sap.provider == null) {
+ return null;
+ }
+ CipherSpi spi = sap.cipherSpi;
+ if (((type == NeedToSet.MODE) || (type == NeedToSet.BOTH))
+ && (tokenizedTransformation[1] != null)) {
+ spi.engineSetMode(tokenizedTransformation[1]);
+ }
+ if (((type == NeedToSet.PADDING) || (type == NeedToSet.BOTH))
+ && (tokenizedTransformation[2] != null)) {
+ spi.engineSetPadding(tokenizedTransformation[2]);
+ }
+
+ if (initParams != null) {
+ switch (initParams.initType) {
+ case ALGORITHM_PARAMS:
+ spi.engineInit(initParams.opmode, initParams.key, initParams.params,
+ initParams.random);
+ break;
+ case ALGORITHM_PARAM_SPEC:
+ spi.engineInit(initParams.opmode, initParams.key, initParams.spec,
+ initParams.random);
+ break;
+ case KEY:
+ spi.engineInit(initParams.opmode, initParams.key, initParams.random);
+ break;
+ default:
+ throw new AssertionError("This should never be reached");
+ }
+ }
+ return new CipherSpiAndProvider(spi, sap.provider);
+ } catch (NoSuchAlgorithmException ignored) {
+ } catch (NoSuchPaddingException ignored) {
+ }
+ return null;
+ }
+ // END Android-added: Bulk of the new provider implementation.
+}
diff --git a/javax/crypto/CipherInputStream.java b/javax/crypto/CipherInputStream.java
new file mode 100644
index 0000000..8cbda3b
--- /dev/null
+++ b/javax/crypto/CipherInputStream.java
@@ -0,0 +1,357 @@
+/*
+ * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.crypto;
+
+import java.io.InputStream;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import javax.crypto.BadPaddingException;
+import javax.crypto.IllegalBlockSizeException;
+
+/**
+ * A CipherInputStream is composed of an InputStream and a Cipher so
+ * that read() methods return data that are read in from the
+ * underlying InputStream but have been additionally processed by the
+ * Cipher. The Cipher must be fully initialized before being used by
+ * a CipherInputStream.
+ *
+ * <p> For example, if the Cipher is initialized for decryption, the
+ * CipherInputStream will attempt to read in data and decrypt them,
+ * before returning the decrypted data.
+ *
+ * <p> This class adheres strictly to the semantics, especially the
+ * failure semantics, of its ancestor classes
+ * java.io.FilterInputStream and java.io.InputStream. This class has
+ * exactly those methods specified in its ancestor classes, and
+ * overrides them all. Moreover, this class catches all exceptions
+ * that are not thrown by its ancestor classes. In particular, the
+ * <code>skip</code> method skips, and the <code>available</code>
+ * method counts only data that have been processed by the encapsulated Cipher.
+ *
+ * <p> It is crucial for a programmer using this class not to use
+ * methods that are not defined or overriden in this class (such as a
+ * new method or constructor that is later added to one of the super
+ * classes), because the design and implementation of those methods
+ * are unlikely to have considered security impact with regard to
+ * CipherInputStream.
+ *
+ * @author Li Gong
+ * @see java.io.InputStream
+ * @see java.io.FilterInputStream
+ * @see javax.crypto.Cipher
+ * @see javax.crypto.CipherOutputStream
+ *
+ * @since 1.4
+ */
+
+public class CipherInputStream extends FilterInputStream {
+
+ // the cipher engine to use to process stream data
+ private Cipher cipher;
+
+ // the underlying input stream
+ private InputStream input;
+
+ /* the buffer holding data that have been read in from the
+ underlying stream, but have not been processed by the cipher
+ engine. the size 512 bytes is somewhat randomly chosen */
+ private byte[] ibuffer = new byte[512];
+
+ // having reached the end of the underlying input stream
+ private boolean done = false;
+
+ /* the buffer holding data that have been processed by the cipher
+ engine, but have not been read out */
+ private byte[] obuffer;
+ // the offset pointing to the next "new" byte
+ private int ostart = 0;
+ // the offset pointing to the last "new" byte
+ private int ofinish = 0;
+ // stream status
+ private boolean closed = false;
+
+ /**
+ * private convenience function.
+ *
+ * Entry condition: ostart = ofinish
+ *
+ * Exit condition: ostart <= ofinish
+ *
+ * return (ofinish-ostart) (we have this many bytes for you)
+ * return 0 (no data now, but could have more later)
+ * return -1 (absolutely no more data)
+ *
+ * Note: Exceptions are only thrown after the stream is completely read.
+ * For AEAD ciphers a read() of any length will internally cause the
+ * whole stream to be read fully and verify the authentication tag before
+ * returning decrypted data or exceptions.
+ */
+ private int getMoreData() throws IOException {
+ // Android-changed: The method was creating a new object every time update(byte[], int, int)
+ // or doFinal() was called resulting in the old object being GCed. With do(byte[], int) and
+ // update(byte[], int, int, byte[], int), we use already initialized obuffer.
+ if (done) return -1;
+ ofinish = 0;
+ ostart = 0;
+ int expectedOutputSize = cipher.getOutputSize(ibuffer.length);
+ if (obuffer == null || expectedOutputSize > obuffer.length) {
+ obuffer = new byte[expectedOutputSize];
+ }
+ int readin = input.read(ibuffer);
+ if (readin == -1) {
+ done = true;
+ try {
+ // doFinal resets the cipher and it is the final call that is made. If there isn't
+ // any more byte available, it returns 0. In case of any exception is raised,
+ // obuffer will get reset and therefore, it is equivalent to no bytes returned.
+ ofinish = cipher.doFinal(obuffer, 0);
+ } catch (IllegalBlockSizeException | BadPaddingException e) {
+ obuffer = null;
+ throw new IOException(e);
+ } catch (ShortBufferException e) {
+ obuffer = null;
+ throw new IllegalStateException("ShortBufferException is not expected", e);
+ }
+ } else {
+ // update returns number of bytes stored in obuffer.
+ try {
+ ofinish = cipher.update(ibuffer, 0, readin, obuffer, 0);
+ } catch (IllegalStateException e) {
+ obuffer = null;
+ throw e;
+ } catch (ShortBufferException e) {
+ // Should not reset the value of ofinish as the cipher is still not invalidated.
+ obuffer = null;
+ throw new IllegalStateException("ShortBufferException is not expected", e);
+ }
+ }
+ return ofinish;
+ }
+
+ /**
+ * Constructs a CipherInputStream from an InputStream and a
+ * Cipher.
+ * <br>Note: if the specified input stream or cipher is
+ * null, a NullPointerException may be thrown later when
+ * they are used.
+ * @param is the to-be-processed input stream
+ * @param c an initialized Cipher object
+ */
+ public CipherInputStream(InputStream is, Cipher c) {
+ super(is);
+ input = is;
+ cipher = c;
+ }
+
+ /**
+ * Constructs a CipherInputStream from an InputStream without
+ * specifying a Cipher. This has the effect of constructing a
+ * CipherInputStream using a NullCipher.
+ * <br>Note: if the specified input stream is null, a
+ * NullPointerException may be thrown later when it is used.
+ * @param is the to-be-processed input stream
+ */
+ protected CipherInputStream(InputStream is) {
+ super(is);
+ input = is;
+ cipher = new NullCipher();
+ }
+
+ /**
+ * Reads the next byte of data from this input stream. The value
+ * byte is returned as an <code>int</code> in the range
+ * <code>0</code> to <code>255</code>. If no byte is available
+ * because the end of the stream has been reached, the value
+ * <code>-1</code> is returned. This method blocks until input data
+ * is available, the end of the stream is detected, or an exception
+ * is thrown.
+ * <p>
+ *
+ * @return the next byte of data, or <code>-1</code> if the end of the
+ * stream is reached.
+ * @exception IOException if an I/O error occurs.
+ * @since JCE1.2
+ */
+ public int read() throws IOException {
+ if (ostart >= ofinish) {
+ // we loop for new data as the spec says we are blocking
+ int i = 0;
+ while (i == 0) i = getMoreData();
+ if (i == -1) return -1;
+ }
+ return ((int) obuffer[ostart++] & 0xff);
+ };
+
+ /**
+ * Reads up to <code>b.length</code> bytes of data from this input
+ * stream into an array of bytes.
+ * <p>
+ * The <code>read</code> method of <code>InputStream</code> calls
+ * the <code>read</code> method of three arguments with the arguments
+ * <code>b</code>, <code>0</code>, and <code>b.length</code>.
+ *
+ * @param b the buffer into which the data is read.
+ * @return the total number of bytes read into the buffer, or
+ * <code>-1</code> is there is no more data because the end of
+ * the stream has been reached.
+ * @exception IOException if an I/O error occurs.
+ * @see java.io.InputStream#read(byte[], int, int)
+ * @since JCE1.2
+ */
+ public int read(byte b[]) throws IOException {
+ return read(b, 0, b.length);
+ }
+
+ /**
+ * Reads up to <code>len</code> bytes of data from this input stream
+ * into an array of bytes. This method blocks until some input is
+ * available. If the first argument is <code>null,</code> up to
+ * <code>len</code> bytes are read and discarded.
+ *
+ * @param b the buffer into which the data is read.
+ * @param off the start offset in the destination array
+ * <code>buf</code>
+ * @param len the maximum number of bytes read.
+ * @return the total number of bytes read into the buffer, or
+ * <code>-1</code> if there is no more data because the end of
+ * the stream has been reached.
+ * @exception IOException if an I/O error occurs.
+ * @see java.io.InputStream#read()
+ * @since JCE1.2
+ */
+ public int read(byte b[], int off, int len) throws IOException {
+ if (ostart >= ofinish) {
+ // we loop for new data as the spec says we are blocking
+ int i = 0;
+ while (i == 0) i = getMoreData();
+ if (i == -1) return -1;
+ }
+ if (len <= 0) {
+ return 0;
+ }
+ int available = ofinish - ostart;
+ if (len < available) available = len;
+ if (b != null) {
+ System.arraycopy(obuffer, ostart, b, off, available);
+ }
+ ostart = ostart + available;
+ return available;
+ }
+
+ /**
+ * Skips <code>n</code> bytes of input from the bytes that can be read
+ * from this input stream without blocking.
+ *
+ * <p>Fewer bytes than requested might be skipped.
+ * The actual number of bytes skipped is equal to <code>n</code> or
+ * the result of a call to
+ * {@link #available() available},
+ * whichever is smaller.
+ * If <code>n</code> is less than zero, no bytes are skipped.
+ *
+ * <p>The actual number of bytes skipped is returned.
+ *
+ * @param n the number of bytes to be skipped.
+ * @return the actual number of bytes skipped.
+ * @exception IOException if an I/O error occurs.
+ * @since JCE1.2
+ */
+ public long skip(long n) throws IOException {
+ int available = ofinish - ostart;
+ if (n > available) {
+ n = available;
+ }
+ if (n < 0) {
+ return 0;
+ }
+ ostart += n;
+ return n;
+ }
+
+ /**
+ * Returns the number of bytes that can be read from this input
+ * stream without blocking. The <code>available</code> method of
+ * <code>InputStream</code> returns <code>0</code>. This method
+ * <B>should</B> be overridden by subclasses.
+ *
+ * @return the number of bytes that can be read from this input stream
+ * without blocking.
+ * @exception IOException if an I/O error occurs.
+ * @since JCE1.2
+ */
+ public int available() throws IOException {
+ return (ofinish - ostart);
+ }
+
+ /**
+ * Closes this input stream and releases any system resources
+ * associated with the stream.
+ * <p>
+ * The <code>close</code> method of <code>CipherInputStream</code>
+ * calls the <code>close</code> method of its underlying input
+ * stream.
+ *
+ * @exception IOException if an I/O error occurs.
+ * @since JCE1.2
+ */
+ public void close() throws IOException {
+ if (closed) {
+ return;
+ }
+
+ closed = true;
+ input.close();
+
+ // Android-removed: Removed a now-inaccurate comment
+ if (!done) {
+ try {
+ cipher.doFinal();
+ }
+ catch (BadPaddingException | IllegalBlockSizeException ex) {
+ // Android-changed: Added throw if bad tag is seen. See b/31590622.
+ if (ex instanceof AEADBadTagException) {
+ throw new IOException(ex);
+ }
+ }
+ }
+ ostart = 0;
+ ofinish = 0;
+ }
+
+ /**
+ * Tests if this input stream supports the <code>mark</code>
+ * and <code>reset</code> methods, which it does not.
+ *
+ * @return <code>false</code>, since this class does not support the
+ * <code>mark</code> and <code>reset</code> methods.
+ * @see java.io.InputStream#mark(int)
+ * @see java.io.InputStream#reset()
+ * @since JCE1.2
+ */
+ public boolean markSupported() {
+ return false;
+ }
+}
diff --git a/javax/crypto/CipherOutputStream.java b/javax/crypto/CipherOutputStream.java
new file mode 100644
index 0000000..370f7af
--- /dev/null
+++ b/javax/crypto/CipherOutputStream.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.crypto;
+
+import java.io.*;
+
+/**
+ * A CipherOutputStream is composed of an OutputStream and a Cipher so
+ * that write() methods first process the data before writing them out
+ * to the underlying OutputStream. The cipher must be fully
+ * initialized before being used by a CipherOutputStream.
+ *
+ * <p> For example, if the cipher is initialized for encryption, the
+ * CipherOutputStream will attempt to encrypt data before writing out the
+ * encrypted data.
+ *
+ * <p> This class adheres strictly to the semantics, especially the
+ * failure semantics, of its ancestor classes
+ * java.io.OutputStream and java.io.FilterOutputStream. This class
+ * has exactly those methods specified in its ancestor classes, and
+ * overrides them all. Moreover, this class catches all exceptions
+ * that are not thrown by its ancestor classes.
+ *
+ * <p> It is crucial for a programmer using this class not to use
+ * methods that are not defined or overriden in this class (such as a
+ * new method or constructor that is later added to one of the super
+ * classes), because the design and implementation of those methods
+ * are unlikely to have considered security impact with regard to
+ * CipherOutputStream.
+ *
+ * @author Li Gong
+ * @see java.io.OutputStream
+ * @see java.io.FilterOutputStream
+ * @see javax.crypto.Cipher
+ * @see javax.crypto.CipherInputStream
+ *
+ * @since 1.4
+ */
+
+public class CipherOutputStream extends FilterOutputStream {
+
+ // the cipher engine to use to process stream data
+ private Cipher cipher;
+
+ // the underlying output stream
+ private OutputStream output;
+
+ /* the buffer holding one byte of incoming data */
+ private byte[] ibuffer = new byte[1];
+
+ // the buffer holding data ready to be written out
+ private byte[] obuffer;
+
+ // stream status
+ private boolean closed = false;
+
+ /**
+ *
+ * Constructs a CipherOutputStream from an OutputStream and a
+ * Cipher.
+ * <br>Note: if the specified output stream or cipher is
+ * null, a NullPointerException may be thrown later when
+ * they are used.
+ *
+ * @param os the OutputStream object
+ * @param c an initialized Cipher object
+ */
+ public CipherOutputStream(OutputStream os, Cipher c) {
+ super(os);
+ output = os;
+ cipher = c;
+ };
+
+ /**
+ * Constructs a CipherOutputStream from an OutputStream without
+ * specifying a Cipher. This has the effect of constructing a
+ * CipherOutputStream using a NullCipher.
+ * <br>Note: if the specified output stream is null, a
+ * NullPointerException may be thrown later when it is used.
+ *
+ * @param os the OutputStream object
+ */
+ protected CipherOutputStream(OutputStream os) {
+ super(os);
+ output = os;
+ cipher = new NullCipher();
+ }
+
+ /**
+ * Writes the specified byte to this output stream.
+ *
+ * @param b the <code>byte</code>.
+ * @exception IOException if an I/O error occurs.
+ * @since JCE1.2
+ */
+ public void write(int b) throws IOException {
+ ibuffer[0] = (byte) b;
+ obuffer = cipher.update(ibuffer, 0, 1);
+ if (obuffer != null) {
+ output.write(obuffer);
+ obuffer = null;
+ }
+ };
+
+ /**
+ * Writes <code>b.length</code> bytes from the specified byte array
+ * to this output stream.
+ * <p>
+ * The <code>write</code> method of
+ * <code>CipherOutputStream</code> calls the <code>write</code>
+ * method of three arguments with the three arguments
+ * <code>b</code>, <code>0</code>, and <code>b.length</code>.
+ *
+ * @param b the data.
+ * @exception NullPointerException if <code>b</code> is null.
+ * @exception IOException if an I/O error occurs.
+ * @see javax.crypto.CipherOutputStream#write(byte[], int, int)
+ * @since JCE1.2
+ */
+ public void write(byte b[]) throws IOException {
+ write(b, 0, b.length);
+ }
+
+ /**
+ * Writes <code>len</code> bytes from the specified byte array
+ * starting at offset <code>off</code> to this output stream.
+ *
+ * @param b the data.
+ * @param off the start offset in the data.
+ * @param len the number of bytes to write.
+ * @exception IOException if an I/O error occurs.
+ * @since JCE1.2
+ */
+ public void write(byte b[], int off, int len) throws IOException {
+ obuffer = cipher.update(b, off, len);
+ if (obuffer != null) {
+ output.write(obuffer);
+ obuffer = null;
+ }
+ }
+
+ /**
+ * Flushes this output stream by forcing any buffered output bytes
+ * that have already been processed by the encapsulated cipher object
+ * to be written out.
+ *
+ * <p>Any bytes buffered by the encapsulated cipher
+ * and waiting to be processed by it will not be written out. For example,
+ * if the encapsulated cipher is a block cipher, and the total number of
+ * bytes written using one of the <code>write</code> methods is less than
+ * the cipher's block size, no bytes will be written out.
+ *
+ * @exception IOException if an I/O error occurs.
+ * @since JCE1.2
+ */
+ public void flush() throws IOException {
+ if (obuffer != null) {
+ output.write(obuffer);
+ obuffer = null;
+ }
+ output.flush();
+ }
+
+ /**
+ * Closes this output stream and releases any system resources
+ * associated with this stream.
+ * <p>
+ * This method invokes the <code>doFinal</code> method of the encapsulated
+ * cipher object, which causes any bytes buffered by the encapsulated
+ * cipher to be processed. The result is written out by calling the
+ * <code>flush</code> method of this output stream.
+ * <p>
+ * This method resets the encapsulated cipher object to its initial state
+ * and calls the <code>close</code> method of the underlying output
+ * stream.
+ *
+ * @exception IOException if an I/O error occurs.
+ * @since JCE1.2
+ */
+ public void close() throws IOException {
+ if (closed) {
+ return;
+ }
+
+ closed = true;
+ try {
+ obuffer = cipher.doFinal();
+ } catch (IllegalBlockSizeException | BadPaddingException e) {
+ obuffer = null;
+ // Android-added: Throw an exception when the underlying cipher does. http://b/36636576
+ throw new IOException(e);
+ }
+ try {
+ flush();
+ } catch (IOException ignored) {}
+ out.close();
+ }
+}
diff --git a/javax/crypto/CipherSpi.java b/javax/crypto/CipherSpi.java
new file mode 100644
index 0000000..ce72581
--- /dev/null
+++ b/javax/crypto/CipherSpi.java
@@ -0,0 +1,1011 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.crypto;
+
+import java.util.StringTokenizer;
+import java.util.NoSuchElementException;
+import java.security.AlgorithmParameters;
+import java.security.Provider;
+import java.security.Key;
+import java.security.SecureRandom;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.InvalidKeyException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.ProviderException;
+import java.security.spec.AlgorithmParameterSpec;
+
+import java.nio.ByteBuffer;
+
+/**
+ * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>)
+ * for the <code>Cipher</code> class.
+ * All the abstract methods in this class must be implemented by each
+ * cryptographic service provider who wishes to supply the implementation
+ * of a particular cipher algorithm.
+ *
+ * <p>In order to create an instance of <code>Cipher</code>, which
+ * encapsulates an instance of this <code>CipherSpi</code> class, an
+ * application calls one of the
+ * {@link Cipher#getInstance(java.lang.String) getInstance}
+ * factory methods of the
+ * {@link Cipher Cipher} engine class and specifies the requested
+ * <i>transformation</i>.
+ * Optionally, the application may also specify the name of a provider.
+ *
+ * <p>A <i>transformation</i> is a string that describes the operation (or
+ * set of operations) to be performed on the given input, to produce some
+ * output. A transformation always includes the name of a cryptographic
+ * algorithm (e.g., <i>DES</i>), and may be followed by a feedback mode and
+ * padding scheme.
+ *
+ * <p> A transformation is of the form:
+ *
+ * <ul>
+ * <li>"<i>algorithm/mode/padding</i>" or
+ *
+ * <li>"<i>algorithm</i>"
+ * </ul>
+ *
+ * <P> (in the latter case,
+ * provider-specific default values for the mode and padding scheme are used).
+ * For example, the following is a valid transformation:
+ *
+ * <pre>
+ * Cipher c = Cipher.getInstance("<i>DES/CBC/PKCS5Padding</i>");
+ * </pre>
+ *
+ * <p>A provider may supply a separate class for each combination
+ * of <i>algorithm/mode/padding</i>, or may decide to provide more generic
+ * classes representing sub-transformations corresponding to
+ * <i>algorithm</i> or <i>algorithm/mode</i> or <i>algorithm//padding</i>
+ * (note the double slashes),
+ * in which case the requested mode and/or padding are set automatically by
+ * the <code>getInstance</code> methods of <code>Cipher</code>, which invoke
+ * the {@link #engineSetMode(java.lang.String) engineSetMode} and
+ * {@link #engineSetPadding(java.lang.String) engineSetPadding}
+ * methods of the provider's subclass of <code>CipherSpi</code>.
+ *
+ * <p>A <code>Cipher</code> property in a provider master class may have one of
+ * the following formats:
+ *
+ * <ul>
+ *
+ * <li>
+ * <pre>
+ * // provider's subclass of "CipherSpi" implements "algName" with
+ * // pluggable mode and padding
+ * <code>Cipher.</code><i>algName</i>
+ * </pre>
+ *
+ * <li>
+ * <pre>
+ * // provider's subclass of "CipherSpi" implements "algName" in the
+ * // specified "mode", with pluggable padding
+ * <code>Cipher.</code><i>algName/mode</i>
+ * </pre>
+ *
+ * <li>
+ * <pre>
+ * // provider's subclass of "CipherSpi" implements "algName" with the
+ * // specified "padding", with pluggable mode
+ * <code>Cipher.</code><i>algName//padding</i>
+ * </pre>
+ *
+ * <li>
+ * <pre>
+ * // provider's subclass of "CipherSpi" implements "algName" with the
+ * // specified "mode" and "padding"
+ * <code>Cipher.</code><i>algName/mode/padding</i>
+ * </pre>
+ *
+ * </ul>
+ *
+ * <p>For example, a provider may supply a subclass of <code>CipherSpi</code>
+ * that implements <i>DES/ECB/PKCS5Padding</i>, one that implements
+ * <i>DES/CBC/PKCS5Padding</i>, one that implements
+ * <i>DES/CFB/PKCS5Padding</i>, and yet another one that implements
+ * <i>DES/OFB/PKCS5Padding</i>. That provider would have the following
+ * <code>Cipher</code> properties in its master class:
+ *
+ * <ul>
+ *
+ * <li>
+ * <pre>
+ * <code>Cipher.</code><i>DES/ECB/PKCS5Padding</i>
+ * </pre>
+ *
+ * <li>
+ * <pre>
+ * <code>Cipher.</code><i>DES/CBC/PKCS5Padding</i>
+ * </pre>
+ *
+ * <li>
+ * <pre>
+ * <code>Cipher.</code><i>DES/CFB/PKCS5Padding</i>
+ * </pre>
+ *
+ * <li>
+ * <pre>
+ * <code>Cipher.</code><i>DES/OFB/PKCS5Padding</i>
+ * </pre>
+ *
+ * </ul>
+ *
+ * <p>Another provider may implement a class for each of the above modes
+ * (i.e., one class for <i>ECB</i>, one for <i>CBC</i>, one for <i>CFB</i>,
+ * and one for <i>OFB</i>), one class for <i>PKCS5Padding</i>,
+ * and a generic <i>DES</i> class that subclasses from <code>CipherSpi</code>.
+ * That provider would have the following
+ * <code>Cipher</code> properties in its master class:
+ *
+ * <ul>
+ *
+ * <li>
+ * <pre>
+ * <code>Cipher.</code><i>DES</i>
+ * </pre>
+ *
+ * </ul>
+ *
+ * <p>The <code>getInstance</code> factory method of the <code>Cipher</code>
+ * engine class follows these rules in order to instantiate a provider's
+ * implementation of <code>CipherSpi</code> for a
+ * transformation of the form "<i>algorithm</i>":
+ *
+ * <ol>
+ * <li>
+ * Check if the provider has registered a subclass of <code>CipherSpi</code>
+ * for the specified "<i>algorithm</i>".
+ * <p>If the answer is YES, instantiate this
+ * class, for whose mode and padding scheme default values (as supplied by
+ * the provider) are used.
+ * <p>If the answer is NO, throw a <code>NoSuchAlgorithmException</code>
+ * exception.
+ * </ol>
+ *
+ * <p>The <code>getInstance</code> factory method of the <code>Cipher</code>
+ * engine class follows these rules in order to instantiate a provider's
+ * implementation of <code>CipherSpi</code> for a
+ * transformation of the form "<i>algorithm/mode/padding</i>":
+ *
+ * <ol>
+ * <li>
+ * Check if the provider has registered a subclass of <code>CipherSpi</code>
+ * for the specified "<i>algorithm/mode/padding</i>" transformation.
+ * <p>If the answer is YES, instantiate it.
+ * <p>If the answer is NO, go to the next step.
+ * <li>
+ * Check if the provider has registered a subclass of <code>CipherSpi</code>
+ * for the sub-transformation "<i>algorithm/mode</i>".
+ * <p>If the answer is YES, instantiate it, and call
+ * <code>engineSetPadding(<i>padding</i>)</code> on the new instance.
+ * <p>If the answer is NO, go to the next step.
+ * <li>
+ * Check if the provider has registered a subclass of <code>CipherSpi</code>
+ * for the sub-transformation "<i>algorithm//padding</i>" (note the double
+ * slashes).
+ * <p>If the answer is YES, instantiate it, and call
+ * <code>engineSetMode(<i>mode</i>)</code> on the new instance.
+ * <p>If the answer is NO, go to the next step.
+ * <li>
+ * Check if the provider has registered a subclass of <code>CipherSpi</code>
+ * for the sub-transformation "<i>algorithm</i>".
+ * <p>If the answer is YES, instantiate it, and call
+ * <code>engineSetMode(<i>mode</i>)</code> and
+ * <code>engineSetPadding(<i>padding</i>)</code> on the new instance.
+ * <p>If the answer is NO, throw a <code>NoSuchAlgorithmException</code>
+ * exception.
+ * </ol>
+ *
+ * @author Jan Luehe
+ * @see KeyGenerator
+ * @see SecretKey
+ * @since 1.4
+ */
+
+public abstract class CipherSpi {
+
+ /**
+ * Sets the mode of this cipher.
+ *
+ * @param mode the cipher mode
+ *
+ * @exception NoSuchAlgorithmException if the requested cipher mode does
+ * not exist
+ */
+ protected abstract void engineSetMode(String mode)
+ throws NoSuchAlgorithmException;
+
+ /**
+ * Sets the padding mechanism of this cipher.
+ *
+ * @param padding the padding mechanism
+ *
+ * @exception NoSuchPaddingException if the requested padding mechanism
+ * does not exist
+ */
+ protected abstract void engineSetPadding(String padding)
+ throws NoSuchPaddingException;
+
+ /**
+ * Returns the block size (in bytes).
+ *
+ * @return the block size (in bytes), or 0 if the underlying algorithm is
+ * not a block cipher
+ */
+ protected abstract int engineGetBlockSize();
+
+ /**
+ * Returns the length in bytes that an output buffer would
+ * need to be in order to hold the result of the next <code>update</code>
+ * or <code>doFinal</code> operation, given the input length
+ * <code>inputLen</code> (in bytes).
+ *
+ * <p>This call takes into account any unprocessed (buffered) data from a
+ * previous <code>update</code> call, padding, and AEAD tagging.
+ *
+ * <p>The actual output length of the next <code>update</code> or
+ * <code>doFinal</code> call may be smaller than the length returned by
+ * this method.
+ *
+ * @param inputLen the input length (in bytes)
+ *
+ * @return the required output buffer size (in bytes)
+ */
+ protected abstract int engineGetOutputSize(int inputLen);
+
+ /**
+ * Returns the initialization vector (IV) in a new buffer.
+ *
+ * <p> This is useful in the context of password-based encryption or
+ * decryption, where the IV is derived from a user-provided passphrase.
+ *
+ * @return the initialization vector in a new buffer, or null if the
+ * underlying algorithm does not use an IV, or if the IV has not yet
+ * been set.
+ */
+ protected abstract byte[] engineGetIV();
+
+ /**
+ * Returns the parameters used with this cipher.
+ *
+ * <p>The returned parameters may be the same that were used to initialize
+ * this cipher, or may contain a combination of default and random
+ * parameter values used by the underlying cipher implementation if this
+ * cipher requires algorithm parameters but was not initialized with any.
+ *
+ * @return the parameters used with this cipher, or null if this cipher
+ * does not use any parameters.
+ */
+ protected abstract AlgorithmParameters engineGetParameters();
+
+ /**
+ * Initializes this cipher with a key and a source
+ * of randomness.
+ *
+ * <p>The cipher is initialized for one of the following four operations:
+ * encryption, decryption, key wrapping or key unwrapping, depending on
+ * the value of <code>opmode</code>.
+ *
+ * <p>If this cipher requires any algorithm parameters that cannot be
+ * derived from the given <code>key</code>, the underlying cipher
+ * implementation is supposed to generate the required parameters itself
+ * (using provider-specific default or random values) if it is being
+ * initialized for encryption or key wrapping, and raise an
+ * <code>InvalidKeyException</code> if it is being
+ * initialized for decryption or key unwrapping.
+ * The generated parameters can be retrieved using
+ * {@link #engineGetParameters() engineGetParameters} or
+ * {@link #engineGetIV() engineGetIV} (if the parameter is an IV).
+ *
+ * <p>If this cipher requires algorithm parameters that cannot be
+ * derived from the input parameters, and there are no reasonable
+ * provider-specific default values, initialization will
+ * necessarily fail.
+ *
+ * <p>If this cipher (including its underlying feedback or padding scheme)
+ * requires any random bytes (e.g., for parameter generation), it will get
+ * them from <code>random</code>.
+ *
+ * <p>Note that when a Cipher object is initialized, it loses all
+ * previously-acquired state. In other words, initializing a Cipher is
+ * equivalent to creating a new instance of that Cipher and initializing
+ * it.
+ *
+ * @param opmode the operation mode of this cipher (this is one of
+ * the following:
+ * <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>,
+ * <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>)
+ * @param key the encryption key
+ * @param random the source of randomness
+ *
+ * @exception InvalidKeyException if the given key is inappropriate for
+ * initializing this cipher, or requires
+ * algorithm parameters that cannot be
+ * determined from the given key.
+ * @throws UnsupportedOperationException if {@code opmode} is
+ * {@code WRAP_MODE} or {@code UNWRAP_MODE} is not implemented
+ * by the cipher.
+ */
+ protected abstract void engineInit(int opmode, Key key,
+ SecureRandom random)
+ throws InvalidKeyException;
+
+ /**
+ * Initializes this cipher with a key, a set of
+ * algorithm parameters, and a source of randomness.
+ *
+ * <p>The cipher is initialized for one of the following four operations:
+ * encryption, decryption, key wrapping or key unwrapping, depending on
+ * the value of <code>opmode</code>.
+ *
+ * <p>If this cipher requires any algorithm parameters and
+ * <code>params</code> is null, the underlying cipher implementation is
+ * supposed to generate the required parameters itself (using
+ * provider-specific default or random values) if it is being
+ * initialized for encryption or key wrapping, and raise an
+ * <code>InvalidAlgorithmParameterException</code> if it is being
+ * initialized for decryption or key unwrapping.
+ * The generated parameters can be retrieved using
+ * {@link #engineGetParameters() engineGetParameters} or
+ * {@link #engineGetIV() engineGetIV} (if the parameter is an IV).
+ *
+ * <p>If this cipher requires algorithm parameters that cannot be
+ * derived from the input parameters, and there are no reasonable
+ * provider-specific default values, initialization will
+ * necessarily fail.
+ *
+ * <p>If this cipher (including its underlying feedback or padding scheme)
+ * requires any random bytes (e.g., for parameter generation), it will get
+ * them from <code>random</code>.
+ *
+ * <p>Note that when a Cipher object is initialized, it loses all
+ * previously-acquired state. In other words, initializing a Cipher is
+ * equivalent to creating a new instance of that Cipher and initializing
+ * it.
+ *
+ * @param opmode the operation mode of this cipher (this is one of
+ * the following:
+ * <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>,
+ * <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>)
+ * @param key the encryption key
+ * @param params the algorithm parameters
+ * @param random the source of randomness
+ *
+ * @exception InvalidKeyException if the given key is inappropriate for
+ * initializing this cipher
+ * @exception InvalidAlgorithmParameterException if the given algorithm
+ * parameters are inappropriate for this cipher,
+ * or if this cipher requires
+ * algorithm parameters and <code>params</code> is null.
+ * @throws UnsupportedOperationException if {@code opmode} is
+ * {@code WRAP_MODE} or {@code UNWRAP_MODE} is not implemented
+ * by the cipher.
+ */
+ protected abstract void engineInit(int opmode, Key key,
+ AlgorithmParameterSpec params,
+ SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException;
+
+ /**
+ * Initializes this cipher with a key, a set of
+ * algorithm parameters, and a source of randomness.
+ *
+ * <p>The cipher is initialized for one of the following four operations:
+ * encryption, decryption, key wrapping or key unwrapping, depending on
+ * the value of <code>opmode</code>.
+ *
+ * <p>If this cipher requires any algorithm parameters and
+ * <code>params</code> is null, the underlying cipher implementation is
+ * supposed to generate the required parameters itself (using
+ * provider-specific default or random values) if it is being
+ * initialized for encryption or key wrapping, and raise an
+ * <code>InvalidAlgorithmParameterException</code> if it is being
+ * initialized for decryption or key unwrapping.
+ * The generated parameters can be retrieved using
+ * {@link #engineGetParameters() engineGetParameters} or
+ * {@link #engineGetIV() engineGetIV} (if the parameter is an IV).
+ *
+ * <p>If this cipher requires algorithm parameters that cannot be
+ * derived from the input parameters, and there are no reasonable
+ * provider-specific default values, initialization will
+ * necessarily fail.
+ *
+ * <p>If this cipher (including its underlying feedback or padding scheme)
+ * requires any random bytes (e.g., for parameter generation), it will get
+ * them from <code>random</code>.
+ *
+ * <p>Note that when a Cipher object is initialized, it loses all
+ * previously-acquired state. In other words, initializing a Cipher is
+ * equivalent to creating a new instance of that Cipher and initializing
+ * it.
+ *
+ * @param opmode the operation mode of this cipher (this is one of
+ * the following:
+ * <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>,
+ * <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>)
+ * @param key the encryption key
+ * @param params the algorithm parameters
+ * @param random the source of randomness
+ *
+ * @exception InvalidKeyException if the given key is inappropriate for
+ * initializing this cipher
+ * @exception InvalidAlgorithmParameterException if the given algorithm
+ * parameters are inappropriate for this cipher,
+ * or if this cipher requires
+ * algorithm parameters and <code>params</code> is null.
+ * @throws UnsupportedOperationException if {@code opmode} is
+ * {@code WRAP_MODE} or {@code UNWRAP_MODE} is not implemented
+ * by the cipher.
+ */
+ protected abstract void engineInit(int opmode, Key key,
+ AlgorithmParameters params,
+ SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException;
+
+ /**
+ * Continues a multiple-part encryption or decryption operation
+ * (depending on how this cipher was initialized), processing another data
+ * part.
+ *
+ * <p>The first <code>inputLen</code> bytes in the <code>input</code>
+ * buffer, starting at <code>inputOffset</code> inclusive, are processed,
+ * and the result is stored in a new buffer.
+ *
+ * @param input the input buffer
+ * @param inputOffset the offset in <code>input</code> where the input
+ * starts
+ * @param inputLen the input length
+ *
+ * @return the new buffer with the result, or null if the underlying
+ * cipher is a block cipher and the input data is too short to result in a
+ * new block.
+ */
+ protected abstract byte[] engineUpdate(byte[] input, int inputOffset,
+ int inputLen);
+
+ /**
+ * Continues a multiple-part encryption or decryption operation
+ * (depending on how this cipher was initialized), processing another data
+ * part.
+ *
+ * <p>The first <code>inputLen</code> bytes in the <code>input</code>
+ * buffer, starting at <code>inputOffset</code> inclusive, are processed,
+ * and the result is stored in the <code>output</code> buffer, starting at
+ * <code>outputOffset</code> inclusive.
+ *
+ * <p>If the <code>output</code> buffer is too small to hold the result,
+ * a <code>ShortBufferException</code> is thrown.
+ *
+ * @param input the input buffer
+ * @param inputOffset the offset in <code>input</code> where the input
+ * starts
+ * @param inputLen the input length
+ * @param output the buffer for the result
+ * @param outputOffset the offset in <code>output</code> where the result
+ * is stored
+ *
+ * @return the number of bytes stored in <code>output</code>
+ *
+ * @exception ShortBufferException if the given output buffer is too small
+ * to hold the result
+ */
+ protected abstract int engineUpdate(byte[] input, int inputOffset,
+ int inputLen, byte[] output,
+ int outputOffset)
+ throws ShortBufferException;
+
+ /**
+ * Continues a multiple-part encryption or decryption operation
+ * (depending on how this cipher was initialized), processing another data
+ * part.
+ *
+ * <p>All <code>input.remaining()</code> bytes starting at
+ * <code>input.position()</code> are processed. The result is stored
+ * in the output buffer.
+ * Upon return, the input buffer's position will be equal
+ * to its limit; its limit will not have changed. The output buffer's
+ * position will have advanced by n, where n is the value returned
+ * by this method; the output buffer's limit will not have changed.
+ *
+ * <p>If <code>output.remaining()</code> bytes are insufficient to
+ * hold the result, a <code>ShortBufferException</code> is thrown.
+ *
+ * <p>Subclasses should consider overriding this method if they can
+ * process ByteBuffers more efficiently than byte arrays.
+ *
+ * @param input the input ByteBuffer
+ * @param output the output ByteByffer
+ *
+ * @return the number of bytes stored in <code>output</code>
+ *
+ * @exception ShortBufferException if there is insufficient space in the
+ * output buffer
+ *
+ * @throws NullPointerException if either parameter is <CODE>null</CODE>
+ * @since 1.5
+ */
+ protected int engineUpdate(ByteBuffer input, ByteBuffer output)
+ throws ShortBufferException {
+ try {
+ return bufferCrypt(input, output, true);
+ } catch (IllegalBlockSizeException e) {
+ // never thrown for engineUpdate()
+ throw new ProviderException("Internal error in update()");
+ } catch (BadPaddingException e) {
+ // never thrown for engineUpdate()
+ throw new ProviderException("Internal error in update()");
+ }
+ }
+
+ /**
+ * Encrypts or decrypts data in a single-part operation,
+ * or finishes a multiple-part operation.
+ * The data is encrypted or decrypted, depending on how this cipher was
+ * initialized.
+ *
+ * <p>The first <code>inputLen</code> bytes in the <code>input</code>
+ * buffer, starting at <code>inputOffset</code> inclusive, and any input
+ * bytes that may have been buffered during a previous <code>update</code>
+ * operation, are processed, with padding (if requested) being applied.
+ * If an AEAD mode such as GCM/CCM is being used, the authentication
+ * tag is appended in the case of encryption, or verified in the
+ * case of decryption.
+ * The result is stored in a new buffer.
+ *
+ * <p>Upon finishing, this method resets this cipher object to the state
+ * it was in when previously initialized via a call to
+ * <code>engineInit</code>.
+ * That is, the object is reset and available to encrypt or decrypt
+ * (depending on the operation mode that was specified in the call to
+ * <code>engineInit</code>) more data.
+ *
+ * <p>Note: if any exception is thrown, this cipher object may need to
+ * be reset before it can be used again.
+ *
+ * @param input the input buffer
+ * @param inputOffset the offset in <code>input</code> where the input
+ * starts
+ * @param inputLen the input length
+ *
+ * @return the new buffer with the result
+ *
+ * @exception IllegalBlockSizeException if this cipher is a block cipher,
+ * no padding has been requested (only in encryption mode), and the total
+ * input length of the data processed by this cipher is not a multiple of
+ * block size; or if this encryption algorithm is unable to
+ * process the input data provided.
+ * @exception BadPaddingException if this cipher is in decryption mode,
+ * and (un)padding has been requested, but the decrypted data is not
+ * bounded by the appropriate padding bytes
+ * @exception AEADBadTagException if this cipher is decrypting in an
+ * AEAD mode (such as GCM/CCM), and the received authentication tag
+ * does not match the calculated value
+ */
+ protected abstract byte[] engineDoFinal(byte[] input, int inputOffset,
+ int inputLen)
+ throws IllegalBlockSizeException, BadPaddingException;
+
+ /**
+ * Encrypts or decrypts data in a single-part operation,
+ * or finishes a multiple-part operation.
+ * The data is encrypted or decrypted, depending on how this cipher was
+ * initialized.
+ *
+ * <p>The first <code>inputLen</code> bytes in the <code>input</code>
+ * buffer, starting at <code>inputOffset</code> inclusive, and any input
+ * bytes that may have been buffered during a previous <code>update</code>
+ * operation, are processed, with padding (if requested) being applied.
+ * If an AEAD mode such as GCM/CCM is being used, the authentication
+ * tag is appended in the case of encryption, or verified in the
+ * case of decryption.
+ * The result is stored in the <code>output</code> buffer, starting at
+ * <code>outputOffset</code> inclusive.
+ *
+ * <p>If the <code>output</code> buffer is too small to hold the result,
+ * a <code>ShortBufferException</code> is thrown.
+ *
+ * <p>Upon finishing, this method resets this cipher object to the state
+ * it was in when previously initialized via a call to
+ * <code>engineInit</code>.
+ * That is, the object is reset and available to encrypt or decrypt
+ * (depending on the operation mode that was specified in the call to
+ * <code>engineInit</code>) more data.
+ *
+ * <p>Note: if any exception is thrown, this cipher object may need to
+ * be reset before it can be used again.
+ *
+ * @param input the input buffer
+ * @param inputOffset the offset in <code>input</code> where the input
+ * starts
+ * @param inputLen the input length
+ * @param output the buffer for the result
+ * @param outputOffset the offset in <code>output</code> where the result
+ * is stored
+ *
+ * @return the number of bytes stored in <code>output</code>
+ *
+ * @exception IllegalBlockSizeException if this cipher is a block cipher,
+ * no padding has been requested (only in encryption mode), and the total
+ * input length of the data processed by this cipher is not a multiple of
+ * block size; or if this encryption algorithm is unable to
+ * process the input data provided.
+ * @exception ShortBufferException if the given output buffer is too small
+ * to hold the result
+ * @exception BadPaddingException if this cipher is in decryption mode,
+ * and (un)padding has been requested, but the decrypted data is not
+ * bounded by the appropriate padding bytes
+ * @exception AEADBadTagException if this cipher is decrypting in an
+ * AEAD mode (such as GCM/CCM), and the received authentication tag
+ * does not match the calculated value
+ */
+ protected abstract int engineDoFinal(byte[] input, int inputOffset,
+ int inputLen, byte[] output,
+ int outputOffset)
+ throws ShortBufferException, IllegalBlockSizeException,
+ BadPaddingException;
+
+ /**
+ * Encrypts or decrypts data in a single-part operation,
+ * or finishes a multiple-part operation.
+ * The data is encrypted or decrypted, depending on how this cipher was
+ * initialized.
+ *
+ * <p>All <code>input.remaining()</code> bytes starting at
+ * <code>input.position()</code> are processed.
+ * If an AEAD mode such as GCM/CCM is being used, the authentication
+ * tag is appended in the case of encryption, or verified in the
+ * case of decryption.
+ * The result is stored in the output buffer.
+ * Upon return, the input buffer's position will be equal
+ * to its limit; its limit will not have changed. The output buffer's
+ * position will have advanced by n, where n is the value returned
+ * by this method; the output buffer's limit will not have changed.
+ *
+ * <p>If <code>output.remaining()</code> bytes are insufficient to
+ * hold the result, a <code>ShortBufferException</code> is thrown.
+ *
+ * <p>Upon finishing, this method resets this cipher object to the state
+ * it was in when previously initialized via a call to
+ * <code>engineInit</code>.
+ * That is, the object is reset and available to encrypt or decrypt
+ * (depending on the operation mode that was specified in the call to
+ * <code>engineInit</code>) more data.
+ *
+ * <p>Note: if any exception is thrown, this cipher object may need to
+ * be reset before it can be used again.
+ *
+ * <p>Subclasses should consider overriding this method if they can
+ * process ByteBuffers more efficiently than byte arrays.
+ *
+ * @param input the input ByteBuffer
+ * @param output the output ByteByffer
+ *
+ * @return the number of bytes stored in <code>output</code>
+ *
+ * @exception IllegalBlockSizeException if this cipher is a block cipher,
+ * no padding has been requested (only in encryption mode), and the total
+ * input length of the data processed by this cipher is not a multiple of
+ * block size; or if this encryption algorithm is unable to
+ * process the input data provided.
+ * @exception ShortBufferException if there is insufficient space in the
+ * output buffer
+ * @exception BadPaddingException if this cipher is in decryption mode,
+ * and (un)padding has been requested, but the decrypted data is not
+ * bounded by the appropriate padding bytes
+ * @exception AEADBadTagException if this cipher is decrypting in an
+ * AEAD mode (such as GCM/CCM), and the received authentication tag
+ * does not match the calculated value
+ *
+ * @throws NullPointerException if either parameter is <CODE>null</CODE>
+ * @since 1.5
+ */
+ protected int engineDoFinal(ByteBuffer input, ByteBuffer output)
+ throws ShortBufferException, IllegalBlockSizeException,
+ BadPaddingException {
+ return bufferCrypt(input, output, false);
+ }
+
+ // copied from sun.security.jca.JCAUtil
+ // will be changed to reference that method once that code has been
+ // integrated and promoted
+ static int getTempArraySize(int totalSize) {
+ return Math.min(4096, totalSize);
+ }
+
+ /**
+ * Implementation for encryption using ByteBuffers. Used for both
+ * engineUpdate() and engineDoFinal().
+ */
+ private int bufferCrypt(ByteBuffer input, ByteBuffer output,
+ boolean isUpdate) throws ShortBufferException,
+ IllegalBlockSizeException, BadPaddingException {
+ if ((input == null) || (output == null)) {
+ throw new NullPointerException
+ ("Input and output buffers must not be null");
+ }
+ int inPos = input.position();
+ int inLimit = input.limit();
+ int inLen = inLimit - inPos;
+ if (isUpdate && (inLen == 0)) {
+ return 0;
+ }
+ int outLenNeeded = engineGetOutputSize(inLen);
+ if (output.remaining() < outLenNeeded) {
+ throw new ShortBufferException("Need at least " + outLenNeeded
+ + " bytes of space in output buffer");
+ }
+
+ boolean a1 = input.hasArray();
+ boolean a2 = output.hasArray();
+
+ if (a1 && a2) {
+ byte[] inArray = input.array();
+ int inOfs = input.arrayOffset() + inPos;
+ byte[] outArray = output.array();
+ int outPos = output.position();
+ int outOfs = output.arrayOffset() + outPos;
+ int n;
+ if (isUpdate) {
+ n = engineUpdate(inArray, inOfs, inLen, outArray, outOfs);
+ } else {
+ n = engineDoFinal(inArray, inOfs, inLen, outArray, outOfs);
+ }
+ input.position(inLimit);
+ output.position(outPos + n);
+ return n;
+ } else if (!a1 && a2) {
+ int outPos = output.position();
+ byte[] outArray = output.array();
+ int outOfs = output.arrayOffset() + outPos;
+ byte[] inArray = new byte[getTempArraySize(inLen)];
+ int total = 0;
+ do {
+ int chunk = Math.min(inLen, inArray.length);
+ if (chunk > 0) {
+ input.get(inArray, 0, chunk);
+ }
+ int n;
+ if (isUpdate || (inLen != chunk)) {
+ n = engineUpdate(inArray, 0, chunk, outArray, outOfs);
+ } else {
+ n = engineDoFinal(inArray, 0, chunk, outArray, outOfs);
+ }
+ total += n;
+ outOfs += n;
+ inLen -= chunk;
+ } while (inLen > 0);
+ output.position(outPos + total);
+ return total;
+ } else { // output is not backed by an accessible byte[]
+ byte[] inArray;
+ int inOfs;
+ if (a1) {
+ inArray = input.array();
+ inOfs = input.arrayOffset() + inPos;
+ } else {
+ inArray = new byte[getTempArraySize(inLen)];
+ inOfs = 0;
+ }
+ byte[] outArray = new byte[getTempArraySize(outLenNeeded)];
+ int outSize = outArray.length;
+ int total = 0;
+ boolean resized = false;
+ do {
+ int chunk =
+ Math.min(inLen, (outSize == 0? inArray.length : outSize));
+ if (!a1 && !resized && chunk > 0) {
+ input.get(inArray, 0, chunk);
+ inOfs = 0;
+ }
+ try {
+ int n;
+ if (isUpdate || (inLen != chunk)) {
+ n = engineUpdate(inArray, inOfs, chunk, outArray, 0);
+ } else {
+ n = engineDoFinal(inArray, inOfs, chunk, outArray, 0);
+ }
+ resized = false;
+ inOfs += chunk;
+ inLen -= chunk;
+ if (n > 0) {
+ output.put(outArray, 0, n);
+ total += n;
+ }
+ } catch (ShortBufferException e) {
+ if (resized) {
+ // we just resized the output buffer, but it still
+ // did not work. Bug in the provider, abort
+ throw (ProviderException)new ProviderException
+ ("Could not determine buffer size").initCause(e);
+ }
+ // output buffer is too small, realloc and try again
+ resized = true;
+ outSize = engineGetOutputSize(chunk);
+ outArray = new byte[outSize];
+ }
+ } while (inLen > 0);
+ if (a1) {
+ input.position(inLimit);
+ }
+ return total;
+ }
+ }
+
+ /**
+ * Wrap a key.
+ *
+ * <p>This concrete method has been added to this previously-defined
+ * abstract class. (For backwards compatibility, it cannot be abstract.)
+ * It may be overridden by a provider to wrap a key.
+ * Such an override is expected to throw an IllegalBlockSizeException or
+ * InvalidKeyException (under the specified circumstances),
+ * if the given key cannot be wrapped.
+ * If this method is not overridden, it always throws an
+ * UnsupportedOperationException.
+ *
+ * @param key the key to be wrapped.
+ *
+ * @return the wrapped key.
+ *
+ * @exception IllegalBlockSizeException if this cipher is a block cipher,
+ * no padding has been requested, and the length of the encoding of the
+ * key to be wrapped is not a multiple of the block size.
+ *
+ * @exception InvalidKeyException if it is impossible or unsafe to
+ * wrap the key with this cipher (e.g., a hardware protected key is
+ * being passed to a software-only cipher).
+ *
+ * @throws UnsupportedOperationException if this method is not supported.
+ */
+ protected byte[] engineWrap(Key key)
+ throws IllegalBlockSizeException, InvalidKeyException
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Unwrap a previously wrapped key.
+ *
+ * <p>This concrete method has been added to this previously-defined
+ * abstract class. (For backwards compatibility, it cannot be abstract.)
+ * It may be overridden by a provider to unwrap a previously wrapped key.
+ * Such an override is expected to throw an InvalidKeyException if
+ * the given wrapped key cannot be unwrapped.
+ * If this method is not overridden, it always throws an
+ * UnsupportedOperationException.
+ *
+ * @param wrappedKey the key to be unwrapped.
+ *
+ * @param wrappedKeyAlgorithm the algorithm associated with the wrapped
+ * key.
+ *
+ * @param wrappedKeyType the type of the wrapped key. This is one of
+ * <code>SECRET_KEY</code>, <code>PRIVATE_KEY</code>, or
+ * <code>PUBLIC_KEY</code>.
+ *
+ * @return the unwrapped key.
+ *
+ * @exception NoSuchAlgorithmException if no installed providers
+ * can create keys of type <code>wrappedKeyType</code> for the
+ * <code>wrappedKeyAlgorithm</code>.
+ *
+ * @exception InvalidKeyException if <code>wrappedKey</code> does not
+ * represent a wrapped key of type <code>wrappedKeyType</code> for
+ * the <code>wrappedKeyAlgorithm</code>.
+ *
+ * @throws UnsupportedOperationException if this method is not supported.
+ */
+ protected Key engineUnwrap(byte[] wrappedKey,
+ String wrappedKeyAlgorithm,
+ int wrappedKeyType)
+ throws InvalidKeyException, NoSuchAlgorithmException
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Returns the key size of the given key object in bits.
+ * <p>This concrete method has been added to this previously-defined
+ * abstract class. It throws an <code>UnsupportedOperationException</code>
+ * if it is not overridden by the provider.
+ *
+ * @param key the key object.
+ *
+ * @return the key size of the given key object.
+ *
+ * @exception InvalidKeyException if <code>key</code> is invalid.
+ */
+ protected int engineGetKeySize(Key key)
+ throws InvalidKeyException
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Continues a multi-part update of the Additional Authentication
+ * Data (AAD), using a subset of the provided buffer.
+ * <p>
+ * Calls to this method provide AAD to the cipher when operating in
+ * modes such as AEAD (GCM/CCM). If this cipher is operating in
+ * either GCM or CCM mode, all AAD must be supplied before beginning
+ * operations on the ciphertext (via the {@code update} and {@code
+ * doFinal} methods).
+ *
+ * @param src the buffer containing the AAD
+ * @param offset the offset in {@code src} where the AAD input starts
+ * @param len the number of AAD bytes
+ *
+ * @throws IllegalStateException if this cipher is in a wrong state
+ * (e.g., has not been initialized), does not accept AAD, or if
+ * operating in either GCM or CCM mode and one of the {@code update}
+ * methods has already been called for the active
+ * encryption/decryption operation
+ * @throws UnsupportedOperationException if this method
+ * has not been overridden by an implementation
+ *
+ * @since 1.7
+ */
+ protected void engineUpdateAAD(byte[] src, int offset, int len) {
+ throw new UnsupportedOperationException(
+ "The underlying Cipher implementation "
+ + "does not support this method");
+ }
+
+ /**
+ * Continues a multi-part update of the Additional Authentication
+ * Data (AAD).
+ * <p>
+ * Calls to this method provide AAD to the cipher when operating in
+ * modes such as AEAD (GCM/CCM). If this cipher is operating in
+ * either GCM or CCM mode, all AAD must be supplied before beginning
+ * operations on the ciphertext (via the {@code update} and {@code
+ * doFinal} methods).
+ * <p>
+ * All {@code src.remaining()} bytes starting at
+ * {@code src.position()} are processed.
+ * Upon return, the input buffer's position will be equal
+ * to its limit; its limit will not have changed.
+ *
+ * @param src the buffer containing the AAD
+ *
+ * @throws IllegalStateException if this cipher is in a wrong state
+ * (e.g., has not been initialized), does not accept AAD, or if
+ * operating in either GCM or CCM mode and one of the {@code update}
+ * methods has already been called for the active
+ * encryption/decryption operation
+ * @throws UnsupportedOperationException if this method
+ * has not been overridden by an implementation
+ *
+ * @since 1.7
+ */
+ protected void engineUpdateAAD(ByteBuffer src) {
+ throw new UnsupportedOperationException(
+ "The underlying Cipher implementation "
+ + "does not support this method");
+ }
+}
diff --git a/javax/crypto/CryptoAllPermission.java b/javax/crypto/CryptoAllPermission.java
new file mode 100644
index 0000000..8a973fc
--- /dev/null
+++ b/javax/crypto/CryptoAllPermission.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.crypto;
+
+// Android-changed: Stubbed the implementation. Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
+/**
+ * Legacy security code; do not use.
+ */
+
+final class CryptoAllPermission extends CryptoPermission {
+
+ static final String ALG_NAME = null;
+ static final CryptoAllPermission INSTANCE = null;
+
+ private CryptoAllPermission() { super(""); }
+}
diff --git a/javax/crypto/CryptoPermission.java b/javax/crypto/CryptoPermission.java
new file mode 100644
index 0000000..56973b6
--- /dev/null
+++ b/javax/crypto/CryptoPermission.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.crypto;
+
+import java.security.*;
+import java.security.spec.AlgorithmParameterSpec;
+
+// Android-changed: Stubbed the implementation. Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
+/**
+ * Legacy security code; do not use.
+ */
+class CryptoPermission extends java.security.Permission {
+
+ static final String ALG_NAME_WILDCARD = null;
+
+ CryptoPermission(String alg) { super(""); }
+
+ CryptoPermission(String alg, int maxKeySize) { super(""); }
+
+ CryptoPermission(String alg,
+ int maxKeySize,
+ AlgorithmParameterSpec algParamSpec) { super(""); }
+
+ CryptoPermission(String alg,
+ String exemptionMechanism) { super(""); }
+
+ CryptoPermission(String alg,
+ int maxKeySize,
+ String exemptionMechanism) { super(""); }
+
+ CryptoPermission(String alg,
+ int maxKeySize,
+ AlgorithmParameterSpec algParamSpec,
+ String exemptionMechanism) { super(""); }
+
+ public boolean implies(Permission p) { return true; }
+
+ public String getActions()
+ {
+ return null;
+ }
+
+ final String getAlgorithm() {
+ return null;
+ }
+
+ final String getExemptionMechanism() {
+ return null;
+ }
+
+
+ final int getMaxKeySize() {
+ return Integer.MAX_VALUE;
+ }
+
+ final boolean getCheckParam() {
+ return false;
+ }
+
+ final AlgorithmParameterSpec getAlgorithmParameterSpec() {
+ return null;
+ }
+}
diff --git a/javax/crypto/CryptoPermissions.java b/javax/crypto/CryptoPermissions.java
new file mode 100644
index 0000000..eef08b7
--- /dev/null
+++ b/javax/crypto/CryptoPermissions.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.crypto;
+
+import java.security.*;
+import java.util.Enumeration;
+import java.io.Serializable;
+import java.io.InputStream;
+import java.io.IOException;
+
+// Android-changed: Stubbed the implementation. Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
+/**
+ * Legacy security code; do not use.
+ */
+final class CryptoPermissions extends PermissionCollection
+implements Serializable {
+
+ CryptoPermissions() { }
+
+ void load(InputStream in)
+ throws IOException, CryptoPolicyParser.ParsingException { }
+
+ boolean isEmpty() {
+ return true;
+ }
+
+ public void add(Permission permission) { }
+
+ public boolean implies(Permission permission) { return true; }
+
+ public Enumeration elements() { return null; }
+
+ CryptoPermissions getMinimum(CryptoPermissions other) { return null; }
+
+ PermissionCollection getPermissionCollection(String alg) { return null; }
+}
diff --git a/javax/crypto/CryptoPolicyParser.java b/javax/crypto/CryptoPolicyParser.java
new file mode 100644
index 0000000..10bdc55
--- /dev/null
+++ b/javax/crypto/CryptoPolicyParser.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.crypto;
+
+import java.io.*;
+
+import java.security.GeneralSecurityException;
+
+// Android-changed: Stubbed the implementation. Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
+/**
+ * Legacy security code; do not use.
+ */
+
+final class CryptoPolicyParser {
+
+ CryptoPolicyParser() { }
+
+ void read(Reader policy)
+ throws ParsingException, IOException { }
+
+ CryptoPermission[] getPermissions() { return null; }
+
+ static final class ParsingException extends GeneralSecurityException {
+
+ ParsingException(String msg) {
+ super("");
+ }
+
+ ParsingException(int line, String msg) {
+ super("");
+ }
+
+ ParsingException(int line, String expect, String actual) {
+ super("");
+ }
+ }
+}
diff --git a/javax/crypto/EncryptedPrivateKeyInfo.java b/javax/crypto/EncryptedPrivateKeyInfo.java
new file mode 100644
index 0000000..5eeb481
--- /dev/null
+++ b/javax/crypto/EncryptedPrivateKeyInfo.java
@@ -0,0 +1,430 @@
+/*
+ * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.crypto;
+
+import java.io.*;
+import java.security.*;
+import java.security.spec.*;
+import sun.security.x509.AlgorithmId;
+import sun.security.util.DerValue;
+import sun.security.util.DerInputStream;
+import sun.security.util.DerOutputStream;
+
+/**
+ * This class implements the <code>EncryptedPrivateKeyInfo</code> type
+ * as defined in PKCS #8.
+ * <p>Its ASN.1 definition is as follows:
+ *
+ * <pre>
+ * EncryptedPrivateKeyInfo ::= SEQUENCE {
+ * encryptionAlgorithm AlgorithmIdentifier,
+ * encryptedData OCTET STRING }
+ *
+ * AlgorithmIdentifier ::= SEQUENCE {
+ * algorithm OBJECT IDENTIFIER,
+ * parameters ANY DEFINED BY algorithm OPTIONAL }
+ * </pre>
+ *
+ * @author Valerie Peng
+ *
+ * @see java.security.spec.PKCS8EncodedKeySpec
+ *
+ * @since 1.4
+ */
+
+public class EncryptedPrivateKeyInfo {
+
+ // the "encryptionAlgorithm" field
+ private AlgorithmId algid;
+
+ // the "encryptedData" field
+ private byte[] encryptedData;
+
+ // the ASN.1 encoded contents of this class
+ private byte[] encoded = null;
+
+ /**
+ * Constructs (i.e., parses) an <code>EncryptedPrivateKeyInfo</code> from
+ * its ASN.1 encoding.
+ * @param encoded the ASN.1 encoding of this object. The contents of
+ * the array are copied to protect against subsequent modification.
+ * @exception NullPointerException if the <code>encoded</code> is null.
+ * @exception IOException if error occurs when parsing the ASN.1 encoding.
+ */
+ public EncryptedPrivateKeyInfo(byte[] encoded)
+ throws IOException {
+ if (encoded == null) {
+ throw new NullPointerException("the encoded parameter " +
+ "must be non-null");
+ }
+ this.encoded = encoded.clone();
+ DerValue val = new DerValue(this.encoded);
+
+ DerValue[] seq = new DerValue[2];
+
+ seq[0] = val.data.getDerValue();
+ seq[1] = val.data.getDerValue();
+
+ if (val.data.available() != 0) {
+ throw new IOException("overrun, bytes = " + val.data.available());
+ }
+
+ this.algid = AlgorithmId.parse(seq[0]);
+ if (seq[0].data.available() != 0) {
+ throw new IOException("encryptionAlgorithm field overrun");
+ }
+
+ this.encryptedData = seq[1].getOctetString();
+ if (seq[1].data.available() != 0) {
+ throw new IOException("encryptedData field overrun");
+ }
+ }
+
+ /**
+ * Constructs an <code>EncryptedPrivateKeyInfo</code> from the
+ * encryption algorithm name and the encrypted data.
+ *
+ * <p>Note: This constructor will use null as the value of the
+ * algorithm parameters. If the encryption algorithm has
+ * parameters whose value is not null, a different constructor,
+ * e.g. EncryptedPrivateKeyInfo(AlgorithmParameters, byte[]),
+ * should be used.
+ *
+ * @param algName encryption algorithm name. See Appendix A in the
+ * <a href=
+ * "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppA">
+ * Java Cryptography Architecture Reference Guide</a>
+ * for information about standard Cipher algorithm names.
+ * @param encryptedData encrypted data. The contents of
+ * <code>encrypedData</code> are copied to protect against subsequent
+ * modification when constructing this object.
+ * @exception NullPointerException if <code>algName</code> or
+ * <code>encryptedData</code> is null.
+ * @exception IllegalArgumentException if <code>encryptedData</code>
+ * is empty, i.e. 0-length.
+ * @exception NoSuchAlgorithmException if the specified algName is
+ * not supported.
+ */
+ public EncryptedPrivateKeyInfo(String algName, byte[] encryptedData)
+ throws NoSuchAlgorithmException {
+
+ if (algName == null)
+ throw new NullPointerException("the algName parameter " +
+ "must be non-null");
+ this.algid = AlgorithmId.get(algName);
+
+ if (encryptedData == null) {
+ throw new NullPointerException("the encryptedData " +
+ "parameter must be non-null");
+ } else if (encryptedData.length == 0) {
+ throw new IllegalArgumentException("the encryptedData " +
+ "parameter must not be empty");
+ } else {
+ this.encryptedData = encryptedData.clone();
+ }
+ // delay the generation of ASN.1 encoding until
+ // getEncoded() is called
+ this.encoded = null;
+ }
+
+ /**
+ * Constructs an <code>EncryptedPrivateKeyInfo</code> from the
+ * encryption algorithm parameters and the encrypted data.
+ *
+ * @param algParams the algorithm parameters for the encryption
+ * algorithm. <code>algParams.getEncoded()</code> should return
+ * the ASN.1 encoded bytes of the <code>parameters</code> field
+ * of the <code>AlgorithmIdentifer</code> component of the
+ * <code>EncryptedPrivateKeyInfo</code> type.
+ * @param encryptedData encrypted data. The contents of
+ * <code>encrypedData</code> are copied to protect against
+ * subsequent modification when constructing this object.
+ * @exception NullPointerException if <code>algParams</code> or
+ * <code>encryptedData</code> is null.
+ * @exception IllegalArgumentException if <code>encryptedData</code>
+ * is empty, i.e. 0-length.
+ * @exception NoSuchAlgorithmException if the specified algName of
+ * the specified <code>algParams</code> parameter is not supported.
+ */
+ public EncryptedPrivateKeyInfo(AlgorithmParameters algParams,
+ byte[] encryptedData) throws NoSuchAlgorithmException {
+
+ if (algParams == null) {
+ throw new NullPointerException("algParams must be non-null");
+ }
+ this.algid = AlgorithmId.get(algParams);
+
+ if (encryptedData == null) {
+ throw new NullPointerException("encryptedData must be non-null");
+ } else if (encryptedData.length == 0) {
+ throw new IllegalArgumentException("the encryptedData " +
+ "parameter must not be empty");
+ } else {
+ this.encryptedData = encryptedData.clone();
+ }
+
+ // delay the generation of ASN.1 encoding until
+ // getEncoded() is called
+ this.encoded = null;
+ }
+
+
+ /**
+ * Returns the encryption algorithm.
+ * <p>Note: Standard name is returned instead of the specified one
+ * in the constructor when such mapping is available.
+ * See Appendix A in the
+ * <a href=
+ * "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppA">
+ * Java Cryptography Architecture Reference Guide</a>
+ * for information about standard Cipher algorithm names.
+ *
+ * @return the encryption algorithm name.
+ */
+ public String getAlgName() {
+ return this.algid.getName();
+ }
+
+ /**
+ * Returns the algorithm parameters used by the encryption algorithm.
+ * @return the algorithm parameters.
+ */
+ public AlgorithmParameters getAlgParameters() {
+ return this.algid.getParameters();
+ }
+
+ /**
+ * Returns the encrypted data.
+ * @return the encrypted data. Returns a new array
+ * each time this method is called.
+ */
+ public byte[] getEncryptedData() {
+ return this.encryptedData.clone();
+ }
+
+ /**
+ * Extract the enclosed PKCS8EncodedKeySpec object from the
+ * encrypted data and return it.
+ * <br>Note: In order to successfully retrieve the enclosed
+ * PKCS8EncodedKeySpec object, <code>cipher</code> needs
+ * to be initialized to either Cipher.DECRYPT_MODE or
+ * Cipher.UNWRAP_MODE, with the same key and parameters used
+ * for generating the encrypted data.
+ *
+ * @param cipher the initialized cipher object which will be
+ * used for decrypting the encrypted data.
+ * @return the PKCS8EncodedKeySpec object.
+ * @exception NullPointerException if <code>cipher</code>
+ * is null.
+ * @exception InvalidKeySpecException if the given cipher is
+ * inappropriate for the encrypted data or the encrypted
+ * data is corrupted and cannot be decrypted.
+ */
+ public PKCS8EncodedKeySpec getKeySpec(Cipher cipher)
+ throws InvalidKeySpecException {
+ byte[] encoded = null;
+ try {
+ encoded = cipher.doFinal(encryptedData);
+ checkPKCS8Encoding(encoded);
+ } catch (GeneralSecurityException |
+ IOException |
+ IllegalStateException ex) {
+ throw new InvalidKeySpecException(
+ "Cannot retrieve the PKCS8EncodedKeySpec", ex);
+ }
+ return new PKCS8EncodedKeySpec(encoded);
+ }
+
+ private PKCS8EncodedKeySpec getKeySpecImpl(Key decryptKey,
+ Provider provider) throws NoSuchAlgorithmException,
+ InvalidKeyException {
+ byte[] encoded = null;
+ Cipher c;
+ try {
+ if (provider == null) {
+ // use the most preferred one
+ c = Cipher.getInstance(algid.getName());
+ } else {
+ c = Cipher.getInstance(algid.getName(), provider);
+ }
+ c.init(Cipher.DECRYPT_MODE, decryptKey, algid.getParameters());
+ encoded = c.doFinal(encryptedData);
+ checkPKCS8Encoding(encoded);
+ } catch (NoSuchAlgorithmException nsae) {
+ // rethrow
+ throw nsae;
+ } catch (GeneralSecurityException | IOException ex) {
+ throw new InvalidKeyException(
+ "Cannot retrieve the PKCS8EncodedKeySpec", ex);
+ }
+ return new PKCS8EncodedKeySpec(encoded);
+ }
+
+ /**
+ * Extract the enclosed PKCS8EncodedKeySpec object from the
+ * encrypted data and return it.
+ * @param decryptKey key used for decrypting the encrypted data.
+ * @return the PKCS8EncodedKeySpec object.
+ * @exception NullPointerException if <code>decryptKey</code>
+ * is null.
+ * @exception NoSuchAlgorithmException if cannot find appropriate
+ * cipher to decrypt the encrypted data.
+ * @exception InvalidKeyException if <code>decryptKey</code>
+ * cannot be used to decrypt the encrypted data or the decryption
+ * result is not a valid PKCS8KeySpec.
+ *
+ * @since 1.5
+ */
+ public PKCS8EncodedKeySpec getKeySpec(Key decryptKey)
+ throws NoSuchAlgorithmException, InvalidKeyException {
+ if (decryptKey == null) {
+ throw new NullPointerException("decryptKey is null");
+ }
+ return getKeySpecImpl(decryptKey, null);
+ }
+
+ /**
+ * Extract the enclosed PKCS8EncodedKeySpec object from the
+ * encrypted data and return it.
+ * @param decryptKey key used for decrypting the encrypted data.
+ * @param providerName the name of provider whose Cipher
+ * implementation will be used.
+ * @return the PKCS8EncodedKeySpec object.
+ * @exception NullPointerException if <code>decryptKey</code>
+ * or <code>providerName</code> is null.
+ * @exception NoSuchProviderException if no provider
+ * <code>providerName</code> is registered.
+ * @exception NoSuchAlgorithmException if cannot find appropriate
+ * cipher to decrypt the encrypted data.
+ * @exception InvalidKeyException if <code>decryptKey</code>
+ * cannot be used to decrypt the encrypted data or the decryption
+ * result is not a valid PKCS8KeySpec.
+ *
+ * @since 1.5
+ */
+ public PKCS8EncodedKeySpec getKeySpec(Key decryptKey,
+ String providerName) throws NoSuchProviderException,
+ NoSuchAlgorithmException, InvalidKeyException {
+ if (decryptKey == null) {
+ throw new NullPointerException("decryptKey is null");
+ }
+ if (providerName == null) {
+ throw new NullPointerException("provider is null");
+ }
+ Provider provider = Security.getProvider(providerName);
+ if (provider == null) {
+ throw new NoSuchProviderException("provider " +
+ providerName + " not found");
+ }
+ return getKeySpecImpl(decryptKey, provider);
+ }
+
+ /**
+ * Extract the enclosed PKCS8EncodedKeySpec object from the
+ * encrypted data and return it.
+ * @param decryptKey key used for decrypting the encrypted data.
+ * @param provider the name of provider whose Cipher implementation
+ * will be used.
+ * @return the PKCS8EncodedKeySpec object.
+ * @exception NullPointerException if <code>decryptKey</code>
+ * or <code>provider</code> is null.
+ * @exception NoSuchAlgorithmException if cannot find appropriate
+ * cipher to decrypt the encrypted data in <code>provider</code>.
+ * @exception InvalidKeyException if <code>decryptKey</code>
+ * cannot be used to decrypt the encrypted data or the decryption
+ * result is not a valid PKCS8KeySpec.
+ *
+ * @since 1.5
+ */
+ public PKCS8EncodedKeySpec getKeySpec(Key decryptKey,
+ Provider provider) throws NoSuchAlgorithmException,
+ InvalidKeyException {
+ if (decryptKey == null) {
+ throw new NullPointerException("decryptKey is null");
+ }
+ if (provider == null) {
+ throw new NullPointerException("provider is null");
+ }
+ return getKeySpecImpl(decryptKey, provider);
+ }
+
+ /**
+ * Returns the ASN.1 encoding of this object.
+ * @return the ASN.1 encoding. Returns a new array
+ * each time this method is called.
+ * @exception IOException if error occurs when constructing its
+ * ASN.1 encoding.
+ */
+ public byte[] getEncoded() throws IOException {
+ if (this.encoded == null) {
+ DerOutputStream out = new DerOutputStream();
+ DerOutputStream tmp = new DerOutputStream();
+
+ // encode encryption algorithm
+ algid.encode(tmp);
+
+ // encode encrypted data
+ tmp.putOctetString(encryptedData);
+
+ // wrap everything into a SEQUENCE
+ out.write(DerValue.tag_Sequence, tmp);
+ this.encoded = out.toByteArray();
+ }
+ return this.encoded.clone();
+ }
+
+ private static void checkTag(DerValue val, byte tag, String valName)
+ throws IOException {
+ if (val.getTag() != tag) {
+ throw new IOException("invalid key encoding - wrong tag for " +
+ valName);
+ }
+ }
+
+ @SuppressWarnings("fallthrough")
+ private static void checkPKCS8Encoding(byte[] encodedKey)
+ throws IOException {
+ DerInputStream in = new DerInputStream(encodedKey);
+ DerValue[] values = in.getSequence(3);
+
+ switch (values.length) {
+ case 4:
+ checkTag(values[3], DerValue.TAG_CONTEXT, "attributes");
+ /* fall through */
+ case 3:
+ checkTag(values[0], DerValue.tag_Integer, "version");
+ DerInputStream algid = values[1].toDerInputStream();
+ algid.getOID();
+ if (algid.available() != 0) {
+ algid.getDerValue();
+ }
+ checkTag(values[2], DerValue.tag_OctetString, "privateKey");
+ break;
+ default:
+ throw new IOException("invalid key encoding");
+ }
+ }
+}
diff --git a/javax/crypto/ExemptionMechanism.java b/javax/crypto/ExemptionMechanism.java
new file mode 100644
index 0000000..b90ab43
--- /dev/null
+++ b/javax/crypto/ExemptionMechanism.java
@@ -0,0 +1,486 @@
+/*
+ * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.crypto;
+
+import java.security.AlgorithmParameters;
+import java.security.Provider;
+import java.security.Key;
+import java.security.Security;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.InvalidKeyException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.spec.AlgorithmParameterSpec;
+
+import sun.security.jca.GetInstance.Instance;
+
+/**
+ * This class provides the functionality of an exemption mechanism, examples
+ * of which are <i>key recovery</i>, <i>key weakening</i>, and
+ * <i>key escrow</i>.
+ *
+ * <p>Applications or applets that use an exemption mechanism may be granted
+ * stronger encryption capabilities than those which don't.
+ *
+ * @since 1.4
+ */
+
+public class ExemptionMechanism {
+
+ // The provider
+ private Provider provider;
+
+ // The provider implementation (delegate)
+ private ExemptionMechanismSpi exmechSpi;
+
+ // The name of the exemption mechanism.
+ private String mechanism;
+
+ // Flag which indicates whether this ExemptionMechanism
+ // result is generated successfully.
+ private boolean done = false;
+
+ // State information
+ private boolean initialized = false;
+
+ // Store away the key at init() time for later comparison.
+ private Key keyStored = null;
+
+ /**
+ * Creates a ExemptionMechanism object.
+ *
+ * @param exmechSpi the delegate
+ * @param provider the provider
+ * @param mechanism the exemption mechanism
+ */
+ protected ExemptionMechanism(ExemptionMechanismSpi exmechSpi,
+ Provider provider,
+ String mechanism) {
+ this.exmechSpi = exmechSpi;
+ this.provider = provider;
+ this.mechanism = mechanism;
+ }
+
+ /**
+ * Returns the exemption mechanism name of this
+ * <code>ExemptionMechanism</code> object.
+ *
+ * <p>This is the same name that was specified in one of the
+ * <code>getInstance</code> calls that created this
+ * <code>ExemptionMechanism</code> object.
+ *
+ * @return the exemption mechanism name of this
+ * <code>ExemptionMechanism</code> object.
+ */
+ public final String getName() {
+ return this.mechanism;
+ }
+
+ /**
+ * Returns an <code>ExemptionMechanism</code> object that implements the
+ * specified exemption mechanism algorithm.
+ *
+ * <p> This method traverses the list of registered security Providers,
+ * starting with the most preferred Provider.
+ * A new ExemptionMechanism object encapsulating the
+ * ExemptionMechanismSpi implementation from the first
+ * Provider that supports the specified algorithm is returned.
+ *
+ * <p> Note that the list of registered providers may be retrieved via
+ * the {@link Security#getProviders() Security.getProviders()} method.
+ *
+ * @param algorithm the standard name of the requested exemption
+ * mechanism.
+ * See the ExemptionMechanism section in the
+ * <a href=
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#Exemption">
+ * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+ * for information about standard exemption mechanism names.
+ *
+ * @return the new <code>ExemptionMechanism</code> object.
+ *
+ * @exception NullPointerException if <code>algorithm</code>
+ * is null.
+ *
+ * @exception NoSuchAlgorithmException if no Provider supports an
+ * ExemptionMechanismSpi implementation for the
+ * specified algorithm.
+ *
+ * @see java.security.Provider
+ */
+ public static final ExemptionMechanism getInstance(String algorithm)
+ throws NoSuchAlgorithmException {
+ Instance instance = JceSecurity.getInstance("ExemptionMechanism",
+ ExemptionMechanismSpi.class, algorithm);
+ return new ExemptionMechanism((ExemptionMechanismSpi)instance.impl,
+ instance.provider, algorithm);
+ }
+
+
+ /**
+ * Returns an <code>ExemptionMechanism</code> object that implements the
+ * specified exemption mechanism algorithm.
+ *
+ * <p> A new ExemptionMechanism object encapsulating the
+ * ExemptionMechanismSpi implementation from the specified provider
+ * is returned. The specified provider must be registered
+ * in the security provider list.
+ *
+ * <p> Note that the list of registered providers may be retrieved via
+ * the {@link Security#getProviders() Security.getProviders()} method.
+
+ * @param algorithm the standard name of the requested exemption mechanism.
+ * See the ExemptionMechanism section in the
+ * <a href=
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#Exemption">
+ * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+ * for information about standard exemption mechanism names.
+ *
+ * @param provider the name of the provider.
+ *
+ * @return the new <code>ExemptionMechanism</code> object.
+ *
+ * @exception NullPointerException if <code>algorithm</code>
+ * is null.
+ *
+ * @exception NoSuchAlgorithmException if an ExemptionMechanismSpi
+ * implementation for the specified algorithm is not
+ * available from the specified provider.
+ *
+ * @exception NoSuchProviderException if the specified provider is not
+ * registered in the security provider list.
+ *
+ * @exception IllegalArgumentException if the <code>provider</code>
+ * is null or empty.
+ *
+ * @see java.security.Provider
+ */
+ public static final ExemptionMechanism getInstance(String algorithm,
+ String provider) throws NoSuchAlgorithmException,
+ NoSuchProviderException {
+ Instance instance = JceSecurity.getInstance("ExemptionMechanism",
+ ExemptionMechanismSpi.class, algorithm, provider);
+ return new ExemptionMechanism((ExemptionMechanismSpi)instance.impl,
+ instance.provider, algorithm);
+ }
+
+ /**
+ * Returns an <code>ExemptionMechanism</code> object that implements the
+ * specified exemption mechanism algorithm.
+ *
+ * <p> A new ExemptionMechanism object encapsulating the
+ * ExemptionMechanismSpi implementation from the specified Provider
+ * object is returned. Note that the specified Provider object
+ * does not have to be registered in the provider list.
+ *
+ * @param algorithm the standard name of the requested exemption mechanism.
+ * See the ExemptionMechanism section in the
+ * <a href=
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#Exemption">
+ * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+ * for information about standard exemption mechanism names.
+ *
+ * @param provider the provider.
+ *
+ * @return the new <code>ExemptionMechanism</code> object.
+ *
+ * @exception NullPointerException if <code>algorithm</code>
+ * is null.
+ *
+ * @exception NoSuchAlgorithmException if an ExemptionMechanismSpi
+ * implementation for the specified algorithm is not available
+ * from the specified Provider object.
+ *
+ * @exception IllegalArgumentException if the <code>provider</code>
+ * is null.
+ *
+ * @see java.security.Provider
+ */
+ public static final ExemptionMechanism getInstance(String algorithm,
+ Provider provider) throws NoSuchAlgorithmException {
+ Instance instance = JceSecurity.getInstance("ExemptionMechanism",
+ ExemptionMechanismSpi.class, algorithm, provider);
+ return new ExemptionMechanism((ExemptionMechanismSpi)instance.impl,
+ instance.provider, algorithm);
+ }
+
+ /**
+ * Returns the provider of this <code>ExemptionMechanism</code> object.
+ *
+ * @return the provider of this <code>ExemptionMechanism</code> object.
+ */
+ public final Provider getProvider() {
+ return this.provider;
+ }
+
+ /**
+ * Returns whether the result blob has been generated successfully by this
+ * exemption mechanism.
+ *
+ * <p>The method also makes sure that the key passed in is the same as
+ * the one this exemption mechanism used in initializing and generating
+ * phases.
+ *
+ * @param key the key the crypto is going to use.
+ *
+ * @return whether the result blob of the same key has been generated
+ * successfully by this exemption mechanism; false if <code>key</code>
+ * is null.
+ *
+ * @exception ExemptionMechanismException if problem(s) encountered
+ * while determining whether the result blob has been generated successfully
+ * by this exemption mechanism object.
+ */
+ public final boolean isCryptoAllowed(Key key)
+ throws ExemptionMechanismException {
+ boolean ret = false;
+ if (done && (key != null)) {
+ // Check if the key passed in is the same as the one
+ // this exemption mechanism used.
+ ret = keyStored.equals(key);
+ }
+ return ret;
+ }
+
+ /**
+ * Returns the length in bytes that an output buffer would need to be in
+ * order to hold the result of the next
+ * {@link #genExemptionBlob(byte[]) genExemptionBlob}
+ * operation, given the input length <code>inputLen</code> (in bytes).
+ *
+ * <p>The actual output length of the next
+ * {@link #genExemptionBlob(byte[]) genExemptionBlob}
+ * call may be smaller than the length returned by this method.
+ *
+ * @param inputLen the input length (in bytes)
+ *
+ * @return the required output buffer size (in bytes)
+ *
+ * @exception IllegalStateException if this exemption mechanism is in a
+ * wrong state (e.g., has not yet been initialized)
+ */
+ public final int getOutputSize(int inputLen) throws IllegalStateException {
+ if (!initialized) {
+ throw new IllegalStateException(
+ "ExemptionMechanism not initialized");
+ }
+ if (inputLen < 0) {
+ throw new IllegalArgumentException(
+ "Input size must be equal to " + "or greater than zero");
+ }
+ return exmechSpi.engineGetOutputSize(inputLen);
+ }
+
+ /**
+ * Initializes this exemption mechanism with a key.
+ *
+ * <p>If this exemption mechanism requires any algorithm parameters
+ * that cannot be derived from the given <code>key</code>, the
+ * underlying exemption mechanism implementation is supposed to
+ * generate the required parameters itself (using provider-specific
+ * default values); in the case that algorithm parameters must be
+ * specified by the caller, an <code>InvalidKeyException</code> is raised.
+ *
+ * @param key the key for this exemption mechanism
+ *
+ * @exception InvalidKeyException if the given key is inappropriate for
+ * this exemption mechanism.
+ * @exception ExemptionMechanismException if problem(s) encountered in the
+ * process of initializing.
+ */
+ public final void init(Key key)
+ throws InvalidKeyException, ExemptionMechanismException {
+ done = false;
+ initialized = false;
+
+ keyStored = key;
+ exmechSpi.engineInit(key);
+ initialized = true;
+ }
+
+ /**
+ * Initializes this exemption mechanism with a key and a set of algorithm
+ * parameters.
+ *
+ * <p>If this exemption mechanism requires any algorithm parameters
+ * and <code>params</code> is null, the underlying exemption
+ * mechanism implementation is supposed to generate the required
+ * parameters itself (using provider-specific default values); in the case
+ * that algorithm parameters must be specified by the caller, an
+ * <code>InvalidAlgorithmParameterException</code> is raised.
+ *
+ * @param key the key for this exemption mechanism
+ * @param params the algorithm parameters
+ *
+ * @exception InvalidKeyException if the given key is inappropriate for
+ * this exemption mechanism.
+ * @exception InvalidAlgorithmParameterException if the given algorithm
+ * parameters are inappropriate for this exemption mechanism.
+ * @exception ExemptionMechanismException if problem(s) encountered in the
+ * process of initializing.
+ */
+ public final void init(Key key, AlgorithmParameterSpec params)
+ throws InvalidKeyException, InvalidAlgorithmParameterException,
+ ExemptionMechanismException {
+ done = false;
+ initialized = false;
+
+ keyStored = key;
+ exmechSpi.engineInit(key, params);
+ initialized = true;
+ }
+
+ /**
+ * Initializes this exemption mechanism with a key and a set of algorithm
+ * parameters.
+ *
+ * <p>If this exemption mechanism requires any algorithm parameters
+ * and <code>params</code> is null, the underlying exemption mechanism
+ * implementation is supposed to generate the required parameters itself
+ * (using provider-specific default values); in the case that algorithm
+ * parameters must be specified by the caller, an
+ * <code>InvalidAlgorithmParameterException</code> is raised.
+ *
+ * @param key the key for this exemption mechanism
+ * @param params the algorithm parameters
+ *
+ * @exception InvalidKeyException if the given key is inappropriate for
+ * this exemption mechanism.
+ * @exception InvalidAlgorithmParameterException if the given algorithm
+ * parameters are inappropriate for this exemption mechanism.
+ * @exception ExemptionMechanismException if problem(s) encountered in the
+ * process of initializing.
+ */
+ public final void init(Key key, AlgorithmParameters params)
+ throws InvalidKeyException, InvalidAlgorithmParameterException,
+ ExemptionMechanismException {
+ done = false;
+ initialized = false;
+
+ keyStored = key;
+ exmechSpi.engineInit(key, params);
+ initialized = true;
+ }
+
+ /**
+ * Generates the exemption mechanism key blob.
+ *
+ * @return the new buffer with the result key blob.
+ *
+ * @exception IllegalStateException if this exemption mechanism is in
+ * a wrong state (e.g., has not been initialized).
+ * @exception ExemptionMechanismException if problem(s) encountered in the
+ * process of generating.
+ */
+ public final byte[] genExemptionBlob() throws IllegalStateException,
+ ExemptionMechanismException {
+ if (!initialized) {
+ throw new IllegalStateException(
+ "ExemptionMechanism not initialized");
+ }
+ byte[] blob = exmechSpi.engineGenExemptionBlob();
+ done = true;
+ return blob;
+ }
+
+ /**
+ * Generates the exemption mechanism key blob, and stores the result in
+ * the <code>output</code> buffer.
+ *
+ * <p>If the <code>output</code> buffer is too small to hold the result,
+ * a <code>ShortBufferException</code> is thrown. In this case, repeat this
+ * call with a larger output buffer. Use
+ * {@link #getOutputSize(int) getOutputSize} to determine how big
+ * the output buffer should be.
+ *
+ * @param output the buffer for the result
+ *
+ * @return the number of bytes stored in <code>output</code>
+ *
+ * @exception IllegalStateException if this exemption mechanism is in
+ * a wrong state (e.g., has not been initialized).
+ * @exception ShortBufferException if the given output buffer is too small
+ * to hold the result.
+ * @exception ExemptionMechanismException if problem(s) encountered in the
+ * process of generating.
+ */
+ public final int genExemptionBlob(byte[] output)
+ throws IllegalStateException, ShortBufferException,
+ ExemptionMechanismException {
+ if (!initialized) {
+ throw new IllegalStateException
+ ("ExemptionMechanism not initialized");
+ }
+ int n = exmechSpi.engineGenExemptionBlob(output, 0);
+ done = true;
+ return n;
+ }
+
+ /**
+ * Generates the exemption mechanism key blob, and stores the result in
+ * the <code>output</code> buffer, starting at <code>outputOffset</code>
+ * inclusive.
+ *
+ * <p>If the <code>output</code> buffer is too small to hold the result,
+ * a <code>ShortBufferException</code> is thrown. In this case, repeat this
+ * call with a larger output buffer. Use
+ * {@link #getOutputSize(int) getOutputSize} to determine how big
+ * the output buffer should be.
+ *
+ * @param output the buffer for the result
+ * @param outputOffset the offset in <code>output</code> where the result
+ * is stored
+ *
+ * @return the number of bytes stored in <code>output</code>
+ *
+ * @exception IllegalStateException if this exemption mechanism is in
+ * a wrong state (e.g., has not been initialized).
+ * @exception ShortBufferException if the given output buffer is too small
+ * to hold the result.
+ * @exception ExemptionMechanismException if problem(s) encountered in the
+ * process of generating.
+ */
+ public final int genExemptionBlob(byte[] output, int outputOffset)
+ throws IllegalStateException, ShortBufferException,
+ ExemptionMechanismException {
+ if (!initialized) {
+ throw new IllegalStateException
+ ("ExemptionMechanism not initialized");
+ }
+ int n = exmechSpi.engineGenExemptionBlob(output, outputOffset);
+ done = true;
+ return n;
+ }
+
+ // Android-removed: Unnecessary finalize() method.
+ // OpenJDK 9 also removed the method.
+ /*
+ protected void finalize() {
+ keyStored = null;
+ // Are there anything else we could do?
+ }
+ */
+}
diff --git a/javax/crypto/ExemptionMechanismException.java b/javax/crypto/ExemptionMechanismException.java
new file mode 100644
index 0000000..2fdc885
--- /dev/null
+++ b/javax/crypto/ExemptionMechanismException.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.crypto;
+
+import java.security.GeneralSecurityException;
+
+/**
+ * This is the generic ExemptionMechanism exception.
+ *
+ * @since 1.4
+ */
+
+public class ExemptionMechanismException extends GeneralSecurityException {
+
+ private static final long serialVersionUID = 1572699429277957109L;
+
+ /**
+ * Constructs a ExemptionMechanismException with no detailed message.
+ * (A detailed message is a String that describes this particular
+ * exception.)
+ */
+ public ExemptionMechanismException() {
+ super();
+ }
+
+ /**
+ * Constructs a ExemptionMechanismException with the specified
+ * detailed message. (A detailed message is a String that describes
+ * this particular exception.)
+ *
+ * @param msg the detailed message.
+ */
+ public ExemptionMechanismException(String msg) {
+ super(msg);
+ }
+}
diff --git a/javax/crypto/ExemptionMechanismSpi.java b/javax/crypto/ExemptionMechanismSpi.java
new file mode 100644
index 0000000..9a6d524
--- /dev/null
+++ b/javax/crypto/ExemptionMechanismSpi.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.crypto;
+
+import java.security.Key;
+import java.security.AlgorithmParameters;
+import java.security.InvalidKeyException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>)
+ * for the <code>ExemptionMechanism</code> class.
+ * All the abstract methods in this class must be implemented by each
+ * cryptographic service provider who wishes to supply the implementation
+ * of a particular exemption mechanism.
+ *
+ * @author Sharon Liu
+ *
+ * @since 1.4
+ */
+
+public abstract class ExemptionMechanismSpi {
+
+ /**
+ * Returns the length in bytes that an output buffer would need to be in
+ * order to hold the result of the next
+ * {@link #engineGenExemptionBlob(byte[], int) engineGenExemptionBlob}
+ * operation, given the input length <code>inputLen</code> (in bytes).
+ *
+ * <p>The actual output length of the next
+ * {@link #engineGenExemptionBlob(byte[], int) engineGenExemptionBlob}
+ * call may be smaller than the length returned by this method.
+ *
+ * @param inputLen the input length (in bytes)
+ *
+ * @return the required output buffer size (in bytes)
+ */
+ protected abstract int engineGetOutputSize(int inputLen);
+
+ /**
+ * Initializes this exemption mechanism with a key.
+ *
+ * <p>If this exemption mechanism requires any algorithm parameters
+ * that cannot be derived from the given <code>key</code>, the underlying
+ * exemption mechanism implementation is supposed to generate the required
+ * parameters itself (using provider-specific default values); in the case
+ * that algorithm parameters must be specified by the caller, an
+ * <code>InvalidKeyException</code> is raised.
+ *
+ * @param key the key for this exemption mechanism
+ *
+ * @exception InvalidKeyException if the given key is inappropriate for
+ * this exemption mechanism.
+ * @exception ExemptionMechanismException if problem(s) encountered in the
+ * process of initializing.
+ */
+ protected abstract void engineInit(Key key)
+ throws InvalidKeyException, ExemptionMechanismException;
+
+ /**
+ * Initializes this exemption mechanism with a key and a set of algorithm
+ * parameters.
+ *
+ * <p>If this exemption mechanism requires any algorithm parameters and
+ * <code>params</code> is null, the underlying exemption mechanism
+ * implementation is supposed to generate the required parameters
+ * itself (using provider-specific default values); in the case that
+ * algorithm parameters must be specified by the caller, an
+ * <code>InvalidAlgorithmParameterException</code> is raised.
+ *
+ * @param key the key for this exemption mechanism
+ * @param params the algorithm parameters
+ *
+ * @exception InvalidKeyException if the given key is inappropriate for
+ * this exemption mechanism.
+ * @exception InvalidAlgorithmParameterException if the given algorithm
+ * parameters are inappropriate for this exemption mechanism.
+ * @exception ExemptionMechanismException if problem(s) encountered in the
+ * process of initializing.
+ */
+ protected abstract void engineInit(Key key, AlgorithmParameterSpec params)
+ throws InvalidKeyException, InvalidAlgorithmParameterException,
+ ExemptionMechanismException;
+
+ /**
+ * Initializes this exemption mechanism with a key and a set of algorithm
+ * parameters.
+ *
+ * <p>If this exemption mechanism requires any algorithm parameters
+ * and <code>params</code> is null, the underlying exemption mechanism
+ * implementation is supposed to generate the required parameters
+ * itself (using provider-specific default values); in the case that
+ * algorithm parameters must be specified by the caller, an
+ * <code>InvalidAlgorithmParameterException</code> is raised.
+ *
+ * @param key the key for this exemption mechanism
+ * @param params the algorithm parameters
+ *
+ * @exception InvalidKeyException if the given key is inappropriate for
+ * this exemption mechanism.
+ * @exception InvalidAlgorithmParameterException if the given algorithm
+ * parameters are inappropriate for this exemption mechanism.
+ * @exception ExemptionMechanismException if problem(s) encountered in the
+ * process of initializing.
+ */
+ protected abstract void engineInit(Key key, AlgorithmParameters params)
+ throws InvalidKeyException, InvalidAlgorithmParameterException,
+ ExemptionMechanismException;
+
+ /**
+ * Generates the exemption mechanism key blob.
+ *
+ * @return the new buffer with the result key blob.
+ *
+ * @exception ExemptionMechanismException if problem(s) encountered in the
+ * process of generating.
+ */
+ protected abstract byte[] engineGenExemptionBlob()
+ throws ExemptionMechanismException;
+
+ /**
+ * Generates the exemption mechanism key blob, and stores the result in
+ * the <code>output</code> buffer, starting at <code>outputOffset</code>
+ * inclusive.
+ *
+ * <p>If the <code>output</code> buffer is too small to hold the result,
+ * a <code>ShortBufferException</code> is thrown. In this case, repeat this
+ * call with a larger output buffer. Use
+ * {@link #engineGetOutputSize(int) engineGetOutputSize} to determine
+ * how big the output buffer should be.
+ *
+ * @param output the buffer for the result
+ * @param outputOffset the offset in <code>output</code> where the result
+ * is stored
+ *
+ * @return the number of bytes stored in <code>output</code>
+ *
+ * @exception ShortBufferException if the given output buffer is too small
+ * to hold the result.
+ * @exception ExemptionMechanismException if problem(s) encountered in the
+ * process of generating.
+ */
+ protected abstract int engineGenExemptionBlob
+ (byte[] output, int outputOffset)
+ throws ShortBufferException, ExemptionMechanismException;
+}
diff --git a/javax/crypto/IllegalBlockSizeException.java b/javax/crypto/IllegalBlockSizeException.java
new file mode 100644
index 0000000..01e7215
--- /dev/null
+++ b/javax/crypto/IllegalBlockSizeException.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.crypto;
+
+/**
+ * This exception is thrown when the length of data provided to a block
+ * cipher is incorrect, i.e., does not match the block size of the cipher.
+ *
+ * @author Jan Luehe
+ *
+ * @since 1.4
+ */
+
+public class IllegalBlockSizeException
+ extends java.security.GeneralSecurityException {
+
+ private static final long serialVersionUID = -1965144811953540392L;
+
+ /**
+ * Constructs an IllegalBlockSizeException with no detail message.
+ * A detail message is a String that describes this particular
+ * exception.
+ */
+ public IllegalBlockSizeException() {
+ super();
+ }
+
+ /**
+ * Constructs an IllegalBlockSizeException with the specified
+ * detail message.
+ *
+ * @param msg the detail message.
+ */
+ public IllegalBlockSizeException(String msg) {
+ super(msg);
+ }
+}
diff --git a/javax/crypto/JarVerifier.java b/javax/crypto/JarVerifier.java
new file mode 100644
index 0000000..c56a0d1
--- /dev/null
+++ b/javax/crypto/JarVerifier.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.crypto;
+
+import java.io.*;
+import java.net.*;
+import java.security.*;
+import java.util.jar.*;
+
+/**
+ * This class verifies JAR files (and any supporting JAR files), and
+ * determines whether they may be used in this implementation.
+ *
+ * The JCE in OpenJDK has an open cryptographic interface, meaning it
+ * does not restrict which providers can be used. Compliance with
+ * United States export controls and with local law governing the
+ * import/export of products incorporating the JCE in the OpenJDK is
+ * the responsibility of the licensee.
+ *
+ * @since 1.7
+ */
+final class JarVerifier {
+
+ // The URL for the JAR file we want to verify.
+ private URL jarURL;
+ private boolean savePerms;
+ private CryptoPermissions appPerms = null;
+
+ /**
+ * Creates a JarVerifier object to verify the given URL.
+ *
+ * @param jarURL the JAR file to be verified.
+ * @param savePerms if true, save the permissions allowed by the
+ * exemption mechanism
+ */
+ JarVerifier(URL jarURL, boolean savePerms) {
+ this.jarURL = jarURL;
+ this.savePerms = savePerms;
+ }
+
+ /**
+ * Verify the JAR file is signed by an entity which has a certificate
+ * issued by a trusted CA.
+ *
+ * In OpenJDK, we just need to examine the "cryptoperms" file to see
+ * if any permissions were bundled together with this jar file.
+ */
+ void verify() throws JarException, IOException {
+
+ // Short-circuit. If we weren't asked to save any, we're done.
+ if (!savePerms) {
+ return;
+ }
+
+ // If the protocol of jarURL isn't "jar", we should
+ // construct a JAR URL so we can open a JarURLConnection
+ // for verifying this provider.
+ final URL url = jarURL.getProtocol().equalsIgnoreCase("jar")?
+ jarURL : new URL("jar:" + jarURL.toString() + "!/");
+
+ JarFile jf = null;
+ try {
+
+ // Get a link to the Jarfile to search.
+ try {
+ jf = AccessController.doPrivileged(
+ new PrivilegedExceptionAction<JarFile>() {
+ public JarFile run() throws Exception {
+ JarURLConnection conn =
+ (JarURLConnection) url.openConnection();
+ // You could do some caching here as
+ // an optimization.
+ conn.setUseCaches(false);
+ return conn.getJarFile();
+ }
+ });
+ } catch (java.security.PrivilegedActionException pae) {
+ throw new SecurityException("Cannot load " + url.toString(), pae);
+ }
+
+ if (jf != null) {
+ JarEntry je = jf.getJarEntry("cryptoPerms");
+ if (je == null) {
+ throw new JarException(
+ "Can not find cryptoPerms");
+ }
+ try {
+ appPerms = new CryptoPermissions();
+ appPerms.load(jf.getInputStream(je));
+ } catch (Exception ex) {
+ JarException jex =
+ new JarException("Cannot load/parse" +
+ jarURL.toString());
+ jex.initCause(ex);
+ throw jex;
+ }
+ }
+ } finally {
+ // Only call close() when caching is not enabled.
+ // Otherwise, exceptions will be thrown for all
+ // subsequent accesses of this cached jar.
+ if (jf != null) {
+ jf.close();
+ }
+ }
+ }
+
+ /**
+ * Verify that the provided certs include the
+ * framework signing certificate.
+ *
+ * @param certs the list of certs to be checked.
+ * @throws Exception if the list of certs did not contain
+ * the framework signing certificate
+ */
+ static void verifyPolicySigned(java.security.cert.Certificate[] certs)
+ throws Exception {
+ }
+
+ /**
+ * Returns the permissions which are bundled with the JAR file,
+ * aka the "cryptoperms" file.
+ *
+ * NOTE: if this JarVerifier instance is constructed with "savePerms"
+ * equal to false, then this method would always return null.
+ */
+ CryptoPermissions getPermissions() {
+ return appPerms;
+ }
+}
diff --git a/javax/crypto/JceSecurity.java b/javax/crypto/JceSecurity.java
new file mode 100644
index 0000000..b0ae07e
--- /dev/null
+++ b/javax/crypto/JceSecurity.java
@@ -0,0 +1,354 @@
+/*
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.crypto;
+
+import java.util.*;
+import java.util.jar.*;
+import java.io.*;
+import java.net.URL;
+import java.security.*;
+
+import java.security.Provider.Service;
+
+import sun.security.jca.*;
+import sun.security.jca.GetInstance.Instance;
+
+/**
+ * This class instantiates implementations of JCE engine classes from
+ * providers registered with the java.security.Security object.
+ *
+ * @author Jan Luehe
+ * @author Sharon Liu
+ * @since 1.4
+ */
+
+final class JceSecurity {
+
+ static final SecureRandom RANDOM = new SecureRandom();
+
+ // The defaultPolicy and exemptPolicy will be set up
+ // in the static initializer.
+ private static CryptoPermissions defaultPolicy = null;
+ private static CryptoPermissions exemptPolicy = null;
+
+ // Map<Provider,?> of the providers we already have verified
+ // value == PROVIDER_VERIFIED is successfully verified
+ // value is failure cause Exception in error case
+ private final static Map<Provider, Object> verificationResults =
+ new IdentityHashMap<>();
+
+ // Map<Provider,?> of the providers currently being verified
+ private final static Map<Provider, Object> verifyingProviders =
+ new IdentityHashMap<>();
+
+ // Android-removed: JCE crypto strength restrictions are never in place on Android.
+ // private static final boolean isRestricted = true;
+
+ // Android-removed: This debugging mechanism is not used in Android.
+ /*
+ private static final Debug debug =
+ Debug.getInstance("jca", "Cipher");
+ */
+
+ /*
+ * Don't let anyone instantiate this.
+ */
+ private JceSecurity() {
+ }
+
+ // BEGIN Android-removed: JCE crypto strength restrictions are never in place on Android.
+ /*
+ static {
+ try {
+ AccessController.doPrivileged(
+ new PrivilegedExceptionAction<Object>() {
+ public Object run() throws Exception {
+ setupJurisdictionPolicies();
+ return null;
+ }
+ });
+
+ isRestricted = defaultPolicy.implies(
+ CryptoAllPermission.INSTANCE) ? false : true;
+ } catch (Exception e) {
+ throw new SecurityException(
+ "Can not initialize cryptographic mechanism", e);
+ }
+ }
+ */
+ // END Android-removed: JCE crypto strength restrictions are never in place on Android.
+
+ static Instance getInstance(String type, Class<?> clazz, String algorithm,
+ String provider) throws NoSuchAlgorithmException,
+ NoSuchProviderException {
+ Service s = GetInstance.getService(type, algorithm, provider);
+ Exception ve = getVerificationResult(s.getProvider());
+ if (ve != null) {
+ String msg = "JCE cannot authenticate the provider " + provider;
+ throw (NoSuchProviderException)
+ new NoSuchProviderException(msg).initCause(ve);
+ }
+ return GetInstance.getInstance(s, clazz);
+ }
+
+ static Instance getInstance(String type, Class<?> clazz, String algorithm,
+ Provider provider) throws NoSuchAlgorithmException {
+ Service s = GetInstance.getService(type, algorithm, provider);
+ Exception ve = JceSecurity.getVerificationResult(provider);
+ if (ve != null) {
+ String msg = "JCE cannot authenticate the provider "
+ + provider.getName();
+ throw new SecurityException(msg, ve);
+ }
+ return GetInstance.getInstance(s, clazz);
+ }
+
+ static Instance getInstance(String type, Class<?> clazz, String algorithm)
+ throws NoSuchAlgorithmException {
+ List<Service> services = GetInstance.getServices(type, algorithm);
+ NoSuchAlgorithmException failure = null;
+ for (Service s : services) {
+ if (canUseProvider(s.getProvider()) == false) {
+ // allow only signed providers
+ continue;
+ }
+ try {
+ Instance instance = GetInstance.getInstance(s, clazz);
+ return instance;
+ } catch (NoSuchAlgorithmException e) {
+ failure = e;
+ }
+ }
+ throw new NoSuchAlgorithmException("Algorithm " + algorithm
+ + " not available", failure);
+ }
+
+ /**
+ * Verify if the JAR at URL codeBase is a signed exempt application
+ * JAR file and returns the permissions bundled with the JAR.
+ *
+ * @throws Exception on error
+ */
+ static CryptoPermissions verifyExemptJar(URL codeBase) throws Exception {
+ JarVerifier jv = new JarVerifier(codeBase, true);
+ jv.verify();
+ return jv.getPermissions();
+ }
+
+ /**
+ * Verify if the JAR at URL codeBase is a signed provider JAR file.
+ *
+ * @throws Exception on error
+ */
+ static void verifyProviderJar(URL codeBase) throws Exception {
+ // Verify the provider JAR file and all
+ // supporting JAR files if there are any.
+ JarVerifier jv = new JarVerifier(codeBase, false);
+ jv.verify();
+ }
+
+ private final static Object PROVIDER_VERIFIED = Boolean.TRUE;
+
+ /*
+ * Verify that the provider JAR files are signed properly, which
+ * means the signer's certificate can be traced back to a
+ * JCE trusted CA.
+ * Return null if ok, failure Exception if verification failed.
+ */
+ static synchronized Exception getVerificationResult(Provider p) {
+ Object o = verificationResults.get(p);
+ if (o == PROVIDER_VERIFIED) {
+ return null;
+ } else if (o != null) {
+ return (Exception)o;
+ }
+ if (verifyingProviders.get(p) != null) {
+ // this method is static synchronized, must be recursion
+ // return failure now but do not save the result
+ return new NoSuchProviderException("Recursion during verification");
+ }
+ try {
+ verifyingProviders.put(p, Boolean.FALSE);
+ URL providerURL = getCodeBase(p.getClass());
+ verifyProviderJar(providerURL);
+ // Verified ok, cache result
+ verificationResults.put(p, PROVIDER_VERIFIED);
+ return null;
+ } catch (Exception e) {
+ verificationResults.put(p, e);
+ return e;
+ } finally {
+ verifyingProviders.remove(p);
+ }
+ }
+
+ // return whether this provider is properly signed and can be used by JCE
+ static boolean canUseProvider(Provider p) {
+ // BEGIN Android-changed: All providers are available.
+ // return getVerificationResult(p) == null;
+ return true;
+ // END Android-changed: All providers are available.
+ }
+
+ // dummy object to represent null
+ private static final URL NULL_URL;
+
+ static {
+ try {
+ NULL_URL = new URL("http://null.sun.com/");
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ // reference to a Map we use as a cache for codebases
+ private static final Map<Class<?>, URL> codeBaseCacheRef =
+ new WeakHashMap<>();
+
+ /*
+ * Returns the CodeBase for the given class.
+ */
+ static URL getCodeBase(final Class<?> clazz) {
+ synchronized (codeBaseCacheRef) {
+ URL url = codeBaseCacheRef.get(clazz);
+ if (url == null) {
+ url = AccessController.doPrivileged(new PrivilegedAction<URL>() {
+ public URL run() {
+ ProtectionDomain pd = clazz.getProtectionDomain();
+ if (pd != null) {
+ CodeSource cs = pd.getCodeSource();
+ if (cs != null) {
+ return cs.getLocation();
+ }
+ }
+ return NULL_URL;
+ }
+ });
+ codeBaseCacheRef.put(clazz, url);
+ }
+ return (url == NULL_URL) ? null : url;
+ }
+ }
+
+ // BEGIN Android-removed: JCE crypto strength restrictions are never in place on Android.
+ /*
+ private static void setupJurisdictionPolicies() throws Exception {
+ String javaHomeDir = System.getProperty("java.home");
+ String sep = File.separator;
+ String pathToPolicyJar = javaHomeDir + sep + "lib" + sep +
+ "security" + sep;
+
+ File exportJar = new File(pathToPolicyJar, "US_export_policy.jar");
+ File importJar = new File(pathToPolicyJar, "local_policy.jar");
+ URL jceCipherURL = ClassLoader.getSystemResource
+ ("javax/crypto/Cipher.class");
+
+ if ((jceCipherURL == null) ||
+ !exportJar.exists() || !importJar.exists()) {
+ throw new SecurityException
+ ("Cannot locate policy or framework files!");
+ }
+
+ // Read jurisdiction policies.
+ CryptoPermissions defaultExport = new CryptoPermissions();
+ CryptoPermissions exemptExport = new CryptoPermissions();
+ loadPolicies(exportJar, defaultExport, exemptExport);
+
+ CryptoPermissions defaultImport = new CryptoPermissions();
+ CryptoPermissions exemptImport = new CryptoPermissions();
+ loadPolicies(importJar, defaultImport, exemptImport);
+
+ // Merge the export and import policies for default applications.
+ if (defaultExport.isEmpty() || defaultImport.isEmpty()) {
+ throw new SecurityException("Missing mandatory jurisdiction " +
+ "policy files");
+ }
+ defaultPolicy = defaultExport.getMinimum(defaultImport);
+
+ // Merge the export and import policies for exempt applications.
+ if (exemptExport.isEmpty()) {
+ exemptPolicy = exemptImport.isEmpty() ? null : exemptImport;
+ } else {
+ exemptPolicy = exemptExport.getMinimum(exemptImport);
+ }
+ }
+ */
+ // END Android-removed: JCE crypto strength restrictions are never in place on Android.
+
+ /**
+ * Load the policies from the specified file. Also checks that the
+ * policies are correctly signed.
+ */
+ private static void loadPolicies(File jarPathName,
+ CryptoPermissions defaultPolicy,
+ CryptoPermissions exemptPolicy)
+ throws Exception {
+
+ JarFile jf = new JarFile(jarPathName);
+
+ Enumeration<JarEntry> entries = jf.entries();
+ while (entries.hasMoreElements()) {
+ JarEntry je = entries.nextElement();
+ InputStream is = null;
+ try {
+ if (je.getName().startsWith("default_")) {
+ is = jf.getInputStream(je);
+ defaultPolicy.load(is);
+ } else if (je.getName().startsWith("exempt_")) {
+ is = jf.getInputStream(je);
+ exemptPolicy.load(is);
+ } else {
+ continue;
+ }
+ } finally {
+ if (is != null) {
+ is.close();
+ }
+ }
+
+ // Enforce the signer restraint, i.e. signer of JCE framework
+ // jar should also be the signer of the two jurisdiction policy
+ // jar files.
+ JarVerifier.verifyPolicySigned(je.getCertificates());
+ }
+ // Close and nullify the JarFile reference to help GC.
+ jf.close();
+ jf = null;
+ }
+
+ static CryptoPermissions getDefaultPolicy() {
+ return defaultPolicy;
+ }
+
+ static CryptoPermissions getExemptPolicy() {
+ return exemptPolicy;
+ }
+
+ // Android-removed: JCE crypto strength restrictions are never in place on Android.
+ // static boolean isRestricted() {
+ // return isRestricted;
+ // }
+}
diff --git a/javax/crypto/JceSecurityManager.java b/javax/crypto/JceSecurityManager.java
new file mode 100644
index 0000000..aafaa58
--- /dev/null
+++ b/javax/crypto/JceSecurityManager.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.crypto;
+
+// Android-changed: Stubbed the implementation. Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
+/**
+ * Legacy security code; do not use.
+ */
+
+final class JceSecurityManager extends SecurityManager {
+
+ // singleton instance
+ static final JceSecurityManager INSTANCE = null;
+
+ private JceSecurityManager() {
+ // empty
+ }
+
+ CryptoPermission getCryptoPermission(String alg) { return null; }
+}
diff --git a/javax/crypto/KeyAgreement.java b/javax/crypto/KeyAgreement.java
new file mode 100644
index 0000000..fd79680
--- /dev/null
+++ b/javax/crypto/KeyAgreement.java
@@ -0,0 +1,687 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.crypto;
+
+import java.util.*;
+
+import java.security.*;
+import java.security.Provider.Service;
+import java.security.spec.*;
+
+import sun.security.jca.*;
+import sun.security.jca.GetInstance.Instance;
+
+/**
+ * This class provides the functionality of a key agreement (or key
+ * exchange) protocol.
+ * <p>
+ * The keys involved in establishing a shared secret are created by one of the
+ * key generators (<code>KeyPairGenerator</code> or
+ * <code>KeyGenerator</code>), a <code>KeyFactory</code>, or as a result from
+ * an intermediate phase of the key agreement protocol.
+ *
+ * <p> For each of the correspondents in the key exchange, <code>doPhase</code>
+ * needs to be called. For example, if this key exchange is with one other
+ * party, <code>doPhase</code> needs to be called once, with the
+ * <code>lastPhase</code> flag set to <code>true</code>.
+ * If this key exchange is
+ * with two other parties, <code>doPhase</code> needs to be called twice,
+ * the first time setting the <code>lastPhase</code> flag to
+ * <code>false</code>, and the second time setting it to <code>true</code>.
+ * There may be any number of parties involved in a key exchange.
+ *
+ * <p> Android provides the following <code>KeyAgreement</code> algorithms:
+ * <table>
+ * <thead>
+ * <tr>
+ * <th>Algorithm</th>
+ * <th>Supported API Levels</th>
+ * </tr>
+ * </thead>
+ * <tbody>
+ * <tr>
+ * <td>DH</td>
+ * <td>1+</td>
+ * </tr>
+ * <tr>
+ * <td>ECDH</td>
+ * <td>11+</td>
+ * </tr>
+ * </tbody>
+ * </table>
+ *
+ * This algorithm is described in the <a href=
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyAgreement">
+ * KeyAgreement section</a> of the
+ * Java Cryptography Architecture Standard Algorithm Name Documentation.
+ *
+ * @author Jan Luehe
+ *
+ * @see KeyGenerator
+ * @see SecretKey
+ * @since 1.4
+ */
+
+public class KeyAgreement {
+
+ // Android-removed: this debugging mechanism is not used in Android.
+ /*
+ private static final Debug debug =
+ Debug.getInstance("jca", "KeyAgreement");
+
+ private static final Debug pdebug =
+ Debug.getInstance("provider", "Provider");
+ private static final boolean skipDebug =
+ Debug.isOn("engine=") && !Debug.isOn("keyagreement");
+ */
+
+ // The provider
+ private Provider provider;
+
+ // The provider implementation (delegate)
+ private KeyAgreementSpi spi;
+
+ // The name of the key agreement algorithm.
+ private final String algorithm;
+
+ // BEGIN Android-removed: Redo the provider selection logic to allow reselecting provider.
+ // When only the algorithm is specified, we want to allow the KeyAgreement provider for that
+ // algorithm to change if multiple providers exist and they support different subsets of
+ // keys. To that end, we don't hold an iterator and exhaust it when we need to choose
+ // a provider like the upstream implementation, we reestablish the list of providers
+ // each time.
+ /*
+ // next service to try in provider selection
+ // null once provider is selected
+ private Service firstService;
+
+ // remaining services to try in provider selection
+ // null once provider is selected
+ private Iterator<Service> serviceIterator;
+ */
+ // END Android-removed: Redo the provider selection logic to allow reselecting provider.
+
+ private final Object lock;
+
+ /**
+ * Creates a KeyAgreement object.
+ *
+ * @param keyAgreeSpi the delegate
+ * @param provider the provider
+ * @param algorithm the algorithm
+ */
+ protected KeyAgreement(KeyAgreementSpi keyAgreeSpi, Provider provider,
+ String algorithm) {
+ this.spi = keyAgreeSpi;
+ this.provider = provider;
+ this.algorithm = algorithm;
+ lock = null;
+ }
+
+ // Android-changed: Remove Service and Iterator from constructor args.
+ private KeyAgreement(String algorithm) {
+ this.algorithm = algorithm;
+ lock = new Object();
+ }
+
+ /**
+ * Returns the algorithm name of this <code>KeyAgreement</code> object.
+ *
+ * <p>This is the same name that was specified in one of the
+ * <code>getInstance</code> calls that created this
+ * <code>KeyAgreement</code> object.
+ *
+ * @return the algorithm name of this <code>KeyAgreement</code> object.
+ */
+ public final String getAlgorithm() {
+ return this.algorithm;
+ }
+
+ /**
+ * Returns a <code>KeyAgreement</code> object that implements the
+ * specified key agreement algorithm.
+ *
+ * <p> This method traverses the list of registered security Providers,
+ * starting with the most preferred Provider.
+ * A new KeyAgreement object encapsulating the
+ * KeyAgreementSpi implementation from the first
+ * Provider that supports the specified algorithm is returned.
+ *
+ * <p> Note that the list of registered providers may be retrieved via
+ * the {@link Security#getProviders() Security.getProviders()} method.
+ *
+ * @param algorithm the standard name of the requested key agreement
+ * algorithm.
+ * See the KeyAgreement section in the <a href=
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyAgreement">
+ * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+ * for information about standard algorithm names.
+ *
+ * @return the new <code>KeyAgreement</code> object.
+ *
+ * @exception NullPointerException if the specified algorithm
+ * is null.
+ *
+ * @exception NoSuchAlgorithmException if no Provider supports a
+ * KeyAgreementSpi implementation for the
+ * specified algorithm.
+ *
+ * @see java.security.Provider
+ */
+ public static final KeyAgreement getInstance(String algorithm)
+ throws NoSuchAlgorithmException {
+ List<Service> services =
+ GetInstance.getServices("KeyAgreement", algorithm);
+ // make sure there is at least one service from a signed provider
+ Iterator<Service> t = services.iterator();
+ while (t.hasNext()) {
+ Service s = t.next();
+ if (JceSecurity.canUseProvider(s.getProvider()) == false) {
+ continue;
+ }
+ // Android-changed: Remove Service and Iterator from constructor args.
+ // return new KeyAgreement(s, t, algorithm);
+ return new KeyAgreement(algorithm);
+ }
+ throw new NoSuchAlgorithmException
+ ("Algorithm " + algorithm + " not available");
+ }
+
+ /**
+ * Returns a <code>KeyAgreement</code> object that implements the
+ * specified key agreement algorithm.
+ *
+ * <p> A new KeyAgreement object encapsulating the
+ * KeyAgreementSpi implementation from the specified provider
+ * is returned. The specified provider must be registered
+ * in the security provider list.
+ *
+ * <p> Note that the list of registered providers may be retrieved via
+ * the {@link Security#getProviders() Security.getProviders()} method.
+ *
+ * @param algorithm the standard name of the requested key agreement
+ * algorithm.
+ * See the KeyAgreement section in the <a href=
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyAgreement">
+ * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+ * for information about standard algorithm names.
+ *
+ * @param provider the name of the provider.
+ *
+ * @return the new <code>KeyAgreement</code> object.
+ *
+ * @exception NullPointerException if the specified algorithm
+ * is null.
+ *
+ * @exception NoSuchAlgorithmException if a KeyAgreementSpi
+ * implementation for the specified algorithm is not
+ * available from the specified provider.
+ *
+ * @exception NoSuchProviderException if the specified provider is not
+ * registered in the security provider list.
+ *
+ * @exception IllegalArgumentException if the <code>provider</code>
+ * is null or empty.
+ *
+ * @see java.security.Provider
+ */
+ public static final KeyAgreement getInstance(String algorithm,
+ String provider) throws NoSuchAlgorithmException,
+ NoSuchProviderException {
+ // Android-added: Check for Bouncy Castle deprecation
+ Providers.checkBouncyCastleDeprecation(provider, "KeyAgreement", algorithm);
+ Instance instance = JceSecurity.getInstance
+ ("KeyAgreement", KeyAgreementSpi.class, algorithm, provider);
+ return new KeyAgreement((KeyAgreementSpi)instance.impl,
+ instance.provider, algorithm);
+ }
+
+ /**
+ * Returns a <code>KeyAgreement</code> object that implements the
+ * specified key agreement algorithm.
+ *
+ * <p> A new KeyAgreement object encapsulating the
+ * KeyAgreementSpi implementation from the specified Provider
+ * object is returned. Note that the specified Provider object
+ * does not have to be registered in the provider list.
+ *
+ * @param algorithm the standard name of the requested key agreement
+ * algorithm.
+ * See the KeyAgreement section in the <a href=
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyAgreement">
+ * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+ * for information about standard algorithm names.
+ *
+ * @param provider the provider.
+ *
+ * @return the new <code>KeyAgreement</code> object.
+ *
+ * @exception NullPointerException if the specified algorithm
+ * is null.
+ *
+ * @exception NoSuchAlgorithmException if a KeyAgreementSpi
+ * implementation for the specified algorithm is not available
+ * from the specified Provider object.
+ *
+ * @exception IllegalArgumentException if the <code>provider</code>
+ * is null.
+ *
+ * @see java.security.Provider
+ */
+ public static final KeyAgreement getInstance(String algorithm,
+ Provider provider) throws NoSuchAlgorithmException {
+ // Android-added: Check for Bouncy Castle deprecation
+ Providers.checkBouncyCastleDeprecation(provider, "KeyAgreement", algorithm);
+ Instance instance = JceSecurity.getInstance
+ ("KeyAgreement", KeyAgreementSpi.class, algorithm, provider);
+ return new KeyAgreement((KeyAgreementSpi)instance.impl,
+ instance.provider, algorithm);
+ }
+
+ // max number of debug warnings to print from chooseFirstProvider()
+ private static int warnCount = 10;
+
+ /**
+ * Choose the Spi from the first provider available. Used if
+ * delayed provider selection is not possible because init()
+ * is not the first method called.
+ */
+ void chooseFirstProvider() {
+ if (spi != null) {
+ return;
+ }
+ synchronized (lock) {
+ if (spi != null) {
+ return;
+ }
+ // Android-removed: this debugging mechanism is not used in Android.
+ /*
+ if (debug != null) {
+ int w = --warnCount;
+ if (w >= 0) {
+ debug.println("KeyAgreement.init() not first method "
+ + "called, disabling delayed provider selection");
+ if (w == 0) {
+ debug.println("Further warnings of this type will "
+ + "be suppressed");
+ }
+ new Exception("Call trace").printStackTrace();
+ }
+ }
+ */
+ Exception lastException = null;
+ // Android-changed: Provider selection; loop over a new list each time.
+ for (Service s : GetInstance.getServices("KeyAgreement", algorithm)) {
+ if (JceSecurity.canUseProvider(s.getProvider()) == false) {
+ continue;
+ }
+ try {
+ Object obj = s.newInstance(null);
+ if (obj instanceof KeyAgreementSpi == false) {
+ continue;
+ }
+ spi = (KeyAgreementSpi)obj;
+ provider = s.getProvider();
+ // Android-removed: Provider selection; loop over a new list each time.
+ /*
+ // not needed any more
+ firstService = null;
+ serviceIterator = null;
+ */
+ return;
+ } catch (Exception e) {
+ lastException = e;
+ }
+ }
+ ProviderException e = new ProviderException
+ ("Could not construct KeyAgreementSpi instance");
+ if (lastException != null) {
+ e.initCause(lastException);
+ }
+ throw e;
+ }
+ }
+
+ private final static int I_NO_PARAMS = 1;
+ private final static int I_PARAMS = 2;
+
+ private void implInit(KeyAgreementSpi spi, int type, Key key,
+ AlgorithmParameterSpec params, SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException {
+ if (type == I_NO_PARAMS) {
+ spi.engineInit(key, random);
+ } else { // I_PARAMS
+ spi.engineInit(key, params, random);
+ }
+ }
+
+ private void chooseProvider(int initType, Key key,
+ AlgorithmParameterSpec params, SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException {
+ synchronized (lock) {
+ // Android-changed: Use the currently-selected provider only if no key was provided.
+ // if (spi != null) {
+ if (spi != null && key == null) {
+ implInit(spi, initType, key, params, random);
+ return;
+ }
+ Exception lastException = null;
+ // Android-changed: Provider selection; loop over a new list each time.
+ for (Service s : GetInstance.getServices("KeyAgreement", algorithm)) {
+ // if provider says it does not support this key, ignore it
+ if (s.supportsParameter(key) == false) {
+ continue;
+ }
+ if (JceSecurity.canUseProvider(s.getProvider()) == false) {
+ continue;
+ }
+ try {
+ KeyAgreementSpi spi = (KeyAgreementSpi)s.newInstance(null);
+ implInit(spi, initType, key, params, random);
+ provider = s.getProvider();
+ this.spi = spi;
+ // Android-removed: Provider selection; loop over a new list each time.
+ /*
+ firstService = null;
+ serviceIterator = null;
+ */
+ return;
+ } catch (Exception e) {
+ // NoSuchAlgorithmException from newInstance()
+ // InvalidKeyException from init()
+ // RuntimeException (ProviderException) from init()
+ if (lastException == null) {
+ lastException = e;
+ }
+ }
+ }
+ // no working provider found, fail
+ if (lastException instanceof InvalidKeyException) {
+ throw (InvalidKeyException)lastException;
+ }
+ if (lastException instanceof InvalidAlgorithmParameterException) {
+ throw (InvalidAlgorithmParameterException)lastException;
+ }
+ if (lastException instanceof RuntimeException) {
+ throw (RuntimeException)lastException;
+ }
+ String kName = (key != null) ? key.getClass().getName() : "(null)";
+ throw new InvalidKeyException
+ ("No installed provider supports this key: "
+ + kName, lastException);
+ }
+ }
+
+ /**
+ * Returns the provider of this <code>KeyAgreement</code> object.
+ *
+ * @return the provider of this <code>KeyAgreement</code> object
+ */
+ public final Provider getProvider() {
+ chooseFirstProvider();
+ return this.provider;
+ }
+
+ /**
+ * Initializes this key agreement with the given key, which is required to
+ * contain all the algorithm parameters required for this key agreement.
+ *
+ * <p> If this key agreement requires any random bytes, it will get
+ * them using the
+ * {@link java.security.SecureRandom}
+ * implementation of the highest-priority
+ * installed provider as the source of randomness.
+ * (If none of the installed providers supply an implementation of
+ * SecureRandom, a system-provided source of randomness will be used.)
+ *
+ * @param key the party's private information. For example, in the case
+ * of the Diffie-Hellman key agreement, this would be the party's own
+ * Diffie-Hellman private key.
+ *
+ * @exception InvalidKeyException if the given key is
+ * inappropriate for this key agreement, e.g., is of the wrong type or
+ * has an incompatible algorithm type.
+ */
+ public final void init(Key key) throws InvalidKeyException {
+ init(key, JceSecurity.RANDOM);
+ }
+
+ /**
+ * Initializes this key agreement with the given key and source of
+ * randomness. The given key is required to contain all the algorithm
+ * parameters required for this key agreement.
+ *
+ * <p> If the key agreement algorithm requires random bytes, it gets them
+ * from the given source of randomness, <code>random</code>.
+ * However, if the underlying
+ * algorithm implementation does not require any random bytes,
+ * <code>random</code> is ignored.
+ *
+ * @param key the party's private information. For example, in the case
+ * of the Diffie-Hellman key agreement, this would be the party's own
+ * Diffie-Hellman private key.
+ * @param random the source of randomness
+ *
+ * @exception InvalidKeyException if the given key is
+ * inappropriate for this key agreement, e.g., is of the wrong type or
+ * has an incompatible algorithm type.
+ */
+ public final void init(Key key, SecureRandom random)
+ throws InvalidKeyException {
+ // Android-changed: Use the currently-selected provider only if no key was provided.
+ // if (spi != null) {
+ if (spi != null && (key == null || lock == null)) {
+ spi.engineInit(key, random);
+ } else {
+ try {
+ chooseProvider(I_NO_PARAMS, key, null, random);
+ } catch (InvalidAlgorithmParameterException e) {
+ // should never occur
+ throw new InvalidKeyException(e);
+ }
+ }
+
+ // Android-removed: this debugging mechanism is not used in Android.
+ /*
+ if (!skipDebug && pdebug != null) {
+ pdebug.println("KeyAgreement." + algorithm + " algorithm from: " +
+ this.provider.getName());
+ }
+ */
+ }
+
+ /**
+ * Initializes this key agreement with the given key and set of
+ * algorithm parameters.
+ *
+ * <p> If this key agreement requires any random bytes, it will get
+ * them using the
+ * {@link java.security.SecureRandom}
+ * implementation of the highest-priority
+ * installed provider as the source of randomness.
+ * (If none of the installed providers supply an implementation of
+ * SecureRandom, a system-provided source of randomness will be used.)
+ *
+ * @param key the party's private information. For example, in the case
+ * of the Diffie-Hellman key agreement, this would be the party's own
+ * Diffie-Hellman private key.
+ * @param params the key agreement parameters
+ *
+ * @exception InvalidKeyException if the given key is
+ * inappropriate for this key agreement, e.g., is of the wrong type or
+ * has an incompatible algorithm type.
+ * @exception InvalidAlgorithmParameterException if the given parameters
+ * are inappropriate for this key agreement.
+ */
+ public final void init(Key key, AlgorithmParameterSpec params)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ init(key, params, JceSecurity.RANDOM);
+ }
+
+ /**
+ * Initializes this key agreement with the given key, set of
+ * algorithm parameters, and source of randomness.
+ *
+ * @param key the party's private information. For example, in the case
+ * of the Diffie-Hellman key agreement, this would be the party's own
+ * Diffie-Hellman private key.
+ * @param params the key agreement parameters
+ * @param random the source of randomness
+ *
+ * @exception InvalidKeyException if the given key is
+ * inappropriate for this key agreement, e.g., is of the wrong type or
+ * has an incompatible algorithm type.
+ * @exception InvalidAlgorithmParameterException if the given parameters
+ * are inappropriate for this key agreement.
+ */
+ public final void init(Key key, AlgorithmParameterSpec params,
+ SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ if (spi != null) {
+ spi.engineInit(key, params, random);
+ } else {
+ chooseProvider(I_PARAMS, key, params, random);
+ }
+
+ // Android-removed: this debugging mechanism is not used in Android.
+ /*
+ if (!skipDebug && pdebug != null) {
+ pdebug.println("KeyAgreement." + algorithm + " algorithm from: " +
+ this.provider.getName());
+ }
+ */
+ }
+
+ /**
+ * Executes the next phase of this key agreement with the given
+ * key that was received from one of the other parties involved in this key
+ * agreement.
+ *
+ * @param key the key for this phase. For example, in the case of
+ * Diffie-Hellman between 2 parties, this would be the other party's
+ * Diffie-Hellman public key.
+ * @param lastPhase flag which indicates whether or not this is the last
+ * phase of this key agreement.
+ *
+ * @return the (intermediate) key resulting from this phase, or null
+ * if this phase does not yield a key
+ *
+ * @exception InvalidKeyException if the given key is inappropriate for
+ * this phase.
+ * @exception IllegalStateException if this key agreement has not been
+ * initialized.
+ */
+ public final Key doPhase(Key key, boolean lastPhase)
+ throws InvalidKeyException, IllegalStateException
+ {
+ chooseFirstProvider();
+ return spi.engineDoPhase(key, lastPhase);
+ }
+
+ /**
+ * Generates the shared secret and returns it in a new buffer.
+ *
+ * <p>This method resets this <code>KeyAgreement</code> object, so that it
+ * can be reused for further key agreements. Unless this key agreement is
+ * reinitialized with one of the <code>init</code> methods, the same
+ * private information and algorithm parameters will be used for
+ * subsequent key agreements.
+ *
+ * @return the new buffer with the shared secret
+ *
+ * @exception IllegalStateException if this key agreement has not been
+ * completed yet
+ */
+ public final byte[] generateSecret() throws IllegalStateException {
+ chooseFirstProvider();
+ return spi.engineGenerateSecret();
+ }
+
+ /**
+ * Generates the shared secret, and places it into the buffer
+ * <code>sharedSecret</code>, beginning at <code>offset</code> inclusive.
+ *
+ * <p>If the <code>sharedSecret</code> buffer is too small to hold the
+ * result, a <code>ShortBufferException</code> is thrown.
+ * In this case, this call should be repeated with a larger output buffer.
+ *
+ * <p>This method resets this <code>KeyAgreement</code> object, so that it
+ * can be reused for further key agreements. Unless this key agreement is
+ * reinitialized with one of the <code>init</code> methods, the same
+ * private information and algorithm parameters will be used for
+ * subsequent key agreements.
+ *
+ * @param sharedSecret the buffer for the shared secret
+ * @param offset the offset in <code>sharedSecret</code> where the
+ * shared secret will be stored
+ *
+ * @return the number of bytes placed into <code>sharedSecret</code>
+ *
+ * @exception IllegalStateException if this key agreement has not been
+ * completed yet
+ * @exception ShortBufferException if the given output buffer is too small
+ * to hold the secret
+ */
+ public final int generateSecret(byte[] sharedSecret, int offset)
+ throws IllegalStateException, ShortBufferException
+ {
+ chooseFirstProvider();
+ return spi.engineGenerateSecret(sharedSecret, offset);
+ }
+
+ /**
+ * Creates the shared secret and returns it as a <code>SecretKey</code>
+ * object of the specified algorithm.
+ *
+ * <p>This method resets this <code>KeyAgreement</code> object, so that it
+ * can be reused for further key agreements. Unless this key agreement is
+ * reinitialized with one of the <code>init</code> methods, the same
+ * private information and algorithm parameters will be used for
+ * subsequent key agreements.
+ *
+ * @param algorithm the requested secret-key algorithm
+ *
+ * @return the shared secret key
+ *
+ * @exception IllegalStateException if this key agreement has not been
+ * completed yet
+ * @exception NoSuchAlgorithmException if the specified secret-key
+ * algorithm is not available
+ * @exception InvalidKeyException if the shared secret-key material cannot
+ * be used to generate a secret key of the specified algorithm (e.g.,
+ * the key material is too short)
+ */
+ public final SecretKey generateSecret(String algorithm)
+ throws IllegalStateException, NoSuchAlgorithmException,
+ InvalidKeyException
+ {
+ chooseFirstProvider();
+ return spi.engineGenerateSecret(algorithm);
+ }
+}
diff --git a/javax/crypto/KeyAgreementSpi.java b/javax/crypto/KeyAgreementSpi.java
new file mode 100644
index 0000000..51c8307
--- /dev/null
+++ b/javax/crypto/KeyAgreementSpi.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.crypto;
+
+import java.security.*;
+import java.security.spec.*;
+
+/**
+ * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>)
+ * for the <code>KeyAgreement</code> class.
+ * All the abstract methods in this class must be implemented by each
+ * cryptographic service provider who wishes to supply the implementation
+ * of a particular key agreement algorithm.
+ *
+ * <p> The keys involved in establishing a shared secret are created by one
+ * of the
+ * key generators (<code>KeyPairGenerator</code> or
+ * <code>KeyGenerator</code>), a <code>KeyFactory</code>, or as a result from
+ * an intermediate phase of the key agreement protocol
+ * ({@link #engineDoPhase(java.security.Key, boolean) engineDoPhase}).
+ *
+ * <p> For each of the correspondents in the key exchange,
+ * <code>engineDoPhase</code>
+ * needs to be called. For example, if the key exchange is with one other
+ * party, <code>engineDoPhase</code> needs to be called once, with the
+ * <code>lastPhase</code> flag set to <code>true</code>.
+ * If the key exchange is
+ * with two other parties, <code>engineDoPhase</code> needs to be called twice,
+ * the first time setting the <code>lastPhase</code> flag to
+ * <code>false</code>, and the second time setting it to <code>true</code>.
+ * There may be any number of parties involved in a key exchange.
+ *
+ * @author Jan Luehe
+ *
+ * @see KeyGenerator
+ * @see SecretKey
+ * @since 1.4
+ */
+
+public abstract class KeyAgreementSpi {
+
+ /**
+ * Initializes this key agreement with the given key and source of
+ * randomness. The given key is required to contain all the algorithm
+ * parameters required for this key agreement.
+ *
+ * <p> If the key agreement algorithm requires random bytes, it gets them
+ * from the given source of randomness, <code>random</code>.
+ * However, if the underlying
+ * algorithm implementation does not require any random bytes,
+ * <code>random</code> is ignored.
+ *
+ * @param key the party's private information. For example, in the case
+ * of the Diffie-Hellman key agreement, this would be the party's own
+ * Diffie-Hellman private key.
+ * @param random the source of randomness
+ *
+ * @exception InvalidKeyException if the given key is
+ * inappropriate for this key agreement, e.g., is of the wrong type or
+ * has an incompatible algorithm type.
+ */
+ protected abstract void engineInit(Key key, SecureRandom random)
+ throws InvalidKeyException;
+
+ /**
+ * Initializes this key agreement with the given key, set of
+ * algorithm parameters, and source of randomness.
+ *
+ * @param key the party's private information. For example, in the case
+ * of the Diffie-Hellman key agreement, this would be the party's own
+ * Diffie-Hellman private key.
+ * @param params the key agreement parameters
+ * @param random the source of randomness
+ *
+ * @exception InvalidKeyException if the given key is
+ * inappropriate for this key agreement, e.g., is of the wrong type or
+ * has an incompatible algorithm type.
+ * @exception InvalidAlgorithmParameterException if the given parameters
+ * are inappropriate for this key agreement.
+ */
+ protected abstract void engineInit(Key key, AlgorithmParameterSpec params,
+ SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException;
+
+ /**
+ * Executes the next phase of this key agreement with the given
+ * key that was received from one of the other parties involved in this key
+ * agreement.
+ *
+ * @param key the key for this phase. For example, in the case of
+ * Diffie-Hellman between 2 parties, this would be the other party's
+ * Diffie-Hellman public key.
+ * @param lastPhase flag which indicates whether or not this is the last
+ * phase of this key agreement.
+ *
+ * @return the (intermediate) key resulting from this phase, or null if
+ * this phase does not yield a key
+ *
+ * @exception InvalidKeyException if the given key is inappropriate for
+ * this phase.
+ * @exception IllegalStateException if this key agreement has not been
+ * initialized.
+ */
+ protected abstract Key engineDoPhase(Key key, boolean lastPhase)
+ throws InvalidKeyException, IllegalStateException;
+
+ /**
+ * Generates the shared secret and returns it in a new buffer.
+ *
+ * <p>This method resets this <code>KeyAgreementSpi</code> object,
+ * so that it
+ * can be reused for further key agreements. Unless this key agreement is
+ * reinitialized with one of the <code>engineInit</code> methods, the same
+ * private information and algorithm parameters will be used for
+ * subsequent key agreements.
+ *
+ * @return the new buffer with the shared secret
+ *
+ * @exception IllegalStateException if this key agreement has not been
+ * completed yet
+ */
+ protected abstract byte[] engineGenerateSecret()
+ throws IllegalStateException;
+
+ /**
+ * Generates the shared secret, and places it into the buffer
+ * <code>sharedSecret</code>, beginning at <code>offset</code> inclusive.
+ *
+ * <p>If the <code>sharedSecret</code> buffer is too small to hold the
+ * result, a <code>ShortBufferException</code> is thrown.
+ * In this case, this call should be repeated with a larger output buffer.
+ *
+ * <p>This method resets this <code>KeyAgreementSpi</code> object,
+ * so that it
+ * can be reused for further key agreements. Unless this key agreement is
+ * reinitialized with one of the <code>engineInit</code> methods, the same
+ * private information and algorithm parameters will be used for
+ * subsequent key agreements.
+ *
+ * @param sharedSecret the buffer for the shared secret
+ * @param offset the offset in <code>sharedSecret</code> where the
+ * shared secret will be stored
+ *
+ * @return the number of bytes placed into <code>sharedSecret</code>
+ *
+ * @exception IllegalStateException if this key agreement has not been
+ * completed yet
+ * @exception ShortBufferException if the given output buffer is too small
+ * to hold the secret
+ */
+ protected abstract int engineGenerateSecret(byte[] sharedSecret,
+ int offset)
+ throws IllegalStateException, ShortBufferException;
+
+ /**
+ * Creates the shared secret and returns it as a secret key object
+ * of the requested algorithm type.
+ *
+ * <p>This method resets this <code>KeyAgreementSpi</code> object,
+ * so that it
+ * can be reused for further key agreements. Unless this key agreement is
+ * reinitialized with one of the <code>engineInit</code> methods, the same
+ * private information and algorithm parameters will be used for
+ * subsequent key agreements.
+ *
+ * @param algorithm the requested secret key algorithm
+ *
+ * @return the shared secret key
+ *
+ * @exception IllegalStateException if this key agreement has not been
+ * completed yet
+ * @exception NoSuchAlgorithmException if the requested secret key
+ * algorithm is not available
+ * @exception InvalidKeyException if the shared secret key material cannot
+ * be used to generate a secret key of the requested algorithm type (e.g.,
+ * the key material is too short)
+ */
+ protected abstract SecretKey engineGenerateSecret(String algorithm)
+ throws IllegalStateException, NoSuchAlgorithmException,
+ InvalidKeyException;
+}
diff --git a/javax/crypto/KeyGenerator.java b/javax/crypto/KeyGenerator.java
new file mode 100644
index 0000000..5951eef
--- /dev/null
+++ b/javax/crypto/KeyGenerator.java
@@ -0,0 +1,628 @@
+/*
+ * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.crypto;
+
+import java.util.*;
+
+import java.security.*;
+import java.security.Provider.Service;
+import java.security.spec.*;
+
+import sun.security.jca.*;
+import sun.security.jca.GetInstance.Instance;
+
+/**
+ * This class provides the functionality of a secret (symmetric) key generator.
+ *
+ * <p>Key generators are constructed using one of the <code>getInstance</code>
+ * class methods of this class.
+ *
+ * <p>KeyGenerator objects are reusable, i.e., after a key has been
+ * generated, the same KeyGenerator object can be re-used to generate further
+ * keys.
+ *
+ * <p>There are two ways to generate a key: in an algorithm-independent
+ * manner, and in an algorithm-specific manner.
+ * The only difference between the two is the initialization of the object:
+ *
+ * <ul>
+ * <li><b>Algorithm-Independent Initialization</b>
+ * <p>All key generators share the concepts of a <i>keysize</i> and a
+ * <i>source of randomness</i>.
+ * There is an
+ * {@link #init(int, java.security.SecureRandom) init}
+ * method in this KeyGenerator class that takes these two universally
+ * shared types of arguments. There is also one that takes just a
+ * <code>keysize</code> argument, and uses the SecureRandom implementation
+ * of the highest-priority installed provider as the source of randomness
+ * (or a system-provided source of randomness if none of the installed
+ * providers supply a SecureRandom implementation), and one that takes just a
+ * source of randomness.
+ *
+ * <p>Since no other parameters are specified when you call the above
+ * algorithm-independent <code>init</code> methods, it is up to the
+ * provider what to do about the algorithm-specific parameters (if any) to be
+ * associated with each of the keys.
+ *
+ * <li><b>Algorithm-Specific Initialization</b>
+ * <p>For situations where a set of algorithm-specific parameters already
+ * exists, there are two
+ * {@link #init(java.security.spec.AlgorithmParameterSpec) init}
+ * methods that have an <code>AlgorithmParameterSpec</code>
+ * argument. One also has a <code>SecureRandom</code> argument, while the
+ * other uses the SecureRandom implementation
+ * of the highest-priority installed provider as the source of randomness
+ * (or a system-provided source of randomness if none of the installed
+ * providers supply a SecureRandom implementation).
+ * </ul>
+ *
+ * <p>In case the client does not explicitly initialize the KeyGenerator
+ * (via a call to an <code>init</code> method), each provider must
+ * supply (and document) a default initialization.
+ *
+ * <p> Android provides the following <code>KeyGenerator</code> algorithms:
+ * <table>
+ * <thead>
+ * <tr>
+ * <th>Algorithm</th>
+ * <th>Supported API Levels</th>
+ * </tr>
+ * </thead>
+ * <tbody>
+ * <tr>
+ * <td>AES</td>
+ * <td>1+</td>
+ * </tr>
+ * <tr class="deprecated">
+ * <td>AESWRAP</td>
+ * <td>1-8</td>
+ * </tr>
+ * <tr>
+ * <td>ARC4</td>
+ * <td>14+</td>
+ * </tr>
+ * <tr>
+ * <td>BLOWFISH</td>
+ * <td>10+</td>
+ * </tr>
+ * <tr>
+ * <td>ChaCha20</td>
+ * <td>28+</td>
+ * </tr>
+ * <tr>
+ * <td>DES</td>
+ * <td>1+</td>
+ * </tr>
+ * <tr>
+ * <td>DESede</td>
+ * <td>1+</td>
+ * </tr>
+ * <tr class="deprecated">
+ * <td>DESedeWRAP</td>
+ * <td>1-8</td>
+ * </tr>
+ * <tr>
+ * <td>HmacMD5</td>
+ * <td>1+</td>
+ * </tr>
+ * <tr>
+ * <td>HmacSHA1</td>
+ * <td>11+</td>
+ * </tr>
+ * <tr>
+ * <td>HmacSHA224</td>
+ * <td>1-8,22+</td>
+ * </tr>
+ * <tr>
+ * <td>HmacSHA256</td>
+ * <td>1+</td>
+ * </tr>
+ * <tr>
+ * <td>HmacSHA384</td>
+ * <td>1+</td>
+ * </tr>
+ * <tr>
+ * <td>HmacSHA512</td>
+ * <td>1+</td>
+ * </tr>
+ * <tr class="deprecated">
+ * <td>RC4</td>
+ * <td>10-13</td>
+ * </tr>
+ * </tbody>
+ * </table>
+ *
+ * These algorithms are described in the <a href=
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyGenerator">
+ * KeyGenerator section</a> of the
+ * Java Cryptography Architecture Standard Algorithm Name Documentation.
+ *
+ * @author Jan Luehe
+ *
+ * @see SecretKey
+ * @since 1.4
+ */
+
+public class KeyGenerator {
+
+ // Android-removed: this debugging mechanism is not used in Android.
+ /*
+ private static final Debug pdebug =
+ Debug.getInstance("provider", "Provider");
+ private static final boolean skipDebug =
+ Debug.isOn("engine=") && !Debug.isOn("keygenerator");
+ */
+
+ // see java.security.KeyPairGenerator for failover notes
+
+ private final static int I_NONE = 1;
+ private final static int I_RANDOM = 2;
+ private final static int I_PARAMS = 3;
+ private final static int I_SIZE = 4;
+
+ // The provider
+ private Provider provider;
+
+ // The provider implementation (delegate)
+ private volatile KeyGeneratorSpi spi;
+
+ // The algorithm
+ private final String algorithm;
+
+ private final Object lock = new Object();
+
+ private Iterator<Service> serviceIterator;
+
+ private int initType;
+ private int initKeySize;
+ private AlgorithmParameterSpec initParams;
+ private SecureRandom initRandom;
+
+ /**
+ * Creates a KeyGenerator object.
+ *
+ * @param keyGenSpi the delegate
+ * @param provider the provider
+ * @param algorithm the algorithm
+ */
+ protected KeyGenerator(KeyGeneratorSpi keyGenSpi, Provider provider,
+ String algorithm) {
+ this.spi = keyGenSpi;
+ this.provider = provider;
+ this.algorithm = algorithm;
+
+ // Android-removed: this debugging mechanism is not used in Android.
+ /*
+ if (!skipDebug && pdebug != null) {
+ pdebug.println("KeyGenerator." + algorithm + " algorithm from: " +
+ this.provider.getName());
+ }
+ */
+ }
+
+ private KeyGenerator(String algorithm) throws NoSuchAlgorithmException {
+ this.algorithm = algorithm;
+ List<Service> list =
+ GetInstance.getServices("KeyGenerator", algorithm);
+ serviceIterator = list.iterator();
+ initType = I_NONE;
+ // fetch and instantiate initial spi
+ if (nextSpi(null, false) == null) {
+ throw new NoSuchAlgorithmException
+ (algorithm + " KeyGenerator not available");
+ }
+
+ // Android-removed: this debugging mechanism is not used in Android.
+ /*
+ if (!skipDebug && pdebug != null) {
+ pdebug.println("KeyGenerator." + algorithm + " algorithm from: " +
+ this.provider.getName());
+ }
+ */
+ }
+
+ /**
+ * Returns the algorithm name of this <code>KeyGenerator</code> object.
+ *
+ * <p>This is the same name that was specified in one of the
+ * <code>getInstance</code> calls that created this
+ * <code>KeyGenerator</code> object.
+ *
+ * @return the algorithm name of this <code>KeyGenerator</code> object.
+ */
+ public final String getAlgorithm() {
+ return this.algorithm;
+ }
+
+ /**
+ * Returns a <code>KeyGenerator</code> object that generates secret keys
+ * for the specified algorithm.
+ *
+ * <p> This method traverses the list of registered security Providers,
+ * starting with the most preferred Provider.
+ * A new KeyGenerator object encapsulating the
+ * KeyGeneratorSpi implementation from the first
+ * Provider that supports the specified algorithm is returned.
+ *
+ * <p> Note that the list of registered providers may be retrieved via
+ * the {@link Security#getProviders() Security.getProviders()} method.
+ *
+ * @param algorithm the standard name of the requested key algorithm.
+ * See the KeyGenerator section in the <a href=
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyGenerator">
+ * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+ * for information about standard algorithm names.
+ *
+ * @return the new <code>KeyGenerator</code> object.
+ *
+ * @exception NullPointerException if the specified algorithm is null.
+ *
+ * @exception NoSuchAlgorithmException if no Provider supports a
+ * KeyGeneratorSpi implementation for the
+ * specified algorithm.
+ *
+ * @see java.security.Provider
+ */
+ public static final KeyGenerator getInstance(String algorithm)
+ throws NoSuchAlgorithmException {
+ return new KeyGenerator(algorithm);
+ }
+
+ /**
+ * Returns a <code>KeyGenerator</code> object that generates secret keys
+ * for the specified algorithm.
+ *
+ * <p> A new KeyGenerator object encapsulating the
+ * KeyGeneratorSpi implementation from the specified provider
+ * is returned. The specified provider must be registered
+ * in the security provider list.
+ *
+ * <p> Note that the list of registered providers may be retrieved via
+ * the {@link Security#getProviders() Security.getProviders()} method.
+ *
+ * @param algorithm the standard name of the requested key algorithm.
+ * See the KeyGenerator section in the <a href=
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyGenerator">
+ * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+ * for information about standard algorithm names.
+ *
+ * @param provider the name of the provider.
+ *
+ * @return the new <code>KeyGenerator</code> object.
+ *
+ * @exception NullPointerException if the specified algorithm is null.
+ *
+ * @exception NoSuchAlgorithmException if a KeyGeneratorSpi
+ * implementation for the specified algorithm is not
+ * available from the specified provider.
+ *
+ * @exception NoSuchProviderException if the specified provider is not
+ * registered in the security provider list.
+ *
+ * @exception IllegalArgumentException if the <code>provider</code>
+ * is null or empty.
+ *
+ * @see java.security.Provider
+ */
+ public static final KeyGenerator getInstance(String algorithm,
+ String provider) throws NoSuchAlgorithmException,
+ NoSuchProviderException {
+ // Android-added: Check for Bouncy Castle deprecation
+ Providers.checkBouncyCastleDeprecation(provider, "KeyGenerator", algorithm);
+ Instance instance = JceSecurity.getInstance("KeyGenerator",
+ KeyGeneratorSpi.class, algorithm, provider);
+ return new KeyGenerator((KeyGeneratorSpi)instance.impl,
+ instance.provider, algorithm);
+ }
+
+ /**
+ * Returns a <code>KeyGenerator</code> object that generates secret keys
+ * for the specified algorithm.
+ *
+ * <p> A new KeyGenerator object encapsulating the
+ * KeyGeneratorSpi implementation from the specified Provider
+ * object is returned. Note that the specified Provider object
+ * does not have to be registered in the provider list.
+ *
+ * @param algorithm the standard name of the requested key algorithm.
+ * See the KeyGenerator section in the <a href=
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyGenerator">
+ * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+ * for information about standard algorithm names.
+ *
+ * @param provider the provider.
+ *
+ * @return the new <code>KeyGenerator</code> object.
+ *
+ * @exception NullPointerException if the specified algorithm is null.
+ *
+ * @exception NoSuchAlgorithmException if a KeyGeneratorSpi
+ * implementation for the specified algorithm is not available
+ * from the specified Provider object.
+ *
+ * @exception IllegalArgumentException if the <code>provider</code>
+ * is null.
+ *
+ * @see java.security.Provider
+ */
+ public static final KeyGenerator getInstance(String algorithm,
+ Provider provider) throws NoSuchAlgorithmException {
+ // Android-added: Check for Bouncy Castle deprecation
+ Providers.checkBouncyCastleDeprecation(provider, "KeyGenerator", algorithm);
+ Instance instance = JceSecurity.getInstance("KeyGenerator",
+ KeyGeneratorSpi.class, algorithm, provider);
+ return new KeyGenerator((KeyGeneratorSpi)instance.impl,
+ instance.provider, algorithm);
+ }
+
+ /**
+ * Returns the provider of this <code>KeyGenerator</code> object.
+ *
+ * @return the provider of this <code>KeyGenerator</code> object
+ */
+ public final Provider getProvider() {
+ synchronized (lock) {
+ disableFailover();
+ return provider;
+ }
+ }
+
+ /**
+ * Update the active spi of this class and return the next
+ * implementation for failover. If no more implemenations are
+ * available, this method returns null. However, the active spi of
+ * this class is never set to null.
+ */
+ private KeyGeneratorSpi nextSpi(KeyGeneratorSpi oldSpi,
+ boolean reinit) {
+ synchronized (lock) {
+ // somebody else did a failover concurrently
+ // try that spi now
+ if ((oldSpi != null) && (oldSpi != spi)) {
+ return spi;
+ }
+ if (serviceIterator == null) {
+ return null;
+ }
+ while (serviceIterator.hasNext()) {
+ Service s = serviceIterator.next();
+ if (JceSecurity.canUseProvider(s.getProvider()) == false) {
+ continue;
+ }
+ try {
+ Object inst = s.newInstance(null);
+ // ignore non-spis
+ if (inst instanceof KeyGeneratorSpi == false) {
+ continue;
+ }
+ KeyGeneratorSpi spi = (KeyGeneratorSpi)inst;
+ if (reinit) {
+ if (initType == I_SIZE) {
+ spi.engineInit(initKeySize, initRandom);
+ } else if (initType == I_PARAMS) {
+ spi.engineInit(initParams, initRandom);
+ } else if (initType == I_RANDOM) {
+ spi.engineInit(initRandom);
+ } else if (initType != I_NONE) {
+ throw new AssertionError
+ ("KeyGenerator initType: " + initType);
+ }
+ }
+ provider = s.getProvider();
+ this.spi = spi;
+ return spi;
+ } catch (Exception e) {
+ // ignore
+ }
+ }
+ disableFailover();
+ return null;
+ }
+ }
+
+ void disableFailover() {
+ serviceIterator = null;
+ initType = 0;
+ initParams = null;
+ initRandom = null;
+ }
+
+ /**
+ * Initializes this key generator.
+ *
+ * @param random the source of randomness for this generator
+ */
+ public final void init(SecureRandom random) {
+ if (serviceIterator == null) {
+ spi.engineInit(random);
+ return;
+ }
+ RuntimeException failure = null;
+ KeyGeneratorSpi mySpi = spi;
+ do {
+ try {
+ mySpi.engineInit(random);
+ initType = I_RANDOM;
+ initKeySize = 0;
+ initParams = null;
+ initRandom = random;
+ return;
+ } catch (RuntimeException e) {
+ if (failure == null) {
+ failure = e;
+ }
+ mySpi = nextSpi(mySpi, false);
+ }
+ } while (mySpi != null);
+ throw failure;
+ }
+
+ /**
+ * Initializes this key generator with the specified parameter set.
+ *
+ * <p> If this key generator requires any random bytes, it will get them
+ * using the
+ * {@link java.security.SecureRandom}
+ * implementation of the highest-priority installed
+ * provider as the source of randomness.
+ * (If none of the installed providers supply an implementation of
+ * SecureRandom, a system-provided source of randomness will be used.)
+ *
+ * @param params the key generation parameters
+ *
+ * @exception InvalidAlgorithmParameterException if the given parameters
+ * are inappropriate for this key generator
+ */
+ public final void init(AlgorithmParameterSpec params)
+ throws InvalidAlgorithmParameterException
+ {
+ init(params, JceSecurity.RANDOM);
+ }
+
+ /**
+ * Initializes this key generator with the specified parameter
+ * set and a user-provided source of randomness.
+ *
+ * @param params the key generation parameters
+ * @param random the source of randomness for this key generator
+ *
+ * @exception InvalidAlgorithmParameterException if <code>params</code> is
+ * inappropriate for this key generator
+ */
+ public final void init(AlgorithmParameterSpec params, SecureRandom random)
+ throws InvalidAlgorithmParameterException
+ {
+ if (serviceIterator == null) {
+ spi.engineInit(params, random);
+ return;
+ }
+ Exception failure = null;
+ KeyGeneratorSpi mySpi = spi;
+ do {
+ try {
+ mySpi.engineInit(params, random);
+ initType = I_PARAMS;
+ initKeySize = 0;
+ initParams = params;
+ initRandom = random;
+ return;
+ } catch (Exception e) {
+ if (failure == null) {
+ failure = e;
+ }
+ mySpi = nextSpi(mySpi, false);
+ }
+ } while (mySpi != null);
+ if (failure instanceof InvalidAlgorithmParameterException) {
+ throw (InvalidAlgorithmParameterException)failure;
+ }
+ if (failure instanceof RuntimeException) {
+ throw (RuntimeException)failure;
+ }
+ throw new InvalidAlgorithmParameterException("init() failed", failure);
+ }
+
+ /**
+ * Initializes this key generator for a certain keysize.
+ *
+ * <p> If this key generator requires any random bytes, it will get them
+ * using the
+ * {@link java.security.SecureRandom}
+ * implementation of the highest-priority installed
+ * provider as the source of randomness.
+ * (If none of the installed providers supply an implementation of
+ * SecureRandom, a system-provided source of randomness will be used.)
+ *
+ * @param keysize the keysize. This is an algorithm-specific metric,
+ * specified in number of bits.
+ *
+ * @exception InvalidParameterException if the keysize is wrong or not
+ * supported.
+ */
+ public final void init(int keysize) {
+ init(keysize, JceSecurity.RANDOM);
+ }
+
+ /**
+ * Initializes this key generator for a certain keysize, using a
+ * user-provided source of randomness.
+ *
+ * @param keysize the keysize. This is an algorithm-specific metric,
+ * specified in number of bits.
+ * @param random the source of randomness for this key generator
+ *
+ * @exception InvalidParameterException if the keysize is wrong or not
+ * supported.
+ */
+ public final void init(int keysize, SecureRandom random) {
+ if (serviceIterator == null) {
+ spi.engineInit(keysize, random);
+ return;
+ }
+ RuntimeException failure = null;
+ KeyGeneratorSpi mySpi = spi;
+ do {
+ try {
+ mySpi.engineInit(keysize, random);
+ initType = I_SIZE;
+ initKeySize = keysize;
+ initParams = null;
+ initRandom = random;
+ return;
+ } catch (RuntimeException e) {
+ if (failure == null) {
+ failure = e;
+ }
+ mySpi = nextSpi(mySpi, false);
+ }
+ } while (mySpi != null);
+ throw failure;
+ }
+
+ /**
+ * Generates a secret key.
+ *
+ * @return the new key
+ */
+ public final SecretKey generateKey() {
+ if (serviceIterator == null) {
+ return spi.engineGenerateKey();
+ }
+ RuntimeException failure = null;
+ KeyGeneratorSpi mySpi = spi;
+ do {
+ try {
+ return mySpi.engineGenerateKey();
+ } catch (RuntimeException e) {
+ if (failure == null) {
+ failure = e;
+ }
+ mySpi = nextSpi(mySpi, true);
+ }
+ } while (mySpi != null);
+ throw failure;
+ }
+}
diff --git a/javax/crypto/KeyGeneratorSpi.java b/javax/crypto/KeyGeneratorSpi.java
new file mode 100644
index 0000000..f271e41
--- /dev/null
+++ b/javax/crypto/KeyGeneratorSpi.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.crypto;
+
+import java.security.*;
+import java.security.spec.*;
+
+/**
+ * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>)
+ * for the <code>KeyGenerator</code> class.
+ * All the abstract methods in this class must be implemented by each
+ * cryptographic service provider who wishes to supply the implementation
+ * of a key generator for a particular algorithm.
+ *
+ * @author Jan Luehe
+ *
+ * @see SecretKey
+ * @since 1.4
+ */
+
+public abstract class KeyGeneratorSpi {
+
+ /**
+ * Initializes the key generator.
+ *
+ * @param random the source of randomness for this generator
+ */
+ protected abstract void engineInit(SecureRandom random);
+
+ /**
+ * Initializes the key generator with the specified parameter
+ * set and a user-provided source of randomness.
+ *
+ * @param params the key generation parameters
+ * @param random the source of randomness for this key generator
+ *
+ * @exception InvalidAlgorithmParameterException if <code>params</code> is
+ * inappropriate for this key generator
+ */
+ protected abstract void engineInit(AlgorithmParameterSpec params,
+ SecureRandom random)
+ throws InvalidAlgorithmParameterException;
+
+ /**
+ * Initializes this key generator for a certain keysize, using the given
+ * source of randomness.
+ *
+ * @param keysize the keysize. This is an algorithm-specific metric,
+ * specified in number of bits.
+ * @param random the source of randomness for this key generator
+ *
+ * @exception InvalidParameterException if the keysize is wrong or not
+ * supported.
+ */
+ protected abstract void engineInit(int keysize, SecureRandom random);
+
+ /**
+ * Generates a secret key.
+ *
+ * @return the new key
+ */
+ protected abstract SecretKey engineGenerateKey();
+}
diff --git a/javax/crypto/Mac.annotated.java b/javax/crypto/Mac.annotated.java
new file mode 100644
index 0000000..a7e1995
--- /dev/null
+++ b/javax/crypto/Mac.annotated.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package javax.crypto;
+
+import java.util.*;
+import java.security.*;
+import sun.security.jca.*;
+import java.nio.ByteBuffer;
+import java.security.spec.AlgorithmParameterSpec;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class Mac implements java.lang.Cloneable {
+
+protected Mac(javax.crypto.MacSpi macSpi, java.security.Provider provider, java.lang.String algorithm) { throw new RuntimeException("Stub!"); }
+
+public final java.lang.String getAlgorithm() { throw new RuntimeException("Stub!"); }
+
+public static final javax.crypto.Mac getInstance(java.lang.String algorithm) throws java.security.NoSuchAlgorithmException { throw new RuntimeException("Stub!"); }
+
+public static final javax.crypto.Mac getInstance(java.lang.String algorithm, java.lang.String provider) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException { throw new RuntimeException("Stub!"); }
+
+public static final javax.crypto.Mac getInstance(java.lang.String algorithm, java.security.Provider provider) throws java.security.NoSuchAlgorithmException { throw new RuntimeException("Stub!"); }
+
+public final java.security.Provider getProvider() { throw new RuntimeException("Stub!"); }
+
+public final int getMacLength() { throw new RuntimeException("Stub!"); }
+
+public final void init(java.security.Key key) throws java.security.InvalidKeyException { throw new RuntimeException("Stub!"); }
+
+public final void init(java.security.Key key, java.security.spec.AlgorithmParameterSpec params) throws java.security.InvalidAlgorithmParameterException, java.security.InvalidKeyException { throw new RuntimeException("Stub!"); }
+
+public final void update(byte input) throws java.lang.IllegalStateException { throw new RuntimeException("Stub!"); }
+
+public final void update(byte[] input) throws java.lang.IllegalStateException { throw new RuntimeException("Stub!"); }
+
+public final void update(byte[] input, int offset, int len) throws java.lang.IllegalStateException { throw new RuntimeException("Stub!"); }
+
+public final void update(java.nio.ByteBuffer input) { throw new RuntimeException("Stub!"); }
+
+public final byte[] doFinal() throws java.lang.IllegalStateException { throw new RuntimeException("Stub!"); }
+
+public final void doFinal(byte[] output, int outOffset) throws java.lang.IllegalStateException, javax.crypto.ShortBufferException { throw new RuntimeException("Stub!"); }
+
+public final byte[] doFinal(byte[] input) throws java.lang.IllegalStateException { throw new RuntimeException("Stub!"); }
+
+public final void reset() { throw new RuntimeException("Stub!"); }
+
+public final java.lang.Object clone() throws java.lang.CloneNotSupportedException { throw new RuntimeException("Stub!"); }
+
[email protected]
+public javax.crypto.MacSpi getCurrentSpi() { throw new RuntimeException("Stub!"); }
+}
+
diff --git a/javax/crypto/Mac.java b/javax/crypto/Mac.java
new file mode 100644
index 0000000..f70a697
--- /dev/null
+++ b/javax/crypto/Mac.java
@@ -0,0 +1,790 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.crypto;
+
+import java.util.*;
+
+import java.security.*;
+import java.security.Provider.Service;
+import java.security.spec.AlgorithmParameterSpec;
+
+import java.nio.ByteBuffer;
+
+import sun.security.jca.*;
+import sun.security.jca.GetInstance.Instance;
+
+/**
+ * This class provides the functionality of a "Message Authentication Code"
+ * (MAC) algorithm.
+ *
+ * <p> A MAC provides a way to check
+ * the integrity of information transmitted over or stored in an unreliable
+ * medium, based on a secret key. Typically, message
+ * authentication codes are used between two parties that share a secret
+ * key in order to validate information transmitted between these
+ * parties.
+ *
+ * <p> A MAC mechanism that is based on cryptographic hash functions is
+ * referred to as HMAC. HMAC can be used with any cryptographic hash function,
+ * e.g., MD5 or SHA-1, in combination with a secret shared key. HMAC is
+ * specified in RFC 2104.
+ *
+ * <p> Android provides the following <code>Mac</code> algorithms:
+ * <table>
+ * <thead>
+ * <tr>
+ * <th>Algorithm</th>
+ * <th>Supported API Levels</th>
+ * </tr>
+ * </thead>
+ * <tbody>
+ * <tr class="deprecated">
+ * <td>DESMAC</td>
+ * <td>1-8</td>
+ * </tr>
+ * <tr class="deprecated">
+ * <td>DESMAC/CFB8</td>
+ * <td>1-8</td>
+ * </tr>
+ * <tr class="deprecated">
+ * <td>DESedeMAC</td>
+ * <td>1-8</td>
+ * </tr>
+ * <tr class="deprecated">
+ * <td>DESedeMAC/CFB8</td>
+ * <td>1-8</td>
+ * </tr>
+ * <tr class="deprecated">
+ * <td>DESedeMAC64</td>
+ * <td>1-8</td>
+ * </tr>
+ * <tr class="deprecated">
+ * <td>DESwithISO9797</td>
+ * <td>1-8</td>
+ * </tr>
+ * <tr>
+ * <td>HmacMD5</td>
+ * <td>1+</td>
+ * </tr>
+ * <tr>
+ * <td>HmacSHA1</td>
+ * <td>1+</td>
+ * </tr>
+ * <tr>
+ * <td>HmacSHA224</td>
+ * <td>1-8,22+</td>
+ * </tr>
+ * <tr>
+ * <td>HmacSHA256</td>
+ * <td>1+</td>
+ * </tr>
+ * <tr>
+ * <td>HmacSHA384</td>
+ * <td>1+</td>
+ * </tr>
+ * <tr>
+ * <td>HmacSHA512</td>
+ * <td>1+</td>
+ * </tr>
+ * <tr class="deprecated">
+ * <td>ISO9797ALG3MAC</td>
+ * <td>1-8</td>
+ * </tr>
+ * <tr>
+ * <td>PBEwithHmacSHA</td>
+ * <td>1+</td>
+ * </tr>
+ * <tr>
+ * <td>PBEwithHmacSHA1</td>
+ * <td>1+</td>
+ * </tr>
+ * <tr>
+ * <td>PBEwithHmacSHA224</td>
+ * <td>26+</td>
+ * </tr>
+ * <tr>
+ * <td>PBEwithHmacSHA256</td>
+ * <td>26+</td>
+ * </tr>
+ * <tr>
+ * <td>PBEwithHmacSHA384</td>
+ * <td>26+</td>
+ * </tr>
+ * <tr>
+ * <td>PBEwithHmacSHA512</td>
+ * <td>26+</td>
+ * </tr>
+ * </tbody>
+ * </table>
+ *
+ * These algorithms are described in the
+ * <a href="{@docRoot}/../technotes/guides/security/StandardNames.html#Mac">
+ * Mac section</a> of the
+ * Java Cryptography Architecture Standard Algorithm Name Documentation.
+ *
+ * @author Jan Luehe
+ *
+ * @since 1.4
+ */
+
+public class Mac implements Cloneable {
+
+ // Android-removed: this debugging mechanism is not used in Android.
+ /*
+ private static final Debug debug =
+ Debug.getInstance("jca", "Mac");
+
+ private static final Debug pdebug =
+ Debug.getInstance("provider", "Provider");
+ private static final boolean skipDebug =
+ Debug.isOn("engine=") && !Debug.isOn("mac");
+ */
+
+ // The provider
+ private Provider provider;
+
+ // The provider implementation (delegate)
+ private MacSpi spi;
+
+ // The name of the MAC algorithm.
+ private final String algorithm;
+
+ // Has this object been initialized?
+ private boolean initialized = false;
+
+ // BEGIN Android-removed: Redo the provider selection logic to allow reselecting provider.
+ // When only the algorithm is specified, we want to allow the Mac provider for that
+ // algorithm to change if multiple providers exist and they support different subsets of
+ // keys. To that end, we don't hold an iterator and exhaust it when we need to choose
+ // a provider like the upstream implementation, we reestablish the list of providers
+ // each time.
+ /*
+ // next service to try in provider selection
+ // null once provider is selected
+ private Service firstService;
+
+ // remaining services to try in provider selection
+ // null once provider is selected
+ private Iterator<Service> serviceIterator;
+ */
+ // END Android-removed: Redo the provider selection logic to allow reselecting provider.
+
+ private final Object lock;
+
+ /**
+ * Creates a MAC object.
+ *
+ * @param macSpi the delegate
+ * @param provider the provider
+ * @param algorithm the algorithm
+ */
+ protected Mac(MacSpi macSpi, Provider provider, String algorithm) {
+ this.spi = macSpi;
+ this.provider = provider;
+ this.algorithm = algorithm;
+ lock = null;
+ }
+
+ // Android-changed: Remove Service and Iterator from constructor args.
+ private Mac(String algorithm) {
+ this.algorithm = algorithm;
+ lock = new Object();
+ }
+
+ /**
+ * Returns the algorithm name of this <code>Mac</code> object.
+ *
+ * <p>This is the same name that was specified in one of the
+ * <code>getInstance</code> calls that created this
+ * <code>Mac</code> object.
+ *
+ * @return the algorithm name of this <code>Mac</code> object.
+ */
+ public final String getAlgorithm() {
+ return this.algorithm;
+ }
+
+ /**
+ * Returns a <code>Mac</code> object that implements the
+ * specified MAC algorithm.
+ *
+ * <p> This method traverses the list of registered security Providers,
+ * starting with the most preferred Provider.
+ * A new Mac object encapsulating the
+ * MacSpi implementation from the first
+ * Provider that supports the specified algorithm is returned.
+ *
+ * <p> Note that the list of registered providers may be retrieved via
+ * the {@link Security#getProviders() Security.getProviders()} method.
+ *
+ * @param algorithm the standard name of the requested MAC algorithm.
+ * See the Mac section in the <a href=
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#Mac">
+ * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+ * for information about standard algorithm names.
+ *
+ * @return the new <code>Mac</code> object.
+ *
+ * @exception NoSuchAlgorithmException if no Provider supports a
+ * MacSpi implementation for the
+ * specified algorithm.
+ *
+ * @see java.security.Provider
+ */
+ public static final Mac getInstance(String algorithm)
+ throws NoSuchAlgorithmException {
+ List<Service> services = GetInstance.getServices("Mac", algorithm);
+ // make sure there is at least one service from a signed provider
+ Iterator<Service> t = services.iterator();
+ while (t.hasNext()) {
+ Service s = t.next();
+ if (JceSecurity.canUseProvider(s.getProvider()) == false) {
+ continue;
+ }
+ // Android-changed: Remove Service and Iterator from constructor args.
+ // return new Mac(s, t, algorithm);
+ return new Mac(algorithm);
+ }
+ throw new NoSuchAlgorithmException
+ ("Algorithm " + algorithm + " not available");
+ }
+
+ /**
+ * Returns a <code>Mac</code> object that implements the
+ * specified MAC algorithm.
+ *
+ * <p> A new Mac object encapsulating the
+ * MacSpi implementation from the specified provider
+ * is returned. The specified provider must be registered
+ * in the security provider list.
+ *
+ * <p> Note that the list of registered providers may be retrieved via
+ * the {@link Security#getProviders() Security.getProviders()} method.
+ *
+ * @param algorithm the standard name of the requested MAC algorithm.
+ * See the Mac section in the <a href=
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#Mac">
+ * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+ * for information about standard algorithm names.
+ *
+ * @param provider the name of the provider.
+ *
+ * @return the new <code>Mac</code> object.
+ *
+ * @exception NoSuchAlgorithmException if a MacSpi
+ * implementation for the specified algorithm is not
+ * available from the specified provider.
+ *
+ * @exception NoSuchProviderException if the specified provider is not
+ * registered in the security provider list.
+ *
+ * @exception IllegalArgumentException if the <code>provider</code>
+ * is null or empty.
+ *
+ * @see java.security.Provider
+ */
+ public static final Mac getInstance(String algorithm, String provider)
+ throws NoSuchAlgorithmException, NoSuchProviderException {
+ // Android-added: Check for Bouncy Castle deprecation
+ Providers.checkBouncyCastleDeprecation(provider, "Mac", algorithm);
+ Instance instance = JceSecurity.getInstance
+ ("Mac", MacSpi.class, algorithm, provider);
+ return new Mac((MacSpi)instance.impl, instance.provider, algorithm);
+ }
+
+ /**
+ * Returns a <code>Mac</code> object that implements the
+ * specified MAC algorithm.
+ *
+ * <p> A new Mac object encapsulating the
+ * MacSpi implementation from the specified Provider
+ * object is returned. Note that the specified Provider object
+ * does not have to be registered in the provider list.
+ *
+ * @param algorithm the standard name of the requested MAC algorithm.
+ * See the Mac section in the <a href=
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#Mac">
+ * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+ * for information about standard algorithm names.
+ *
+ * @param provider the provider.
+ *
+ * @return the new <code>Mac</code> object.
+ *
+ * @exception NoSuchAlgorithmException if a MacSpi
+ * implementation for the specified algorithm is not available
+ * from the specified Provider object.
+ *
+ * @exception IllegalArgumentException if the <code>provider</code>
+ * is null.
+ *
+ * @see java.security.Provider
+ */
+ public static final Mac getInstance(String algorithm, Provider provider)
+ throws NoSuchAlgorithmException {
+ // Android-added: Check for Bouncy Castle deprecation
+ Providers.checkBouncyCastleDeprecation(provider, "Mac", algorithm);
+ Instance instance = JceSecurity.getInstance
+ ("Mac", MacSpi.class, algorithm, provider);
+ return new Mac((MacSpi)instance.impl, instance.provider, algorithm);
+ }
+
+ // max number of debug warnings to print from chooseFirstProvider()
+ private static int warnCount = 10;
+
+ /**
+ * Choose the Spi from the first provider available. Used if
+ * delayed provider selection is not possible because init()
+ * is not the first method called.
+ */
+ void chooseFirstProvider() {
+ // Android-changed: Check if lock is null rather than removed serviceIterator field.
+ // if ((spi != null) || (serviceIterator == null)) {
+ if (spi != null || lock == null) {
+ return;
+ }
+ synchronized (lock) {
+ if (spi != null) {
+ return;
+ }
+ // Android-removed: this debugging mechanism is not used in Android.
+ /*
+ if (debug != null) {
+ int w = --warnCount;
+ if (w >= 0) {
+ debug.println("Mac.init() not first method "
+ + "called, disabling delayed provider selection");
+ if (w == 0) {
+ debug.println("Further warnings of this type will "
+ + "be suppressed");
+ }
+ new Exception("Call trace").printStackTrace();
+ }
+ }
+ */
+ Exception lastException = null;
+ // Android-changed: Provider selection; loop over a new list each time.
+ for (Service s : GetInstance.getServices("Mac", algorithm)) {
+ if (JceSecurity.canUseProvider(s.getProvider()) == false) {
+ continue;
+ }
+ try {
+ Object obj = s.newInstance(null);
+ if (obj instanceof MacSpi == false) {
+ continue;
+ }
+ spi = (MacSpi)obj;
+ provider = s.getProvider();
+ // Android-removed: Provider selection; loop over a new list each time.
+ /*
+ // not needed any more
+ firstService = null;
+ serviceIterator = null;
+ */
+ return;
+ } catch (NoSuchAlgorithmException e) {
+ lastException = e;
+ }
+ }
+ ProviderException e = new ProviderException
+ ("Could not construct MacSpi instance");
+ if (lastException != null) {
+ e.initCause(lastException);
+ }
+ throw e;
+ }
+ }
+
+ private void chooseProvider(Key key, AlgorithmParameterSpec params)
+ throws InvalidKeyException, InvalidAlgorithmParameterException {
+ synchronized (lock) {
+ // Android-changed: Use the currently-selected provider only if no key was provided.
+ // if (spi != null) {
+ if (spi != null && (key == null || lock == null)) {
+ spi.engineInit(key, params);
+ return;
+ }
+ Exception lastException = null;
+ // Android-changed: Provider selection; loop over a new list each time.
+ for (Service s : GetInstance.getServices("Mac", algorithm)) {
+ // if provider says it does not support this key, ignore it
+ if (s.supportsParameter(key) == false) {
+ continue;
+ }
+ if (JceSecurity.canUseProvider(s.getProvider()) == false) {
+ continue;
+ }
+ try {
+ MacSpi spi = (MacSpi)s.newInstance(null);
+ spi.engineInit(key, params);
+ provider = s.getProvider();
+ this.spi = spi;
+ // Android-removed: Provider selection; loop over a new list each time.
+ /*
+ firstService = null;
+ serviceIterator = null;
+ */
+ return;
+ } catch (Exception e) {
+ // NoSuchAlgorithmException from newInstance()
+ // InvalidKeyException from init()
+ // RuntimeException (ProviderException) from init()
+ if (lastException == null) {
+ lastException = e;
+ }
+ }
+ }
+ // no working provider found, fail
+ if (lastException instanceof InvalidKeyException) {
+ throw (InvalidKeyException)lastException;
+ }
+ if (lastException instanceof InvalidAlgorithmParameterException) {
+ throw (InvalidAlgorithmParameterException)lastException;
+ }
+ if (lastException instanceof RuntimeException) {
+ throw (RuntimeException)lastException;
+ }
+ String kName = (key != null) ? key.getClass().getName() : "(null)";
+ throw new InvalidKeyException
+ ("No installed provider supports this key: "
+ + kName, lastException);
+ }
+ }
+
+ /**
+ * Returns the provider of this <code>Mac</code> object.
+ *
+ * @return the provider of this <code>Mac</code> object.
+ */
+ public final Provider getProvider() {
+ chooseFirstProvider();
+ return this.provider;
+ }
+
+ /**
+ * Returns the length of the MAC in bytes.
+ *
+ * @return the MAC length in bytes.
+ */
+ public final int getMacLength() {
+ chooseFirstProvider();
+ return spi.engineGetMacLength();
+ }
+
+ /**
+ * Initializes this <code>Mac</code> object with the given key.
+ *
+ * @param key the key.
+ *
+ * @exception InvalidKeyException if the given key is inappropriate for
+ * initializing this MAC.
+ */
+ public final void init(Key key) throws InvalidKeyException {
+ try {
+ // Android-changed: Use the currently-selected provider only if no key was provided.
+ // if (spi != null) {
+ if (spi != null && (key == null || lock == null)) {
+ spi.engineInit(key, null);
+ } else {
+ chooseProvider(key, null);
+ }
+ } catch (InvalidAlgorithmParameterException e) {
+ throw new InvalidKeyException("init() failed", e);
+ }
+ initialized = true;
+
+ // Android-removed: this debugging mechanism is not used in Android.
+ /*
+ if (!skipDebug && pdebug != null) {
+ pdebug.println("Mac." + algorithm + " algorithm from: " +
+ this.provider.getName());
+ }
+ */
+ }
+
+ /**
+ * Initializes this <code>Mac</code> object with the given key and
+ * algorithm parameters.
+ *
+ * @param key the key.
+ * @param params the algorithm parameters.
+ *
+ * @exception InvalidKeyException if the given key is inappropriate for
+ * initializing this MAC.
+ * @exception InvalidAlgorithmParameterException if the given algorithm
+ * parameters are inappropriate for this MAC.
+ */
+ public final void init(Key key, AlgorithmParameterSpec params)
+ throws InvalidKeyException, InvalidAlgorithmParameterException {
+ // Android-changed: Use the currently-selected provider only if no key was provided.
+ // if (spi != null) {
+ if (spi != null && (key == null || lock == null)) {
+ spi.engineInit(key, params);
+ } else {
+ chooseProvider(key, params);
+ }
+ initialized = true;
+
+ // Android-removed: this debugging mechanism is not used in Android.
+ /*
+ if (!skipDebug && pdebug != null) {
+ pdebug.println("Mac." + algorithm + " algorithm from: " +
+ this.provider.getName());
+ }
+ */
+ }
+
+ /**
+ * Processes the given byte.
+ *
+ * @param input the input byte to be processed.
+ *
+ * @exception IllegalStateException if this <code>Mac</code> has not been
+ * initialized.
+ */
+ public final void update(byte input) throws IllegalStateException {
+ chooseFirstProvider();
+ if (initialized == false) {
+ throw new IllegalStateException("MAC not initialized");
+ }
+ spi.engineUpdate(input);
+ }
+
+ /**
+ * Processes the given array of bytes.
+ *
+ * @param input the array of bytes to be processed.
+ *
+ * @exception IllegalStateException if this <code>Mac</code> has not been
+ * initialized.
+ */
+ public final void update(byte[] input) throws IllegalStateException {
+ chooseFirstProvider();
+ if (initialized == false) {
+ throw new IllegalStateException("MAC not initialized");
+ }
+ if (input != null) {
+ spi.engineUpdate(input, 0, input.length);
+ }
+ }
+
+ /**
+ * Processes the first <code>len</code> bytes in <code>input</code>,
+ * starting at <code>offset</code> inclusive.
+ *
+ * @param input the input buffer.
+ * @param offset the offset in <code>input</code> where the input starts.
+ * @param len the number of bytes to process.
+ *
+ * @exception IllegalStateException if this <code>Mac</code> has not been
+ * initialized.
+ */
+ public final void update(byte[] input, int offset, int len)
+ throws IllegalStateException {
+ chooseFirstProvider();
+ if (initialized == false) {
+ throw new IllegalStateException("MAC not initialized");
+ }
+
+ if (input != null) {
+ if ((offset < 0) || (len > (input.length - offset)) || (len < 0))
+ throw new IllegalArgumentException("Bad arguments");
+ spi.engineUpdate(input, offset, len);
+ }
+ }
+
+ /**
+ * Processes <code>input.remaining()</code> bytes in the ByteBuffer
+ * <code>input</code>, starting at <code>input.position()</code>.
+ * Upon return, the buffer's position will be equal to its limit;
+ * its limit will not have changed.
+ *
+ * @param input the ByteBuffer
+ *
+ * @exception IllegalStateException if this <code>Mac</code> has not been
+ * initialized.
+ * @since 1.5
+ */
+ public final void update(ByteBuffer input) {
+ chooseFirstProvider();
+ if (initialized == false) {
+ throw new IllegalStateException("MAC not initialized");
+ }
+ if (input == null) {
+ throw new IllegalArgumentException("Buffer must not be null");
+ }
+ spi.engineUpdate(input);
+ }
+
+ /**
+ * Finishes the MAC operation.
+ *
+ * <p>A call to this method resets this <code>Mac</code> object to the
+ * state it was in when previously initialized via a call to
+ * <code>init(Key)</code> or
+ * <code>init(Key, AlgorithmParameterSpec)</code>.
+ * That is, the object is reset and available to generate another MAC from
+ * the same key, if desired, via new calls to <code>update</code> and
+ * <code>doFinal</code>.
+ * (In order to reuse this <code>Mac</code> object with a different key,
+ * it must be reinitialized via a call to <code>init(Key)</code> or
+ * <code>init(Key, AlgorithmParameterSpec)</code>.
+ *
+ * @return the MAC result.
+ *
+ * @exception IllegalStateException if this <code>Mac</code> has not been
+ * initialized.
+ */
+ public final byte[] doFinal() throws IllegalStateException {
+ chooseFirstProvider();
+ if (initialized == false) {
+ throw new IllegalStateException("MAC not initialized");
+ }
+ byte[] mac = spi.engineDoFinal();
+ spi.engineReset();
+ return mac;
+ }
+
+ /**
+ * Finishes the MAC operation.
+ *
+ * <p>A call to this method resets this <code>Mac</code> object to the
+ * state it was in when previously initialized via a call to
+ * <code>init(Key)</code> or
+ * <code>init(Key, AlgorithmParameterSpec)</code>.
+ * That is, the object is reset and available to generate another MAC from
+ * the same key, if desired, via new calls to <code>update</code> and
+ * <code>doFinal</code>.
+ * (In order to reuse this <code>Mac</code> object with a different key,
+ * it must be reinitialized via a call to <code>init(Key)</code> or
+ * <code>init(Key, AlgorithmParameterSpec)</code>.
+ *
+ * <p>The MAC result is stored in <code>output</code>, starting at
+ * <code>outOffset</code> inclusive.
+ *
+ * @param output the buffer where the MAC result is stored
+ * @param outOffset the offset in <code>output</code> where the MAC is
+ * stored
+ *
+ * @exception ShortBufferException if the given output buffer is too small
+ * to hold the result
+ * @exception IllegalStateException if this <code>Mac</code> has not been
+ * initialized.
+ */
+ public final void doFinal(byte[] output, int outOffset)
+ throws ShortBufferException, IllegalStateException
+ {
+ chooseFirstProvider();
+ if (initialized == false) {
+ throw new IllegalStateException("MAC not initialized");
+ }
+ int macLen = getMacLength();
+ if (output == null || output.length-outOffset < macLen) {
+ throw new ShortBufferException
+ ("Cannot store MAC in output buffer");
+ }
+ byte[] mac = doFinal();
+ System.arraycopy(mac, 0, output, outOffset, macLen);
+ return;
+ }
+
+ /**
+ * Processes the given array of bytes and finishes the MAC operation.
+ *
+ * <p>A call to this method resets this <code>Mac</code> object to the
+ * state it was in when previously initialized via a call to
+ * <code>init(Key)</code> or
+ * <code>init(Key, AlgorithmParameterSpec)</code>.
+ * That is, the object is reset and available to generate another MAC from
+ * the same key, if desired, via new calls to <code>update</code> and
+ * <code>doFinal</code>.
+ * (In order to reuse this <code>Mac</code> object with a different key,
+ * it must be reinitialized via a call to <code>init(Key)</code> or
+ * <code>init(Key, AlgorithmParameterSpec)</code>.
+ *
+ * @param input data in bytes
+ * @return the MAC result.
+ *
+ * @exception IllegalStateException if this <code>Mac</code> has not been
+ * initialized.
+ */
+ public final byte[] doFinal(byte[] input) throws IllegalStateException
+ {
+ chooseFirstProvider();
+ if (initialized == false) {
+ throw new IllegalStateException("MAC not initialized");
+ }
+ update(input);
+ return doFinal();
+ }
+
+ /**
+ * Resets this <code>Mac</code> object.
+ *
+ * <p>A call to this method resets this <code>Mac</code> object to the
+ * state it was in when previously initialized via a call to
+ * <code>init(Key)</code> or
+ * <code>init(Key, AlgorithmParameterSpec)</code>.
+ * That is, the object is reset and available to generate another MAC from
+ * the same key, if desired, via new calls to <code>update</code> and
+ * <code>doFinal</code>.
+ * (In order to reuse this <code>Mac</code> object with a different key,
+ * it must be reinitialized via a call to <code>init(Key)</code> or
+ * <code>init(Key, AlgorithmParameterSpec)</code>.
+ */
+ public final void reset() {
+ chooseFirstProvider();
+ spi.engineReset();
+ }
+
+ /**
+ * Returns a clone if the provider implementation is cloneable.
+ *
+ * @return a clone if the provider implementation is cloneable.
+ *
+ * @exception CloneNotSupportedException if this is called on a
+ * delegate that does not support <code>Cloneable</code>.
+ */
+ public final Object clone() throws CloneNotSupportedException {
+ chooseFirstProvider();
+ Mac that = (Mac)super.clone();
+ that.spi = (MacSpi)this.spi.clone();
+ return that;
+ }
+
+ // BEGIN Android-added: Allow access to the current SPI for testing purposes.
+ /**
+ * Returns the {@code MacSpi} backing this {@code Mac} or {@code null} if no {@code MacSpi} is
+ * backing this {@code Mac}.
+ *
+ * @hide
+ */
+ public MacSpi getCurrentSpi() {
+ return spi;
+ }
+ // END Android-added: Allow access to the current SPI for testing purposes.
+}
diff --git a/javax/crypto/MacSpi.java b/javax/crypto/MacSpi.java
new file mode 100644
index 0000000..63aef78
--- /dev/null
+++ b/javax/crypto/MacSpi.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 1998, 2007, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.crypto;
+
+import java.security.*;
+import java.security.spec.*;
+
+import java.nio.ByteBuffer;
+
+/**
+ * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>)
+ * for the <code>Mac</code> class.
+ * All the abstract methods in this class must be implemented by each
+ * cryptographic service provider who wishes to supply the implementation
+ * of a particular MAC algorithm.
+ *
+ * <p> Implementations are free to implement the Cloneable interface.
+ *
+ * @author Jan Luehe
+ *
+ * @since 1.4
+ */
+
+public abstract class MacSpi {
+
+ /**
+ * Returns the length of the MAC in bytes.
+ *
+ * @return the MAC length in bytes.
+ */
+ protected abstract int engineGetMacLength();
+
+ /**
+ * Initializes the MAC with the given (secret) key and algorithm
+ * parameters.
+ *
+ * @param key the (secret) key.
+ * @param params the algorithm parameters.
+ *
+ * @exception InvalidKeyException if the given key is inappropriate for
+ * initializing this MAC.
+ * @exception InvalidAlgorithmParameterException if the given algorithm
+ * parameters are inappropriate for this MAC.
+ */
+ protected abstract void engineInit(Key key,
+ AlgorithmParameterSpec params)
+ throws InvalidKeyException, InvalidAlgorithmParameterException ;
+
+ /**
+ * Processes the given byte.
+ *
+ * @param input the input byte to be processed.
+ */
+ protected abstract void engineUpdate(byte input);
+
+ /**
+ * Processes the first <code>len</code> bytes in <code>input</code>,
+ * starting at <code>offset</code> inclusive.
+ *
+ * @param input the input buffer.
+ * @param offset the offset in <code>input</code> where the input starts.
+ * @param len the number of bytes to process.
+ */
+ protected abstract void engineUpdate(byte[] input, int offset, int len);
+
+ /**
+ * Processes <code>input.remaining()</code> bytes in the ByteBuffer
+ * <code>input</code>, starting at <code>input.position()</code>.
+ * Upon return, the buffer's position will be equal to its limit;
+ * its limit will not have changed.
+ *
+ * <p>Subclasses should consider overriding this method if they can
+ * process ByteBuffers more efficiently than byte arrays.
+ *
+ * @param input the ByteBuffer
+ * @since 1.5
+ */
+ protected void engineUpdate(ByteBuffer input) {
+ if (input.hasRemaining() == false) {
+ return;
+ }
+ if (input.hasArray()) {
+ byte[] b = input.array();
+ int ofs = input.arrayOffset();
+ int pos = input.position();
+ int lim = input.limit();
+ engineUpdate(b, ofs + pos, lim - pos);
+ input.position(lim);
+ } else {
+ int len = input.remaining();
+ byte[] b = new byte[CipherSpi.getTempArraySize(len)];
+ while (len > 0) {
+ int chunk = Math.min(len, b.length);
+ input.get(b, 0, chunk);
+ engineUpdate(b, 0, chunk);
+ len -= chunk;
+ }
+ }
+ }
+
+ /**
+ * Completes the MAC computation and resets the MAC for further use,
+ * maintaining the secret key that the MAC was initialized with.
+ *
+ * @return the MAC result.
+ */
+ protected abstract byte[] engineDoFinal();
+
+ /**
+ * Resets the MAC for further use, maintaining the secret key that the
+ * MAC was initialized with.
+ */
+ protected abstract void engineReset();
+
+ /**
+ * Returns a clone if the implementation is cloneable.
+ *
+ * @return a clone if the implementation is cloneable.
+ *
+ * @exception CloneNotSupportedException if this is called
+ * on an implementation that does not support <code>Cloneable</code>.
+ */
+ public Object clone() throws CloneNotSupportedException {
+ if (this instanceof Cloneable) {
+ return super.clone();
+ } else {
+ throw new CloneNotSupportedException();
+ }
+ }
+}
diff --git a/javax/crypto/NoSuchPaddingException.java b/javax/crypto/NoSuchPaddingException.java
new file mode 100644
index 0000000..054157f
--- /dev/null
+++ b/javax/crypto/NoSuchPaddingException.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.crypto;
+
+import java.security.GeneralSecurityException;
+
+/**
+ * This exception is thrown when a particular padding mechanism is
+ * requested but is not available in the environment.
+ *
+ * @author Jan Luehe
+ *
+ * @since 1.4
+ */
+
+public class NoSuchPaddingException extends GeneralSecurityException {
+
+ private static final long serialVersionUID = -4572885201200175466L;
+
+ /**
+ * Constructs a NoSuchPaddingException with no detail
+ * message. A detail message is a String that describes this
+ * particular exception.
+ */
+ public NoSuchPaddingException() {
+ super();
+ }
+
+ /**
+ * Constructs a NoSuchPaddingException with the specified
+ * detail message.
+ *
+ * @param msg the detail message.
+ */
+ public NoSuchPaddingException(String msg) {
+ super(msg);
+ }
+}
diff --git a/javax/crypto/NullCipher.java b/javax/crypto/NullCipher.java
new file mode 100644
index 0000000..dda9eb4
--- /dev/null
+++ b/javax/crypto/NullCipher.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.crypto;
+
+/**
+ * The NullCipher class is a class that provides an
+ * "identity cipher" -- one that does not transform the plain text. As
+ * a consequence, the ciphertext is identical to the plaintext. All
+ * initialization methods do nothing, while the blocksize is set to 1
+ * byte.
+ *
+ * @author Li Gong
+ * @since 1.4
+ */
+
+public class NullCipher extends Cipher {
+
+ /**
+ * Creates a NullCipher object.
+ */
+ public NullCipher() {
+ super(new NullCipherSpi(), null, null);
+ }
+}
diff --git a/javax/crypto/NullCipherSpi.java b/javax/crypto/NullCipherSpi.java
new file mode 100644
index 0000000..7419f87
--- /dev/null
+++ b/javax/crypto/NullCipherSpi.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.crypto;
+
+import java.security.*;
+import java.security.spec.*;
+
+/**
+ * This class provides a delegate for the identity cipher - one that does not
+ * transform the plain text.
+ *
+ * @author Li Gong
+ * @see NullCipher
+ *
+ * @since 1.4
+ */
+
+final class NullCipherSpi extends CipherSpi {
+
+ /*
+ * Do not let anybody instantiate this directly (protected).
+ */
+ protected NullCipherSpi() {}
+
+ public void engineSetMode(String mode) {}
+
+ public void engineSetPadding(String padding) {}
+
+ protected int engineGetBlockSize() {
+ return 1;
+ }
+
+ protected int engineGetOutputSize(int inputLen) {
+ return inputLen;
+ }
+
+ protected byte[] engineGetIV() {
+ byte[] x = new byte[8];
+ return x;
+ }
+
+ protected AlgorithmParameters engineGetParameters() {
+ return null;
+ }
+
+ protected void engineInit(int mode, Key key, SecureRandom random) {}
+
+ protected void engineInit(int mode, Key key,
+ AlgorithmParameterSpec params,
+ SecureRandom random) {}
+
+ protected void engineInit(int mode, Key key,
+ AlgorithmParameters params,
+ SecureRandom random) {}
+
+ protected byte[] engineUpdate(byte[] input, int inputOffset,
+ int inputLen) {
+ if (input == null) return null;
+ byte[] x = new byte[inputLen];
+ System.arraycopy(input, inputOffset, x, 0, inputLen);
+ return x;
+ }
+
+ protected int engineUpdate(byte[] input, int inputOffset,
+ int inputLen, byte[] output,
+ int outputOffset) {
+ if (input == null) return 0;
+ System.arraycopy(input, inputOffset, output, outputOffset, inputLen);
+ return inputLen;
+ }
+
+ protected byte[] engineDoFinal(byte[] input, int inputOffset,
+ int inputLen)
+ {
+ return engineUpdate(input, inputOffset, inputLen);
+ }
+
+ protected int engineDoFinal(byte[] input, int inputOffset,
+ int inputLen, byte[] output,
+ int outputOffset)
+ {
+ return engineUpdate(input, inputOffset, inputLen,
+ output, outputOffset);
+ }
+
+ protected int engineGetKeySize(Key key)
+ {
+ return 0;
+ }
+}
diff --git a/javax/crypto/SealedObject.java b/javax/crypto/SealedObject.java
new file mode 100644
index 0000000..9cee4d0
--- /dev/null
+++ b/javax/crypto/SealedObject.java
@@ -0,0 +1,493 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.crypto;
+
+import java.io.*;
+import java.security.AlgorithmParameters;
+import java.security.Key;
+import java.security.InvalidKeyException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+
+/**
+ * This class enables a programmer to create an object and protect its
+ * confidentiality with a cryptographic algorithm.
+ *
+ * <p> Given any Serializable object, one can create a SealedObject
+ * that encapsulates the original object, in serialized
+ * format (i.e., a "deep copy"), and seals (encrypts) its serialized contents,
+ * using a cryptographic algorithm such as DES, to protect its
+ * confidentiality. The encrypted content can later be decrypted (with
+ * the corresponding algorithm using the correct decryption key) and
+ * de-serialized, yielding the original object.
+ *
+ * <p> Note that the Cipher object must be fully initialized with the
+ * correct algorithm, key, padding scheme, etc., before being applied
+ * to a SealedObject.
+ *
+ * <p> The original object that was sealed can be recovered in two different
+ * ways:
+ *
+ * <ul>
+ *
+ * <li>by using the {@link #getObject(javax.crypto.Cipher) getObject}
+ * method that takes a <code>Cipher</code> object.
+ *
+ * <p> This method requires a fully initialized <code>Cipher</code> object,
+ * initialized with the
+ * exact same algorithm, key, padding scheme, etc., that were used to seal the
+ * object.
+ *
+ * <p> This approach has the advantage that the party who unseals the
+ * sealed object does not require knowledge of the decryption key. For example,
+ * after one party has initialized the cipher object with the required
+ * decryption key, it could hand over the cipher object to
+ * another party who then unseals the sealed object.
+ *
+ * <li>by using one of the
+ * {@link #getObject(java.security.Key) getObject} methods
+ * that take a <code>Key</code> object.
+ *
+ * <p> In this approach, the <code>getObject</code> method creates a cipher
+ * object for the appropriate decryption algorithm and initializes it with the
+ * given decryption key and the algorithm parameters (if any) that were stored
+ * in the sealed object.
+ *
+ * <p> This approach has the advantage that the party who
+ * unseals the object does not need to keep track of the parameters (e.g., an
+ * IV) that were used to seal the object.
+ *
+ * </ul>
+ *
+ * @author Li Gong
+ * @author Jan Luehe
+ * @see Cipher
+ * @since 1.4
+ */
+
+public class SealedObject implements Serializable {
+
+ static final long serialVersionUID = 4482838265551344752L;
+
+ /**
+ * The serialized object contents in encrypted format.
+ *
+ * @serial
+ */
+ private byte[] encryptedContent = null;
+
+ /**
+ * The algorithm that was used to seal this object.
+ *
+ * @serial
+ */
+ private String sealAlg = null;
+
+ /**
+ * The algorithm of the parameters used.
+ *
+ * @serial
+ */
+ private String paramsAlg = null;
+
+ /**
+ * The cryptographic parameters used by the sealing Cipher,
+ * encoded in the default format.
+ * <p>
+ * That is, <code>cipher.getParameters().getEncoded()</code>.
+ *
+ * @serial
+ */
+ protected byte[] encodedParams = null;
+
+ /**
+ * Constructs a SealedObject from any Serializable object.
+ *
+ * <p>The given object is serialized, and its serialized contents are
+ * encrypted using the given Cipher, which must be fully initialized.
+ *
+ * <p>Any algorithm parameters that may be used in the encryption
+ * operation are stored inside of the new <code>SealedObject</code>.
+ *
+ * @param object the object to be sealed; can be null.
+ * @param c the cipher used to seal the object.
+ *
+ * @exception NullPointerException if the given cipher is null.
+ * @exception IOException if an error occurs during serialization
+ * @exception IllegalBlockSizeException if the given cipher is a block
+ * cipher, no padding has been requested, and the total input length
+ * (i.e., the length of the serialized object contents) is not a multiple
+ * of the cipher's block size
+ */
+ public SealedObject(Serializable object, Cipher c) throws IOException,
+ IllegalBlockSizeException
+ {
+ /*
+ * Serialize the object
+ */
+
+ // creating a stream pipe-line, from a to b
+ ByteArrayOutputStream b = new ByteArrayOutputStream();
+ ObjectOutput a = new ObjectOutputStream(b);
+ byte[] content;
+ try {
+ // write and flush the object content to byte array
+ a.writeObject(object);
+ a.flush();
+ content = b.toByteArray();
+ } finally {
+ a.close();
+ }
+
+ /*
+ * Seal the object
+ */
+ try {
+ this.encryptedContent = c.doFinal(content);
+ }
+ catch (BadPaddingException ex) {
+ // if sealing is encryption only
+ // Should never happen??
+ }
+
+ // Save the parameters
+ if (c.getParameters() != null) {
+ this.encodedParams = c.getParameters().getEncoded();
+ this.paramsAlg = c.getParameters().getAlgorithm();
+ }
+
+ // Save the encryption algorithm
+ this.sealAlg = c.getAlgorithm();
+ }
+
+ /**
+ * Constructs a SealedObject object from the passed-in SealedObject.
+ *
+ * @param so a SealedObject object
+ * @exception NullPointerException if the given sealed object is null.
+ */
+ protected SealedObject(SealedObject so) {
+ this.encryptedContent = so.encryptedContent.clone();
+ this.sealAlg = so.sealAlg;
+ this.paramsAlg = so.paramsAlg;
+ if (so.encodedParams != null) {
+ this.encodedParams = so.encodedParams.clone();
+ } else {
+ this.encodedParams = null;
+ }
+ }
+
+ /**
+ * Returns the algorithm that was used to seal this object.
+ *
+ * @return the algorithm that was used to seal this object.
+ */
+ public final String getAlgorithm() {
+ return this.sealAlg;
+ }
+
+ /**
+ * Retrieves the original (encapsulated) object.
+ *
+ * <p>This method creates a cipher for the algorithm that had been used in
+ * the sealing operation.
+ * If the default provider package provides an implementation of that
+ * algorithm, an instance of Cipher containing that implementation is used.
+ * If the algorithm is not available in the default package, other
+ * packages are searched.
+ * The Cipher object is initialized for decryption, using the given
+ * <code>key</code> and the parameters (if any) that had been used in the
+ * sealing operation.
+ *
+ * <p>The encapsulated object is unsealed and de-serialized, before it is
+ * returned.
+ *
+ * @param key the key used to unseal the object.
+ *
+ * @return the original object.
+ *
+ * @exception IOException if an error occurs during de-serialiazation.
+ * @exception ClassNotFoundException if an error occurs during
+ * de-serialiazation.
+ * @exception NoSuchAlgorithmException if the algorithm to unseal the
+ * object is not available.
+ * @exception InvalidKeyException if the given key cannot be used to unseal
+ * the object (e.g., it has the wrong algorithm).
+ * @exception NullPointerException if <code>key</code> is null.
+ */
+ public final Object getObject(Key key)
+ throws IOException, ClassNotFoundException, NoSuchAlgorithmException,
+ InvalidKeyException
+ {
+ if (key == null) {
+ throw new NullPointerException("key is null");
+ }
+
+ try {
+ return unseal(key, null);
+ } catch (NoSuchProviderException nspe) {
+ // we've already caught NoSuchProviderException's and converted
+ // them into NoSuchAlgorithmException's with details about
+ // the failing algorithm
+ throw new NoSuchAlgorithmException("algorithm not found");
+ } catch (IllegalBlockSizeException ibse) {
+ throw new InvalidKeyException(ibse.getMessage());
+ } catch (BadPaddingException bpe) {
+ throw new InvalidKeyException(bpe.getMessage());
+ }
+ }
+
+ /**
+ * Retrieves the original (encapsulated) object.
+ *
+ * <p>The encapsulated object is unsealed (using the given Cipher,
+ * assuming that the Cipher is already properly initialized) and
+ * de-serialized, before it is returned.
+ *
+ * @param c the cipher used to unseal the object
+ *
+ * @return the original object.
+ *
+ * @exception NullPointerException if the given cipher is null.
+ * @exception IOException if an error occurs during de-serialiazation
+ * @exception ClassNotFoundException if an error occurs during
+ * de-serialiazation
+ * @exception IllegalBlockSizeException if the given cipher is a block
+ * cipher, no padding has been requested, and the total input length is
+ * not a multiple of the cipher's block size
+ * @exception BadPaddingException if the given cipher has been
+ * initialized for decryption, and padding has been specified, but
+ * the input data does not have proper expected padding bytes
+ */
+ public final Object getObject(Cipher c)
+ throws IOException, ClassNotFoundException, IllegalBlockSizeException,
+ BadPaddingException
+ {
+ /*
+ * Unseal the object
+ */
+ byte[] content = c.doFinal(this.encryptedContent);
+
+ /*
+ * De-serialize it
+ */
+ // creating a stream pipe-line, from b to a
+ ByteArrayInputStream b = new ByteArrayInputStream(content);
+ ObjectInput a = new extObjectInputStream(b);
+ try {
+ Object obj = a.readObject();
+ return obj;
+ } finally {
+ a.close();
+ }
+ }
+
+ /**
+ * Retrieves the original (encapsulated) object.
+ *
+ * <p>This method creates a cipher for the algorithm that had been used in
+ * the sealing operation, using an implementation of that algorithm from
+ * the given <code>provider</code>.
+ * The Cipher object is initialized for decryption, using the given
+ * <code>key</code> and the parameters (if any) that had been used in the
+ * sealing operation.
+ *
+ * <p>The encapsulated object is unsealed and de-serialized, before it is
+ * returned.
+ *
+ * @param key the key used to unseal the object.
+ * @param provider the name of the provider of the algorithm to unseal
+ * the object.
+ *
+ * @return the original object.
+ *
+ * @exception IllegalArgumentException if the given provider is null
+ * or empty.
+ * @exception IOException if an error occurs during de-serialiazation.
+ * @exception ClassNotFoundException if an error occurs during
+ * de-serialiazation.
+ * @exception NoSuchAlgorithmException if the algorithm to unseal the
+ * object is not available.
+ * @exception NoSuchProviderException if the given provider is not
+ * configured.
+ * @exception InvalidKeyException if the given key cannot be used to unseal
+ * the object (e.g., it has the wrong algorithm).
+ * @exception NullPointerException if <code>key</code> is null.
+ */
+ public final Object getObject(Key key, String provider)
+ throws IOException, ClassNotFoundException, NoSuchAlgorithmException,
+ NoSuchProviderException, InvalidKeyException
+ {
+ if (key == null) {
+ throw new NullPointerException("key is null");
+ }
+ if (provider == null || provider.length() == 0) {
+ throw new IllegalArgumentException("missing provider");
+ }
+
+ try {
+ return unseal(key, provider);
+ } catch (IllegalBlockSizeException | BadPaddingException ex) {
+ throw new InvalidKeyException(ex.getMessage());
+ }
+ }
+
+
+ private Object unseal(Key key, String provider)
+ throws IOException, ClassNotFoundException, NoSuchAlgorithmException,
+ NoSuchProviderException, InvalidKeyException,
+ IllegalBlockSizeException, BadPaddingException
+ {
+ /*
+ * Create the parameter object.
+ */
+ AlgorithmParameters params = null;
+ if (this.encodedParams != null) {
+ try {
+ if (provider != null)
+ params = AlgorithmParameters.getInstance(this.paramsAlg,
+ provider);
+ else
+ params = AlgorithmParameters.getInstance(this.paramsAlg);
+
+ } catch (NoSuchProviderException nspe) {
+ if (provider == null) {
+ throw new NoSuchAlgorithmException(this.paramsAlg
+ + " not found");
+ } else {
+ throw new NoSuchProviderException(nspe.getMessage());
+ }
+ }
+ params.init(this.encodedParams);
+ }
+
+ /*
+ * Create and initialize the cipher.
+ */
+ Cipher c;
+ try {
+ if (provider != null)
+ c = Cipher.getInstance(this.sealAlg, provider);
+ else
+ c = Cipher.getInstance(this.sealAlg);
+ } catch (NoSuchPaddingException nspe) {
+ throw new NoSuchAlgorithmException("Padding that was used in "
+ + "sealing operation not "
+ + "available");
+ } catch (NoSuchProviderException nspe) {
+ if (provider == null) {
+ throw new NoSuchAlgorithmException(this.sealAlg+" not found");
+ } else {
+ throw new NoSuchProviderException(nspe.getMessage());
+ }
+ }
+
+ try {
+ if (params != null)
+ c.init(Cipher.DECRYPT_MODE, key, params);
+ else
+ c.init(Cipher.DECRYPT_MODE, key);
+ } catch (InvalidAlgorithmParameterException iape) {
+ // this should never happen, because we use the exact same
+ // parameters that were used in the sealing operation
+ throw new RuntimeException(iape.getMessage());
+ }
+
+ /*
+ * Unseal the object
+ */
+ byte[] content = c.doFinal(this.encryptedContent);
+
+ /*
+ * De-serialize it
+ */
+ // creating a stream pipe-line, from b to a
+ ByteArrayInputStream b = new ByteArrayInputStream(content);
+ ObjectInput a = new extObjectInputStream(b);
+ try {
+ Object obj = a.readObject();
+ return obj;
+ } finally {
+ a.close();
+ }
+ }
+
+ /**
+ * Restores the state of the SealedObject from a stream.
+ * @param s the object input stream.
+ * @exception NullPointerException if s is null.
+ */
+ private void readObject(java.io.ObjectInputStream s)
+ throws java.io.IOException, ClassNotFoundException
+ {
+ s.defaultReadObject();
+ if (encryptedContent != null)
+ encryptedContent = encryptedContent.clone();
+ if (encodedParams != null)
+ encodedParams = encodedParams.clone();
+ }
+}
+
+final class extObjectInputStream extends ObjectInputStream {
+
+ private static ClassLoader systemClassLoader = null;
+
+ extObjectInputStream(InputStream in)
+ throws IOException, StreamCorruptedException {
+ super(in);
+ }
+
+ protected Class<?> resolveClass(ObjectStreamClass v)
+ throws IOException, ClassNotFoundException
+ {
+
+ try {
+ /*
+ * Calling the super.resolveClass() first
+ * will let us pick up bug fixes in the super
+ * class (e.g., 4171142).
+ */
+ return super.resolveClass(v);
+ } catch (ClassNotFoundException cnfe) {
+ /*
+ * This is a workaround for bug 4224921.
+ */
+ ClassLoader loader = Thread.currentThread().getContextClassLoader();
+ if (loader == null) {
+ if (systemClassLoader == null) {
+ systemClassLoader = ClassLoader.getSystemClassLoader();
+ }
+ loader = systemClassLoader;
+ if (loader == null) {
+ throw new ClassNotFoundException(v.getName());
+ }
+ }
+
+ return Class.forName(v.getName(), false, loader);
+ }
+ }
+}
diff --git a/javax/crypto/SecretKey.java b/javax/crypto/SecretKey.java
new file mode 100644
index 0000000..e03639a
--- /dev/null
+++ b/javax/crypto/SecretKey.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.crypto;
+
+/**
+ * A secret (symmetric) key.
+ * The purpose of this interface is to group (and provide type safety
+ * for) all secret key interfaces.
+ * <p>
+ * Provider implementations of this interface must overwrite the
+ * {@code equals} and {@code hashCode} methods inherited from
+ * {@link java.lang.Object}, so that secret keys are compared based on
+ * their underlying key material and not based on reference.
+ * Implementations should override the default {@code destroy} and
+ * {@code isDestroyed} methods from the
+ * {@link javax.security.auth.Destroyable} interface to enable
+ * sensitive key information to be destroyed, cleared, or in the case
+ * where such information is immutable, unreferenced.
+ * Finally, since {@code SecretKey} is {@code Serializable}, implementations
+ * should also override
+ * {@link java.io.ObjectOutputStream#writeObject(java.lang.Object)}
+ * to prevent keys that have been destroyed from being serialized.
+ *
+ * <p>Keys that implement this interface return the string {@code RAW}
+ * as their encoding format (see {@code getFormat}), and return the
+ * raw key bytes as the result of a {@code getEncoded} method call. (The
+ * {@code getFormat} and {@code getEncoded} methods are inherited
+ * from the {@link java.security.Key} parent interface.)
+ *
+ * @author Jan Luehe
+ *
+ * @see SecretKeyFactory
+ * @see Cipher
+ * @since 1.4
+ */
+
+public interface SecretKey extends
+ java.security.Key, javax.security.auth.Destroyable {
+
+ /**
+ * The class fingerprint that is set to indicate serialization
+ * compatibility since J2SE 1.4.
+ */
+ static final long serialVersionUID = -4795878709595146952L;
+}
diff --git a/javax/crypto/SecretKeyFactory.java b/javax/crypto/SecretKeyFactory.java
new file mode 100644
index 0000000..bd8b271
--- /dev/null
+++ b/javax/crypto/SecretKeyFactory.java
@@ -0,0 +1,617 @@
+/*
+ * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.crypto;
+
+import java.util.*;
+
+import java.security.*;
+import java.security.Provider.Service;
+import java.security.spec.*;
+
+import sun.security.jca.*;
+import sun.security.jca.GetInstance.Instance;
+
+/**
+ * This class represents a factory for secret keys.
+ *
+ * <P> Key factories are used to convert <I>keys</I> (opaque
+ * cryptographic keys of type <code>Key</code>) into <I>key specifications</I>
+ * (transparent representations of the underlying key material), and vice
+ * versa.
+ * Secret key factories operate only on secret (symmetric) keys.
+ *
+ * <P> Key factories are bi-directional, i.e., they allow to build an opaque
+ * key object from a given key specification (key material), or to retrieve
+ * the underlying key material of a key object in a suitable format.
+ *
+ * <P> Application developers should refer to their provider's documentation
+ * to find out which key specifications are supported by the
+ * {@link #generateSecret(java.security.spec.KeySpec) generateSecret} and
+ * {@link #getKeySpec(javax.crypto.SecretKey, java.lang.Class) getKeySpec}
+ * methods.
+ * For example, the DES secret-key factory supplied by the "SunJCE" provider
+ * supports <code>DESKeySpec</code> as a transparent representation of DES
+ * keys, and that provider's secret-key factory for Triple DES keys supports
+ * <code>DESedeKeySpec</code> as a transparent representation of Triple DES
+ * keys.
+ *
+ * <p> Android provides the following <code>SecretKeyFactory</code> algorithms:
+ * <table>
+ * <thead>
+ * <tr>
+ * <th>Algorithm</th>
+ * <th>Supported API Levels</th>
+ * </tr>
+ * </thead>
+ * <tbody>
+ * <tr>
+ * <td>AES</td>
+ * <td>23+</td>
+ * </tr>
+ * <tr>
+ * <td>DES</td>
+ * <td>1+</td>
+ * </tr>
+ * <tr>
+ * <td>DESede</td>
+ * <td>1+</td>
+ * </tr>
+ * <tr>
+ * <td>HmacSHA1</td>
+ * <td>23+</td>
+ * </tr>
+ * <tr>
+ * <td>HmacSHA224</td>
+ * <td>23+</td>
+ * </tr>
+ * <tr>
+ * <td>HmacSHA256</td>
+ * <td>23+</td>
+ * </tr>
+ * <tr>
+ * <td>HmacSHA384</td>
+ * <td>23+</td>
+ * </tr>
+ * <tr>
+ * <td>HmacSHA512</td>
+ * <td>23+</td>
+ * </tr>
+ * <tr>
+ * <td>PBEwithHmacSHA1</td>
+ * <td>1+</td>
+ * </tr>
+ * <tr>
+ * <td>PBEwithHmacSHA1AndAES_128</td>
+ * <td>26+</td>
+ * </tr>
+ * <tr>
+ * <td>PBEwithHmacSHA1AndAES_256</td>
+ * <td>26+</td>
+ * </tr>
+ * <tr>
+ * <td>PBEwithHmacSHA224AndAES_128</td>
+ * <td>26+</td>
+ * </tr>
+ * <tr>
+ * <td>PBEwithHmacSHA224AndAES_256</td>
+ * <td>26+</td>
+ * </tr>
+ * <tr>
+ * <td>PBEwithHmacSHA256AndAES_128</td>
+ * <td>26+</td>
+ * </tr>
+ * <tr>
+ * <td>PBEwithHmacSHA256AndAES_256</td>
+ * <td>26+</td>
+ * </tr>
+ * <tr>
+ * <td>PBEwithHmacSHA384AndAES_128</td>
+ * <td>26+</td>
+ * </tr>
+ * <tr>
+ * <td>PBEwithHmacSHA384AndAES_256</td>
+ * <td>26+</td>
+ * </tr>
+ * <tr>
+ * <td>PBEwithHmacSHA512AndAES_128</td>
+ * <td>26+</td>
+ * </tr>
+ * <tr>
+ * <td>PBEwithHmacSHA512AndAES_256</td>
+ * <td>26+</td>
+ * </tr>
+ * <tr>
+ * <td>PBEwithMD5AND128BITAES-CBC-OPENSSL</td>
+ * <td>1+</td>
+ * </tr>
+ * <tr>
+ * <td>PBEwithMD5AND192BITAES-CBC-OPENSSL</td>
+ * <td>1+</td>
+ * </tr>
+ * <tr>
+ * <td>PBEwithMD5AND256BITAES-CBC-OPENSSL</td>
+ * <td>1+</td>
+ * </tr>
+ * <tr>
+ * <td>PBEwithMD5ANDDES</td>
+ * <td>1+</td>
+ * </tr>
+ * <tr>
+ * <td>PBEwithMD5ANDRC2</td>
+ * <td>1+</td>
+ * </tr>
+ * <tr>
+ * <td>PBEwithSHA1ANDDES</td>
+ * <td>1+</td>
+ * </tr>
+ * <tr>
+ * <td>PBEwithSHA1ANDRC2</td>
+ * <td>1+</td>
+ * </tr>
+ * <tr>
+ * <td>PBEwithSHA256AND128BITAES-CBC-BC</td>
+ * <td>1+</td>
+ * </tr>
+ * <tr>
+ * <td>PBEwithSHA256AND192BITAES-CBC-BC</td>
+ * <td>1+</td>
+ * </tr>
+ * <tr>
+ * <td>PBEwithSHA256AND256BITAES-CBC-BC</td>
+ * <td>1+</td>
+ * </tr>
+ * <tr>
+ * <td>PBEwithSHAAND128BITAES-CBC-BC</td>
+ * <td>1+</td>
+ * </tr>
+ * <tr>
+ * <td>PBEwithSHAAND128BITRC2-CBC</td>
+ * <td>10+</td>
+ * </tr>
+ * <tr>
+ * <td>PBEwithSHAAND128BITRC4</td>
+ * <td>10+</td>
+ * </tr>
+ * <tr>
+ * <td>PBEwithSHAAND192BITAES-CBC-BC</td>
+ * <td>1+</td>
+ * </tr>
+ * <tr>
+ * <td>PBEwithSHAAND2-KEYTRIPLEDES-CBC</td>
+ * <td>1+</td>
+ * </tr>
+ * <tr>
+ * <td>PBEwithSHAAND256BITAES-CBC-BC</td>
+ * <td>1+</td>
+ * </tr>
+ * <tr>
+ * <td>PBEwithSHAAND3-KEYTRIPLEDES-CBC</td>
+ * <td>1+</td>
+ * </tr>
+ * <tr>
+ * <td>PBEwithSHAAND40BITRC2-CBC</td>
+ * <td>1+</td>
+ * </tr>
+ * <tr>
+ * <td>PBEwithSHAAND40BITRC4</td>
+ * <td>10+</td>
+ * </tr>
+ * <tr>
+ * <td>PBEwithSHAANDTWOFISH-CBC</td>
+ * <td>10+</td>
+ * </tr>
+ * <tr>
+ * <td>PBKDF2withHmacSHA1</td>
+ * <td>10+</td>
+ * </tr>
+ * <tr>
+ * <td>PBKDF2withHmacSHA1And8BIT</td>
+ * <td>19+</td>
+ * </tr>
+ * <tr>
+ * <td>PBKDF2withHmacSHA224</td>
+ * <td>26+</td>
+ * </tr>
+ * <tr>
+ * <td>PBKDF2withHmacSHA256</td>
+ * <td>26+</td>
+ * </tr>
+ * <tr>
+ * <td>PBKDF2withHmacSHA384</td>
+ * <td>26+</td>
+ * </tr>
+ * <tr>
+ * <td>PBKDF2withHmacSHA512</td>
+ * <td>26+</td>
+ * </tr>
+ * </tbody>
+ * </table>
+ *
+ * These algorithms are described in the <a href=
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#SecretKeyFactory">
+ * SecretKeyFactory section</a> of the
+ * Java Cryptography Architecture Standard Algorithm Name Documentation.
+ *
+ * @author Jan Luehe
+ *
+ * @see SecretKey
+ * @see javax.crypto.spec.DESKeySpec
+ * @see javax.crypto.spec.DESedeKeySpec
+ * @see javax.crypto.spec.PBEKeySpec
+ * @since 1.4
+ */
+
+public class SecretKeyFactory {
+
+ // The provider
+ private Provider provider;
+
+ // The algorithm associated with this factory
+ private final String algorithm;
+
+ // The provider implementation (delegate)
+ private volatile SecretKeyFactorySpi spi;
+
+ // lock for mutex during provider selection
+ private final Object lock = new Object();
+
+ // remaining services to try in provider selection
+ // null once provider is selected
+ private Iterator<Service> serviceIterator;
+
+ /**
+ * Creates a SecretKeyFactory object.
+ *
+ * @param keyFacSpi the delegate
+ * @param provider the provider
+ * @param algorithm the secret-key algorithm
+ */
+ protected SecretKeyFactory(SecretKeyFactorySpi keyFacSpi,
+ Provider provider, String algorithm) {
+ this.spi = keyFacSpi;
+ this.provider = provider;
+ this.algorithm = algorithm;
+ }
+
+ private SecretKeyFactory(String algorithm) throws NoSuchAlgorithmException {
+ this.algorithm = algorithm;
+ List<Service> list =
+ GetInstance.getServices("SecretKeyFactory", algorithm);
+ serviceIterator = list.iterator();
+ // fetch and instantiate initial spi
+ if (nextSpi(null) == null) {
+ throw new NoSuchAlgorithmException
+ (algorithm + " SecretKeyFactory not available");
+ }
+ }
+
+ /**
+ * Returns a <code>SecretKeyFactory</code> object that converts
+ * secret keys of the specified algorithm.
+ *
+ * <p> This method traverses the list of registered security Providers,
+ * starting with the most preferred Provider.
+ * A new SecretKeyFactory object encapsulating the
+ * SecretKeyFactorySpi implementation from the first
+ * Provider that supports the specified algorithm is returned.
+ *
+ * <p> Note that the list of registered providers may be retrieved via
+ * the {@link Security#getProviders() Security.getProviders()} method.
+ *
+ * @param algorithm the standard name of the requested secret-key
+ * algorithm.
+ * See the SecretKeyFactory section in the <a href=
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#SecretKeyFactory">
+ * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+ * for information about standard algorithm names.
+ *
+ * @return the new <code>SecretKeyFactory</code> object.
+ *
+ * @exception NullPointerException if the specified algorithm
+ * is null.
+ *
+ * @exception NoSuchAlgorithmException if no Provider supports a
+ * SecretKeyFactorySpi implementation for the
+ * specified algorithm.
+ *
+ * @see java.security.Provider
+ */
+ public static final SecretKeyFactory getInstance(String algorithm)
+ throws NoSuchAlgorithmException {
+ return new SecretKeyFactory(algorithm);
+ }
+
+ /**
+ * Returns a <code>SecretKeyFactory</code> object that converts
+ * secret keys of the specified algorithm.
+ *
+ * <p> A new SecretKeyFactory object encapsulating the
+ * SecretKeyFactorySpi implementation from the specified provider
+ * is returned. The specified provider must be registered
+ * in the security provider list.
+ *
+ * <p> Note that the list of registered providers may be retrieved via
+ * the {@link Security#getProviders() Security.getProviders()} method.
+ *
+ * @param algorithm the standard name of the requested secret-key
+ * algorithm.
+ * See the SecretKeyFactory section in the <a href=
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#SecretKeyFactory">
+ * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+ * for information about standard algorithm names.
+ *
+ * @param provider the name of the provider.
+ *
+ * @return the new <code>SecretKeyFactory</code> object.
+ *
+ * @exception NoSuchAlgorithmException if a SecretKeyFactorySpi
+ * implementation for the specified algorithm is not
+ * available from the specified provider.
+ *
+ * @exception NullPointerException if the specified algorithm
+ * is null.
+ *
+ * @throws NoSuchProviderException if the specified provider is not
+ * registered in the security provider list.
+ *
+ * @exception IllegalArgumentException if the <code>provider</code>
+ * is null or empty.
+ *
+ * @see java.security.Provider
+ */
+ public static final SecretKeyFactory getInstance(String algorithm,
+ String provider) throws NoSuchAlgorithmException,
+ NoSuchProviderException {
+ // Android-added: Check for Bouncy Castle deprecation
+ Providers.checkBouncyCastleDeprecation(provider, "SecretKeyFactory", algorithm);
+ Instance instance = JceSecurity.getInstance("SecretKeyFactory",
+ SecretKeyFactorySpi.class, algorithm, provider);
+ return new SecretKeyFactory((SecretKeyFactorySpi)instance.impl,
+ instance.provider, algorithm);
+ }
+
+ /**
+ * Returns a <code>SecretKeyFactory</code> object that converts
+ * secret keys of the specified algorithm.
+ *
+ * <p> A new SecretKeyFactory object encapsulating the
+ * SecretKeyFactorySpi implementation from the specified Provider
+ * object is returned. Note that the specified Provider object
+ * does not have to be registered in the provider list.
+ *
+ * @param algorithm the standard name of the requested secret-key
+ * algorithm.
+ * See the SecretKeyFactory section in the <a href=
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#SecretKeyFactory">
+ * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+ * for information about standard algorithm names.
+ *
+ * @param provider the provider.
+ *
+ * @return the new <code>SecretKeyFactory</code> object.
+ *
+ * @exception NullPointerException if the specified algorithm
+ * is null.
+ *
+ * @exception NoSuchAlgorithmException if a SecretKeyFactorySpi
+ * implementation for the specified algorithm is not available
+ * from the specified Provider object.
+ *
+ * @exception IllegalArgumentException if the <code>provider</code>
+ * is null.
+ *
+ * @see java.security.Provider
+ */
+ public static final SecretKeyFactory getInstance(String algorithm,
+ Provider provider) throws NoSuchAlgorithmException {
+ // Android-added: Check for Bouncy Castle deprecation
+ Providers.checkBouncyCastleDeprecation(provider, "SecretKeyFactory", algorithm);
+ Instance instance = JceSecurity.getInstance("SecretKeyFactory",
+ SecretKeyFactorySpi.class, algorithm, provider);
+ return new SecretKeyFactory((SecretKeyFactorySpi)instance.impl,
+ instance.provider, algorithm);
+ }
+
+ /**
+ * Returns the provider of this <code>SecretKeyFactory</code> object.
+ *
+ * @return the provider of this <code>SecretKeyFactory</code> object
+ */
+ public final Provider getProvider() {
+ synchronized (lock) {
+ // disable further failover after this call
+ serviceIterator = null;
+ return provider;
+ }
+ }
+
+ /**
+ * Returns the algorithm name of this <code>SecretKeyFactory</code> object.
+ *
+ * <p>This is the same name that was specified in one of the
+ * <code>getInstance</code> calls that created this
+ * <code>SecretKeyFactory</code> object.
+ *
+ * @return the algorithm name of this <code>SecretKeyFactory</code>
+ * object.
+ */
+ public final String getAlgorithm() {
+ return this.algorithm;
+ }
+
+ /**
+ * Update the active spi of this class and return the next
+ * implementation for failover. If no more implemenations are
+ * available, this method returns null. However, the active spi of
+ * this class is never set to null.
+ */
+ private SecretKeyFactorySpi nextSpi(SecretKeyFactorySpi oldSpi) {
+ synchronized (lock) {
+ // somebody else did a failover concurrently
+ // try that spi now
+ if ((oldSpi != null) && (oldSpi != spi)) {
+ return spi;
+ }
+ if (serviceIterator == null) {
+ return null;
+ }
+ while (serviceIterator.hasNext()) {
+ Service s = serviceIterator.next();
+ if (JceSecurity.canUseProvider(s.getProvider()) == false) {
+ continue;
+ }
+ try {
+ Object obj = s.newInstance(null);
+ if (obj instanceof SecretKeyFactorySpi == false) {
+ continue;
+ }
+ SecretKeyFactorySpi spi = (SecretKeyFactorySpi)obj;
+ provider = s.getProvider();
+ this.spi = spi;
+ return spi;
+ } catch (NoSuchAlgorithmException e) {
+ // ignore
+ }
+ }
+ serviceIterator = null;
+ return null;
+ }
+ }
+
+ /**
+ * Generates a <code>SecretKey</code> object from the provided key
+ * specification (key material).
+ *
+ * @param keySpec the specification (key material) of the secret key
+ *
+ * @return the secret key
+ *
+ * @exception InvalidKeySpecException if the given key specification
+ * is inappropriate for this secret-key factory to produce a secret key.
+ */
+ public final SecretKey generateSecret(KeySpec keySpec)
+ throws InvalidKeySpecException {
+ if (serviceIterator == null) {
+ return spi.engineGenerateSecret(keySpec);
+ }
+ Exception failure = null;
+ SecretKeyFactorySpi mySpi = spi;
+ do {
+ try {
+ return mySpi.engineGenerateSecret(keySpec);
+ } catch (Exception e) {
+ if (failure == null) {
+ failure = e;
+ }
+ mySpi = nextSpi(mySpi);
+ }
+ } while (mySpi != null);
+ if (failure instanceof InvalidKeySpecException) {
+ throw (InvalidKeySpecException)failure;
+ }
+ throw new InvalidKeySpecException
+ ("Could not generate secret key", failure);
+ }
+
+ /**
+ * Returns a specification (key material) of the given key object
+ * in the requested format.
+ *
+ * @param key the key
+ * @param keySpec the requested format in which the key material shall be
+ * returned
+ *
+ * @return the underlying key specification (key material) in the
+ * requested format
+ *
+ * @exception InvalidKeySpecException if the requested key specification is
+ * inappropriate for the given key (e.g., the algorithms associated with
+ * <code>key</code> and <code>keySpec</code> do not match, or
+ * <code>key</code> references a key on a cryptographic hardware device
+ * whereas <code>keySpec</code> is the specification of a software-based
+ * key), or the given key cannot be dealt with
+ * (e.g., the given key has an algorithm or format not supported by this
+ * secret-key factory).
+ */
+ public final KeySpec getKeySpec(SecretKey key, Class<?> keySpec)
+ throws InvalidKeySpecException {
+ if (serviceIterator == null) {
+ return spi.engineGetKeySpec(key, keySpec);
+ }
+ Exception failure = null;
+ SecretKeyFactorySpi mySpi = spi;
+ do {
+ try {
+ return mySpi.engineGetKeySpec(key, keySpec);
+ } catch (Exception e) {
+ if (failure == null) {
+ failure = e;
+ }
+ mySpi = nextSpi(mySpi);
+ }
+ } while (mySpi != null);
+ if (failure instanceof InvalidKeySpecException) {
+ throw (InvalidKeySpecException)failure;
+ }
+ throw new InvalidKeySpecException
+ ("Could not get key spec", failure);
+ }
+
+ /**
+ * Translates a key object, whose provider may be unknown or potentially
+ * untrusted, into a corresponding key object of this secret-key factory.
+ *
+ * @param key the key whose provider is unknown or untrusted
+ *
+ * @return the translated key
+ *
+ * @exception InvalidKeyException if the given key cannot be processed
+ * by this secret-key factory.
+ */
+ public final SecretKey translateKey(SecretKey key)
+ throws InvalidKeyException {
+ if (serviceIterator == null) {
+ return spi.engineTranslateKey(key);
+ }
+ Exception failure = null;
+ SecretKeyFactorySpi mySpi = spi;
+ do {
+ try {
+ return mySpi.engineTranslateKey(key);
+ } catch (Exception e) {
+ if (failure == null) {
+ failure = e;
+ }
+ mySpi = nextSpi(mySpi);
+ }
+ } while (mySpi != null);
+ if (failure instanceof InvalidKeyException) {
+ throw (InvalidKeyException)failure;
+ }
+ throw new InvalidKeyException
+ ("Could not translate key", failure);
+ }
+}
diff --git a/javax/crypto/SecretKeyFactorySpi.java b/javax/crypto/SecretKeyFactorySpi.java
new file mode 100644
index 0000000..342a5c7
--- /dev/null
+++ b/javax/crypto/SecretKeyFactorySpi.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.crypto;
+
+import java.security.*;
+import java.security.spec.*;
+
+/**
+ * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>)
+ * for the <code>SecretKeyFactory</code> class.
+ * All the abstract methods in this class must be implemented by each
+ * cryptographic service provider who wishes to supply the implementation
+ * of a secret-key factory for a particular algorithm.
+ *
+ * <P> A provider should document all the key specifications supported by its
+ * secret key factory.
+ * For example, the DES secret-key factory supplied by the "SunJCE" provider
+ * supports <code>DESKeySpec</code> as a transparent representation of DES
+ * keys, and that provider's secret-key factory for Triple DES keys supports
+ * <code>DESedeKeySpec</code> as a transparent representation of Triple DES
+ * keys.
+ *
+ * @author Jan Luehe
+ *
+ * @see SecretKey
+ * @see javax.crypto.spec.DESKeySpec
+ * @see javax.crypto.spec.DESedeKeySpec
+ * @since 1.4
+ */
+
+public abstract class SecretKeyFactorySpi {
+
+ /**
+ * Generates a <code>SecretKey</code> object from the
+ * provided key specification (key material).
+ *
+ * @param keySpec the specification (key material) of the secret key
+ *
+ * @return the secret key
+ *
+ * @exception InvalidKeySpecException if the given key specification
+ * is inappropriate for this secret-key factory to produce a secret key.
+ */
+ protected abstract SecretKey engineGenerateSecret(KeySpec keySpec)
+ throws InvalidKeySpecException;
+
+ /**
+ * Returns a specification (key material) of the given key
+ * object in the requested format.
+ *
+ * @param key the key
+ *
+ * @param keySpec the requested format in which the key material shall be
+ * returned
+ *
+ * @return the underlying key specification (key material) in the
+ * requested format
+ *
+ * @exception InvalidKeySpecException if the requested key specification is
+ * inappropriate for the given key (e.g., the algorithms associated with
+ * <code>key</code> and <code>keySpec</code> do not match, or
+ * <code>key</code> references a key on a cryptographic hardware device
+ * whereas <code>keySpec</code> is the specification of a software-based
+ * key), or the given key cannot be dealt with
+ * (e.g., the given key has an algorithm or format not supported by this
+ * secret-key factory).
+ */
+ protected abstract KeySpec engineGetKeySpec(SecretKey key, Class<?> keySpec)
+ throws InvalidKeySpecException;
+
+ /**
+ * Translates a key object, whose provider may be unknown or
+ * potentially untrusted, into a corresponding key object of this
+ * secret-key factory.
+ *
+ * @param key the key whose provider is unknown or untrusted
+ *
+ * @return the translated key
+ *
+ * @exception InvalidKeyException if the given key cannot be processed
+ * by this secret-key factory.
+ */
+ protected abstract SecretKey engineTranslateKey(SecretKey key)
+ throws InvalidKeyException;
+}
diff --git a/javax/crypto/ShortBufferException.java b/javax/crypto/ShortBufferException.java
new file mode 100644
index 0000000..0a25fff
--- /dev/null
+++ b/javax/crypto/ShortBufferException.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.crypto;
+
+import java.security.GeneralSecurityException;
+
+/**
+ * This exception is thrown when an output buffer provided by the user
+ * is too short to hold the operation result.
+ *
+ * @author Jan Luehe
+ *
+ * @since 1.4
+ */
+
+public class ShortBufferException extends GeneralSecurityException {
+
+ private static final long serialVersionUID = 8427718640832943747L;
+
+ /**
+ * Constructs a ShortBufferException with no detail
+ * message. A detail message is a String that describes this
+ * particular exception.
+ */
+ public ShortBufferException() {
+ super();
+ }
+
+ /**
+ * Constructs a ShortBufferException with the specified
+ * detail message.
+ *
+ * @param msg the detail message.
+ */
+ public ShortBufferException(String msg) {
+ super(msg);
+ }
+}
diff --git a/javax/crypto/interfaces/DHKey.java b/javax/crypto/interfaces/DHKey.java
new file mode 100644
index 0000000..37dfda7
--- /dev/null
+++ b/javax/crypto/interfaces/DHKey.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.crypto.interfaces;
+
+import javax.crypto.spec.DHParameterSpec;
+
+/**
+ * The interface to a Diffie-Hellman key.
+ *
+ * @author Jan Luehe
+ *
+ * @see javax.crypto.spec.DHParameterSpec
+ * @see DHPublicKey
+ * @see DHPrivateKey
+ * @since 1.4
+ */
+public interface DHKey {
+
+ /**
+ * Returns the key parameters.
+ *
+ * @return the key parameters
+ */
+ DHParameterSpec getParams();
+}
diff --git a/javax/crypto/interfaces/DHPrivateKey.java b/javax/crypto/interfaces/DHPrivateKey.java
new file mode 100644
index 0000000..1fa3ba0
--- /dev/null
+++ b/javax/crypto/interfaces/DHPrivateKey.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.crypto.interfaces;
+
+import java.math.BigInteger;
+
+/**
+ * The interface to a Diffie-Hellman private key.
+ *
+ * @author Jan Luehe
+ *
+ * @see DHKey
+ * @see DHPublicKey
+ * @since 1.4
+ */
+public interface DHPrivateKey extends DHKey, java.security.PrivateKey {
+
+ /**
+ * The class fingerprint that is set to indicate serialization
+ * compatibility since J2SE 1.4.
+ */
+ static final long serialVersionUID = 2211791113380396553L;
+
+ /**
+ * Returns the private value, <code>x</code>.
+ *
+ * @return the private value, <code>x</code>
+ */
+ BigInteger getX();
+}
diff --git a/javax/crypto/interfaces/DHPublicKey.java b/javax/crypto/interfaces/DHPublicKey.java
new file mode 100644
index 0000000..a1fdb41
--- /dev/null
+++ b/javax/crypto/interfaces/DHPublicKey.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.crypto.interfaces;
+
+import java.math.BigInteger;
+
+/**
+ * The interface to a Diffie-Hellman public key.
+ *
+ * @author Jan Luehe
+ *
+ * @see DHKey
+ * @see DHPrivateKey
+ * @since 1.4
+ */
+public interface DHPublicKey extends DHKey, java.security.PublicKey {
+
+ /**
+ * The class fingerprint that is set to indicate serialization
+ * compatibility since J2SE 1.4.
+ */
+ static final long serialVersionUID = -6628103563352519193L;
+
+ /**
+ * Returns the public value, <code>y</code>.
+ *
+ * @return the public value, <code>y</code>
+ */
+ BigInteger getY();
+}
diff --git a/javax/crypto/interfaces/PBEKey.java b/javax/crypto/interfaces/PBEKey.java
new file mode 100644
index 0000000..3027726
--- /dev/null
+++ b/javax/crypto/interfaces/PBEKey.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2001, 2007, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.crypto.interfaces;
+
+import java.math.BigInteger;
+
+/**
+ * The interface to a PBE key.
+ *
+ * @author Valerie Peng
+ *
+ * @see javax.crypto.spec.PBEKeySpec
+ * @see javax.crypto.SecretKey
+ * @since 1.4
+ */
+public interface PBEKey extends javax.crypto.SecretKey {
+
+ /**
+ * The class fingerprint that is set to indicate serialization
+ * compatibility since J2SE 1.4.
+ */
+ static final long serialVersionUID = -1430015993304333921L;
+
+ /**
+ * Returns the password.
+ *
+ * <p> Note: this method should return a copy of the password. It is
+ * the caller's responsibility to zero out the password information after
+ * it is no longer needed.
+ *
+ * @return the password.
+ */
+ char[] getPassword();
+
+ /**
+ * Returns the salt or null if not specified.
+ *
+ * <p> Note: this method should return a copy of the salt. It is
+ * the caller's responsibility to zero out the salt information after
+ * it is no longer needed.
+ *
+ * @return the salt.
+ */
+ byte[] getSalt();
+
+ /**
+ * Returns the iteration count or 0 if not specified.
+ *
+ * @return the iteration count.
+ */
+ int getIterationCount();
+}
diff --git a/javax/crypto/spec/DESKeySpec.java b/javax/crypto/spec/DESKeySpec.java
new file mode 100644
index 0000000..2d35f0a
--- /dev/null
+++ b/javax/crypto/spec/DESKeySpec.java
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.crypto.spec;
+
+import java.security.InvalidKeyException;
+
+/**
+ * This class specifies a DES key.
+ *
+ * @author Jan Luehe
+ *
+ * @since 1.4
+ */
+public class DESKeySpec implements java.security.spec.KeySpec {
+
+ /**
+ * The constant which defines the length of a DES key in bytes.
+ */
+ public static final int DES_KEY_LEN = 8;
+
+ private byte[] key;
+
+ /*
+ * Weak/semi-weak keys copied from FIPS 74.
+ *
+ * "...The first 6 keys have duals different than themselves, hence
+ * each is both a key and a dual giving 12 keys with duals. The last
+ * four keys equal their duals, and are called self-dual keys..."
+ *
+ * 1. E001E001F101F101 01E001E001F101F1
+ * 2. FE1FFE1FFEOEFEOE 1FFE1FFEOEFEOEFE
+ * 3. E01FE01FF10EF10E 1FE01FEOOEF10EF1
+ * 4. 01FE01FE01FE01FE FE01FE01FE01FE01
+ * 5. 011F011F010E010E 1F011F010E010E01
+ * 6. E0FEE0FEF1FEF1FE FEE0FEE0FEF1FEF1
+ * 7. 0101010101010101 0101010101010101
+ * 8. FEFEFEFEFEFEFEFE FEFEFEFEFEFEFEFE
+ * 9. E0E0E0E0F1F1F1F1 E0E0E0E0F1F1F1F1
+ * 10. 1F1F1F1F0E0E0E0E 1F1F1F1F0E0E0E0E
+ */
+ private static final byte[][] WEAK_KEYS = {
+
+ { (byte)0x01, (byte)0x01, (byte)0x01, (byte)0x01, (byte)0x01,
+ (byte)0x01, (byte)0x01, (byte)0x01 },
+
+ { (byte)0xFE, (byte)0xFE, (byte)0xFE, (byte)0xFE, (byte)0xFE,
+ (byte)0xFE, (byte)0xFE, (byte)0xFE },
+
+ { (byte)0x1F, (byte)0x1F, (byte)0x1F, (byte)0x1F, (byte)0x0E,
+ (byte)0x0E, (byte)0x0E, (byte)0x0E },
+
+ { (byte)0xE0, (byte)0xE0, (byte)0xE0, (byte)0xE0, (byte)0xF1,
+ (byte)0xF1, (byte)0xF1, (byte)0xF1 },
+
+ { (byte)0x01, (byte)0xFE, (byte)0x01, (byte)0xFE, (byte)0x01,
+ (byte)0xFE, (byte)0x01, (byte)0xFE },
+
+ { (byte)0x1F, (byte)0xE0, (byte)0x1F, (byte)0xE0, (byte)0x0E,
+ (byte)0xF1, (byte)0x0E, (byte)0xF1 },
+
+ { (byte)0x01, (byte)0xE0, (byte)0x01, (byte)0xE0, (byte)0x01,
+ (byte)0xF1, (byte)0x01, (byte)0xF1 },
+
+ { (byte)0x1F, (byte)0xFE, (byte)0x1F, (byte)0xFE, (byte)0x0E,
+ (byte)0xFE, (byte)0x0E, (byte)0xFE },
+
+ { (byte)0x01, (byte)0x1F, (byte)0x01, (byte)0x1F, (byte)0x01,
+ (byte)0x0E, (byte)0x01, (byte)0x0E },
+
+ { (byte)0xE0, (byte)0xFE, (byte)0xE0, (byte)0xFE, (byte)0xF1,
+ (byte)0xFE, (byte)0xF1, (byte)0xFE },
+
+ { (byte)0xFE, (byte)0x01, (byte)0xFE, (byte)0x01, (byte)0xFE,
+ (byte)0x01, (byte)0xFE, (byte)0x01 },
+
+ { (byte)0xE0, (byte)0x1F, (byte)0xE0, (byte)0x1F, (byte)0xF1,
+ (byte)0x0E, (byte)0xF1, (byte)0x0E },
+
+ { (byte)0xE0, (byte)0x01, (byte)0xE0, (byte)0x01, (byte)0xF1,
+ (byte)0x01, (byte)0xF1, (byte)0x01 },
+
+ { (byte)0xFE, (byte)0x1F, (byte)0xFE, (byte)0x1F, (byte)0xFE,
+ (byte)0x0E, (byte)0xFE, (byte)0x0E },
+
+ { (byte)0x1F, (byte)0x01, (byte)0x1F, (byte)0x01, (byte)0x0E,
+ (byte)0x01, (byte)0x0E, (byte)0x01 },
+
+ { (byte)0xFE, (byte)0xE0, (byte)0xFE, (byte)0xE0, (byte)0xFE,
+ (byte)0xF1, (byte)0xFE, (byte)0xF1 }
+ };
+
+ /**
+ * Creates a DESKeySpec object using the first 8 bytes in
+ * <code>key</code> as the key material for the DES key.
+ *
+ * <p> The bytes that constitute the DES key are those between
+ * <code>key[0]</code> and <code>key[7]</code> inclusive.
+ *
+ * @param key the buffer with the DES key material. The first 8 bytes
+ * of the buffer are copied to protect against subsequent modification.
+ *
+ * @exception NullPointerException if the given key material is
+ * <code>null</code>
+ * @exception InvalidKeyException if the given key material is shorter
+ * than 8 bytes.
+ */
+ public DESKeySpec(byte[] key) throws InvalidKeyException {
+ this(key, 0);
+ }
+
+ /**
+ * Creates a DESKeySpec object using the first 8 bytes in
+ * <code>key</code>, beginning at <code>offset</code> inclusive,
+ * as the key material for the DES key.
+ *
+ * <p> The bytes that constitute the DES key are those between
+ * <code>key[offset]</code> and <code>key[offset+7]</code> inclusive.
+ *
+ * @param key the buffer with the DES key material. The first 8 bytes
+ * of the buffer beginning at <code>offset</code> inclusive are copied
+ * to protect against subsequent modification.
+ * @param offset the offset in <code>key</code>, where the DES key
+ * material starts.
+ *
+ * @exception NullPointerException if the given key material is
+ * <code>null</code>
+ * @exception InvalidKeyException if the given key material, starting at
+ * <code>offset</code> inclusive, is shorter than 8 bytes.
+ */
+ public DESKeySpec(byte[] key, int offset) throws InvalidKeyException {
+ if (key.length - offset < DES_KEY_LEN) {
+ throw new InvalidKeyException("Wrong key size");
+ }
+ this.key = new byte[DES_KEY_LEN];
+ System.arraycopy(key, offset, this.key, 0, DES_KEY_LEN);
+ }
+
+ /**
+ * Returns the DES key material.
+ *
+ * @return the DES key material. Returns a new array
+ * each time this method is called.
+ */
+ public byte[] getKey() {
+ return this.key.clone();
+ }
+
+ /**
+ * Checks if the given DES key material, starting at <code>offset</code>
+ * inclusive, is parity-adjusted.
+ *
+ * @param key the buffer with the DES key material.
+ * @param offset the offset in <code>key</code>, where the DES key
+ * material starts.
+ *
+ * @return true if the given DES key material is parity-adjusted, false
+ * otherwise.
+ *
+ * @exception InvalidKeyException if the given key material is
+ * <code>null</code>, or starting at <code>offset</code> inclusive, is
+ * shorter than 8 bytes.
+ */
+ public static boolean isParityAdjusted(byte[] key, int offset)
+ throws InvalidKeyException {
+ if (key == null) {
+ throw new InvalidKeyException("null key");
+ }
+ if (key.length - offset < DES_KEY_LEN) {
+ throw new InvalidKeyException("Wrong key size");
+ }
+
+ for (int i = 0; i < DES_KEY_LEN; i++) {
+ int k = Integer.bitCount(key[offset++] & 0xff);
+ if ((k & 1) == 0) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Checks if the given DES key material is weak or semi-weak.
+ *
+ * @param key the buffer with the DES key material.
+ * @param offset the offset in <code>key</code>, where the DES key
+ * material starts.
+ *
+ * @return true if the given DES key material is weak or semi-weak, false
+ * otherwise.
+ *
+ * @exception InvalidKeyException if the given key material is
+ * <code>null</code>, or starting at <code>offset</code> inclusive, is
+ * shorter than 8 bytes.
+ */
+ public static boolean isWeak(byte[] key, int offset)
+ throws InvalidKeyException {
+ if (key == null) {
+ throw new InvalidKeyException("null key");
+ }
+ if (key.length - offset < DES_KEY_LEN) {
+ throw new InvalidKeyException("Wrong key size");
+ }
+ for (int i = 0; i < WEAK_KEYS.length; i++) {
+ boolean found = true;
+ for (int j = 0; j < DES_KEY_LEN && found == true; j++) {
+ if (WEAK_KEYS[i][j] != key[j+offset]) {
+ found = false;
+ }
+ }
+ if (found == true) {
+ return found;
+ }
+ }
+ return false;
+ }
+}
diff --git a/javax/crypto/spec/DESedeKeySpec.java b/javax/crypto/spec/DESedeKeySpec.java
new file mode 100644
index 0000000..32454de
--- /dev/null
+++ b/javax/crypto/spec/DESedeKeySpec.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.crypto.spec;
+
+import java.security.InvalidKeyException;
+
+/**
+ * This class specifies a DES-EDE ("triple-DES") key.
+ *
+ * @author Jan Luehe
+ *
+ * @since 1.4
+ */
+public class DESedeKeySpec implements java.security.spec.KeySpec {
+
+ /**
+ * The constant which defines the length of a DESede key in bytes.
+ */
+ public static final int DES_EDE_KEY_LEN = 24;
+
+ private byte[] key;
+
+ /**
+ * Creates a DESedeKeySpec object using the first 24 bytes in
+ * <code>key</code> as the key material for the DES-EDE key.
+ *
+ * <p> The bytes that constitute the DES-EDE key are those between
+ * <code>key[0]</code> and <code>key[23]</code> inclusive
+ *
+ * @param key the buffer with the DES-EDE key material. The first
+ * 24 bytes of the buffer are copied to protect against subsequent
+ * modification.
+ *
+ * @exception NullPointerException if <code>key</code> is null.
+ * @exception InvalidKeyException if the given key material is shorter
+ * than 24 bytes.
+ */
+ public DESedeKeySpec(byte[] key) throws InvalidKeyException {
+ this(key, 0);
+ }
+
+ /**
+ * Creates a DESedeKeySpec object using the first 24 bytes in
+ * <code>key</code>, beginning at <code>offset</code> inclusive,
+ * as the key material for the DES-EDE key.
+ *
+ * <p> The bytes that constitute the DES-EDE key are those between
+ * <code>key[offset]</code> and <code>key[offset+23]</code> inclusive.
+ *
+ * @param key the buffer with the DES-EDE key material. The first
+ * 24 bytes of the buffer beginning at <code>offset</code> inclusive
+ * are copied to protect against subsequent modification.
+ * @param offset the offset in <code>key</code>, where the DES-EDE key
+ * material starts.
+ *
+ * @exception NullPointerException if <code>key</code> is null.
+ * @exception InvalidKeyException if the given key material, starting at
+ * <code>offset</code> inclusive, is shorter than 24 bytes
+ */
+ public DESedeKeySpec(byte[] key, int offset) throws InvalidKeyException {
+ if (key.length - offset < 24) {
+ throw new InvalidKeyException("Wrong key size");
+ }
+ this.key = new byte[24];
+ System.arraycopy(key, offset, this.key, 0, 24);
+ }
+
+ /**
+ * Returns the DES-EDE key.
+ *
+ * @return the DES-EDE key. Returns a new array
+ * each time this method is called.
+ */
+ public byte[] getKey() {
+ return this.key.clone();
+ }
+
+ /**
+ * Checks if the given DES-EDE key, starting at <code>offset</code>
+ * inclusive, is parity-adjusted.
+ *
+ * @param key a byte array which holds the key value
+ * @param offset the offset into the byte array
+ * @return true if the given DES-EDE key is parity-adjusted, false
+ * otherwise
+ *
+ * @exception NullPointerException if <code>key</code> is null.
+ * @exception InvalidKeyException if the given key material, starting at
+ * <code>offset</code> inclusive, is shorter than 24 bytes
+ */
+ public static boolean isParityAdjusted(byte[] key, int offset)
+ throws InvalidKeyException {
+ if (key.length - offset < 24) {
+ throw new InvalidKeyException("Wrong key size");
+ }
+ if (DESKeySpec.isParityAdjusted(key, offset) == false
+ || DESKeySpec.isParityAdjusted(key, offset + 8) == false
+ || DESKeySpec.isParityAdjusted(key, offset + 16) == false) {
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/javax/crypto/spec/DHGenParameterSpec.java b/javax/crypto/spec/DHGenParameterSpec.java
new file mode 100644
index 0000000..d3b5cf4
--- /dev/null
+++ b/javax/crypto/spec/DHGenParameterSpec.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.crypto.spec;
+
+import java.math.BigInteger;
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * This class specifies the set of parameters used for generating
+ * Diffie-Hellman (system) parameters for use in Diffie-Hellman key
+ * agreement. This is typically done by a central
+ * authority.
+ *
+ * <p> The central authority, after computing the parameters, must send this
+ * information to the parties looking to agree on a secret key.
+ *
+ * @author Jan Luehe
+ *
+ * @see DHParameterSpec
+ * @since 1.4
+ */
+public class DHGenParameterSpec implements AlgorithmParameterSpec {
+
+ // The size in bits of the prime modulus
+ private int primeSize;
+
+ // The size in bits of the random exponent (private value)
+ private int exponentSize;
+
+ /**
+ * Constructs a parameter set for the generation of Diffie-Hellman
+ * (system) parameters. The constructed parameter set can be used to
+ * initialize an
+ * {@link java.security.AlgorithmParameterGenerator AlgorithmParameterGenerator}
+ * object for the generation of Diffie-Hellman parameters.
+ *
+ * @param primeSize the size (in bits) of the prime modulus.
+ * @param exponentSize the size (in bits) of the random exponent.
+ */
+ public DHGenParameterSpec(int primeSize, int exponentSize) {
+ this.primeSize = primeSize;
+ this.exponentSize = exponentSize;
+ }
+
+ /**
+ * Returns the size in bits of the prime modulus.
+ *
+ * @return the size in bits of the prime modulus
+ */
+ public int getPrimeSize() {
+ return this.primeSize;
+ }
+
+ /**
+ * Returns the size in bits of the random exponent (private value).
+ *
+ * @return the size in bits of the random exponent (private value)
+ */
+ public int getExponentSize() {
+ return this.exponentSize;
+ }
+}
diff --git a/javax/crypto/spec/DHParameterSpec.java b/javax/crypto/spec/DHParameterSpec.java
new file mode 100644
index 0000000..4d113ec
--- /dev/null
+++ b/javax/crypto/spec/DHParameterSpec.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.crypto.spec;
+
+import java.math.BigInteger;
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * This class specifies the set of parameters used with the Diffie-Hellman
+ * algorithm, as specified in PKCS #3: <i>Diffie-Hellman Key-Agreement
+ * Standard</i>.
+ *
+ * <p>A central authority generates parameters and gives them to the two
+ * entities seeking to generate a secret key. The parameters are a prime
+ * <code>p</code>, a base <code>g</code>, and optionally the length
+ * in bits of the private value, <code>l</code>.
+ *
+ * <p>It is possible that more than one instance of parameters may be
+ * generated by a given central authority, and that there may be more than
+ * one central authority. Indeed, each individual may be its own central
+ * authority, with different entities having different parameters.
+ *
+ * <p>Note that this class does not perform any validation on specified
+ * parameters. Thus, the specified values are returned directly even
+ * if they are null.
+ *
+ * @author Jan Luehe
+ *
+ * @see javax.crypto.KeyAgreement
+ * @since 1.4
+ */
+public class DHParameterSpec implements AlgorithmParameterSpec {
+
+ // The prime modulus
+ private BigInteger p;
+
+ // The base generator
+ private BigInteger g;
+
+ // The size in bits of the random exponent (private value) (optional)
+ private int l;
+
+ /**
+ * Constructs a parameter set for Diffie-Hellman, using a prime modulus
+ * <code>p</code> and a base generator <code>g</code>.
+ *
+ * @param p the prime modulus
+ * @param g the base generator
+ */
+ public DHParameterSpec(BigInteger p, BigInteger g) {
+ this.p = p;
+ this.g = g;
+ this.l = 0;
+ }
+
+ /**
+ * Constructs a parameter set for Diffie-Hellman, using a prime modulus
+ * <code>p</code>, a base generator <code>g</code>,
+ * and the size in bits, <code>l</code>, of the random exponent
+ * (private value).
+ *
+ * @param p the prime modulus
+ * @param g the base generator
+ * @param l the size in bits of the random exponent (private value)
+ */
+ public DHParameterSpec(BigInteger p, BigInteger g, int l) {
+ this.p = p;
+ this.g = g;
+ this.l = l;
+ }
+
+ /**
+ * Returns the prime modulus <code>p</code>.
+ *
+ * @return the prime modulus <code>p</code>
+ */
+ public BigInteger getP() {
+ return this.p;
+ }
+
+ /**
+ * Returns the base generator <code>g</code>.
+ *
+ * @return the base generator <code>g</code>
+ */
+ public BigInteger getG() {
+ return this.g;
+ }
+
+ /**
+ * Returns the size in bits, <code>l</code>, of the random exponent
+ * (private value).
+ *
+ * @return the size in bits, <code>l</code>, of the random exponent
+ * (private value), or 0 if this size has not been set
+ */
+ public int getL() {
+ return this.l;
+ }
+}
diff --git a/javax/crypto/spec/DHPrivateKeySpec.java b/javax/crypto/spec/DHPrivateKeySpec.java
new file mode 100644
index 0000000..5842bbc
--- /dev/null
+++ b/javax/crypto/spec/DHPrivateKeySpec.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.crypto.spec;
+
+import java.math.BigInteger;
+
+/**
+ * This class specifies a Diffie-Hellman private key with its associated
+ * parameters.
+ *
+ * <p>Note that this class does not perform any validation on specified
+ * parameters. Thus, the specified values are returned directly even
+ * if they are null.
+ *
+ * @author Jan Luehe
+ *
+ * @see DHPublicKeySpec
+ * @since 1.4
+ */
+public class DHPrivateKeySpec implements java.security.spec.KeySpec {
+
+ // The private value
+ private BigInteger x;
+
+ // The prime modulus
+ private BigInteger p;
+
+ // The base generator
+ private BigInteger g;
+
+ /**
+ * Constructor that takes a private value <code>x</code>, a prime
+ * modulus <code>p</code>, and a base generator <code>g</code>.
+ * @param x private value x
+ * @param p prime modulus p
+ * @param g base generator g
+ */
+ public DHPrivateKeySpec(BigInteger x, BigInteger p, BigInteger g) {
+ this.x = x;
+ this.p = p;
+ this.g = g;
+ }
+
+ /**
+ * Returns the private value <code>x</code>.
+ *
+ * @return the private value <code>x</code>
+ */
+ public BigInteger getX() {
+ return this.x;
+ }
+
+ /**
+ * Returns the prime modulus <code>p</code>.
+ *
+ * @return the prime modulus <code>p</code>
+ */
+ public BigInteger getP() {
+ return this.p;
+ }
+
+ /**
+ * Returns the base generator <code>g</code>.
+ *
+ * @return the base generator <code>g</code>
+ */
+ public BigInteger getG() {
+ return this.g;
+ }
+}
diff --git a/javax/crypto/spec/DHPublicKeySpec.java b/javax/crypto/spec/DHPublicKeySpec.java
new file mode 100644
index 0000000..91baf7a
--- /dev/null
+++ b/javax/crypto/spec/DHPublicKeySpec.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.crypto.spec;
+
+import java.math.BigInteger;
+
+/**
+ * This class specifies a Diffie-Hellman public key with its associated
+ * parameters.
+ *
+ * <p>Note that this class does not perform any validation on specified
+ * parameters. Thus, the specified values are returned directly even
+ * if they are null.
+ *
+ * @author Jan Luehe
+ *
+ * @see DHPrivateKeySpec
+ * @since 1.4
+ */
+public class DHPublicKeySpec implements java.security.spec.KeySpec {
+
+ // The public value
+ private BigInteger y;
+
+ // The prime modulus
+ private BigInteger p;
+
+ // The base generator
+ private BigInteger g;
+
+ /**
+ * Constructor that takes a public value <code>y</code>, a prime
+ * modulus <code>p</code>, and a base generator <code>g</code>.
+ * @param y public value y
+ * @param p prime modulus p
+ * @param g base generator g
+ */
+ public DHPublicKeySpec(BigInteger y, BigInteger p, BigInteger g) {
+ this.y = y;
+ this.p = p;
+ this.g = g;
+ }
+
+ /**
+ * Returns the public value <code>y</code>.
+ *
+ * @return the public value <code>y</code>
+ */
+ public BigInteger getY() {
+ return this.y;
+ }
+
+ /**
+ * Returns the prime modulus <code>p</code>.
+ *
+ * @return the prime modulus <code>p</code>
+ */
+ public BigInteger getP() {
+ return this.p;
+ }
+
+ /**
+ * Returns the base generator <code>g</code>.
+ *
+ * @return the base generator <code>g</code>
+ */
+ public BigInteger getG() {
+ return this.g;
+ }
+}
diff --git a/javax/crypto/spec/GCMParameterSpec.java b/javax/crypto/spec/GCMParameterSpec.java
new file mode 100644
index 0000000..403205a
--- /dev/null
+++ b/javax/crypto/spec/GCMParameterSpec.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.crypto.spec;
+
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * Specifies the set of parameters required by a {@link
+ * javax.crypto.Cipher} using the Galois/Counter Mode (GCM) mode.
+ * <p>
+ * Simple block cipher modes (such as CBC) generally require only an
+ * initialization vector (such as {@code IvParameterSpec}),
+ * but GCM needs these parameters:
+ * <ul>
+ * <li>{@code IV}: Initialization Vector (IV) </li>
+ * <li>{@code tLen}: length (in bits) of authentication tag T</li>
+ * </ul>
+ * <p>
+ * In addition to the parameters described here, other GCM inputs/output
+ * (Additional Authenticated Data (AAD), Keys, block ciphers,
+ * plain/ciphertext and authentication tags) are handled in the {@code
+ * Cipher} class.
+ * <p>
+ * Please see <a href="http://www.ietf.org/rfc/rfc5116.txt"> RFC 5116
+ * </a> for more information on the Authenticated Encryption with
+ * Associated Data (AEAD) algorithm, and <a href=
+ * "http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf">
+ * NIST Special Publication 800-38D</a>, "NIST Recommendation for Block
+ * Cipher Modes of Operation: Galois/Counter Mode (GCM) and GMAC."
+ * <p>
+ * The GCM specification states that {@code tLen} may only have the
+ * values {128, 120, 112, 104, 96}, or {64, 32} for certain
+ * applications. Other values can be specified for this class, but not
+ * all CSP implementations will support them.
+ *
+ * @see javax.crypto.Cipher
+ *
+ * @since 1.7
+ */
+public class GCMParameterSpec implements AlgorithmParameterSpec {
+
+ // Initialization Vector. Could use IvParameterSpec, but that
+ // would add extra copies.
+ private byte[] iv;
+
+ // Required Tag length (in bits).
+ private int tLen;
+
+ /**
+ * Constructs a GCMParameterSpec using the specified authentication
+ * tag bit-length and IV buffer.
+ *
+ * @param tLen the authentication tag length (in bits)
+ * @param src the IV source buffer. The contents of the buffer are
+ * copied to protect against subsequent modification.
+ *
+ * @throws IllegalArgumentException if {@code tLen} is negative,
+ * or {@code src} is null.
+ */
+ public GCMParameterSpec(int tLen, byte[] src) {
+ if (src == null) {
+ throw new IllegalArgumentException("src array is null");
+ }
+
+ init(tLen, src, 0, src.length);
+ }
+
+ /**
+ * Constructs a GCMParameterSpec object using the specified
+ * authentication tag bit-length and a subset of the specified
+ * buffer as the IV.
+ *
+ * @param tLen the authentication tag length (in bits)
+ * @param src the IV source buffer. The contents of the
+ * buffer are copied to protect against subsequent modification.
+ * @param offset the offset in {@code src} where the IV starts
+ * @param len the number of IV bytes
+ *
+ * @throws IllegalArgumentException if {@code tLen} is negative,
+ * {@code src} is null, {@code len} or {@code offset} is negative,
+ * or the sum of {@code offset} and {@code len} is greater than the
+ * length of the {@code src} byte array.
+ */
+ public GCMParameterSpec(int tLen, byte[] src, int offset, int len) {
+ init(tLen, src, offset, len);
+ }
+
+ /*
+ * Check input parameters.
+ */
+ private void init(int tLen, byte[] src, int offset, int len) {
+ if (tLen < 0) {
+ throw new IllegalArgumentException(
+ "Length argument is negative");
+ }
+ this.tLen = tLen;
+
+ // Input sanity check
+ if ((src == null) ||(len < 0) || (offset < 0)
+ || ((len + offset) > src.length)) {
+ throw new IllegalArgumentException("Invalid buffer arguments");
+ }
+
+ iv = new byte[len];
+ System.arraycopy(src, offset, iv, 0, len);
+ }
+
+ /**
+ * Returns the authentication tag length.
+ *
+ * @return the authentication tag length (in bits)
+ */
+ public int getTLen() {
+ return tLen;
+ }
+
+ /**
+ * Returns the Initialization Vector (IV).
+ *
+ * @return the IV. Creates a new array each time this method
+ * is called.
+ */
+ public byte[] getIV() {
+ return iv.clone();
+ }
+}
diff --git a/javax/crypto/spec/IvParameterSpec.java b/javax/crypto/spec/IvParameterSpec.java
new file mode 100644
index 0000000..243c848
--- /dev/null
+++ b/javax/crypto/spec/IvParameterSpec.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.crypto.spec;
+
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * This class specifies an <i>initialization vector</i> (IV).
+ * Examples which use IVs are ciphers in feedback mode,
+ * e.g., DES in CBC mode and RSA ciphers with OAEP encoding
+ * operation.
+ *
+ * @author Jan Luehe
+ *
+ * @since 1.4
+ */
+public class IvParameterSpec implements AlgorithmParameterSpec {
+
+ private byte[] iv;
+
+ /**
+ * Creates an IvParameterSpec object using the bytes in <code>iv</code>
+ * as the IV.
+ *
+ * @param iv the buffer with the IV. The contents of the
+ * buffer are copied to protect against subsequent modification.
+ * @throws NullPointerException if <code>iv</code> is <code>null</code>
+ */
+ public IvParameterSpec(byte[] iv) {
+ this(iv, 0, iv.length);
+ }
+
+ /**
+ * Creates an IvParameterSpec object using the first <code>len</code>
+ * bytes in <code>iv</code>, beginning at <code>offset</code>
+ * inclusive, as the IV.
+ *
+ * <p> The bytes that constitute the IV are those between
+ * <code>iv[offset]</code> and <code>iv[offset+len-1]</code> inclusive.
+ *
+ * @param iv the buffer with the IV. The first <code>len</code>
+ * bytes of the buffer beginning at <code>offset</code> inclusive
+ * are copied to protect against subsequent modification.
+ * @param offset the offset in <code>iv</code> where the IV
+ * starts.
+ * @param len the number of IV bytes.
+ * @throws IllegalArgumentException if <code>iv</code> is <code>null</code>
+ * or {@code (iv.length - offset < len)}
+ * @throws ArrayIndexOutOfBoundsException is thrown if <code>offset</code>
+ * or <code>len</code> index bytes outside the <code>iv</code>.
+ */
+ public IvParameterSpec(byte[] iv, int offset, int len) {
+ if (iv == null) {
+ throw new IllegalArgumentException("IV missing");
+ }
+ if (iv.length - offset < len) {
+ throw new IllegalArgumentException
+ ("IV buffer too short for given offset/length combination");
+ }
+ if (len < 0) {
+ throw new ArrayIndexOutOfBoundsException("len is negative");
+ }
+ this.iv = new byte[len];
+ System.arraycopy(iv, offset, this.iv, 0, len);
+ }
+
+ /**
+ * Returns the initialization vector (IV).
+ *
+ * @return the initialization vector (IV). Returns a new array
+ * each time this method is called.
+ */
+ public byte[] getIV() {
+ return this.iv.clone();
+ }
+}
diff --git a/javax/crypto/spec/OAEPParameterSpec.java b/javax/crypto/spec/OAEPParameterSpec.java
new file mode 100644
index 0000000..fcdc018
--- /dev/null
+++ b/javax/crypto/spec/OAEPParameterSpec.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.crypto.spec;
+
+import java.math.BigInteger;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.MGF1ParameterSpec;
+
+/**
+ * This class specifies the set of parameters used with OAEP Padding,
+ * as defined in the
+ * <a href="http://www.ietf.org/rfc/rfc3447.txt">PKCS #1</a>
+ * standard.
+ *
+ * Its ASN.1 definition in PKCS#1 standard is described below:
+ * <pre>
+ * RSAES-OAEP-params ::= SEQUENCE {
+ * hashAlgorithm [0] OAEP-PSSDigestAlgorithms DEFAULT sha1,
+ * maskGenAlgorithm [1] PKCS1MGFAlgorithms DEFAULT mgf1SHA1,
+ * pSourceAlgorithm [2] PKCS1PSourceAlgorithms DEFAULT pSpecifiedEmpty
+ * }
+ * </pre>
+ * where
+ * <pre>
+ * OAEP-PSSDigestAlgorithms ALGORITHM-IDENTIFIER ::= {
+ * { OID id-sha1 PARAMETERS NULL }|
+ * { OID id-sha256 PARAMETERS NULL }|
+ * { OID id-sha384 PARAMETERS NULL }|
+ * { OID id-sha512 PARAMETERS NULL },
+ * ... -- Allows for future expansion --
+ * }
+ * PKCS1MGFAlgorithms ALGORITHM-IDENTIFIER ::= {
+ * { OID id-mgf1 PARAMETERS OAEP-PSSDigestAlgorithms },
+ * ... -- Allows for future expansion --
+ * }
+ * PKCS1PSourceAlgorithms ALGORITHM-IDENTIFIER ::= {
+ * { OID id-pSpecified PARAMETERS OCTET STRING },
+ * ... -- Allows for future expansion --
+ * }
+ * </pre>
+ * <p>Note: the OAEPParameterSpec.DEFAULT uses the following:
+ * message digest -- "SHA-1"
+ * mask generation function (mgf) -- "MGF1"
+ * parameters for mgf -- MGF1ParameterSpec.SHA1
+ * source of encoding input -- PSource.PSpecified.DEFAULT
+ *
+ * @see java.security.spec.MGF1ParameterSpec
+ * @see PSource
+ *
+ * @author Valerie Peng
+ *
+ * @since 1.5
+ */
+public class OAEPParameterSpec implements AlgorithmParameterSpec {
+
+ private String mdName = "SHA-1";
+ private String mgfName = "MGF1";
+ private AlgorithmParameterSpec mgfSpec = MGF1ParameterSpec.SHA1;
+ private PSource pSrc = PSource.PSpecified.DEFAULT;
+
+ /**
+ * The OAEP parameter set with all default values.
+ */
+ public static final OAEPParameterSpec DEFAULT = new OAEPParameterSpec();
+
+ /**
+ * Constructs a parameter set for OAEP padding as defined in
+ * the PKCS #1 standard using the default values.
+ */
+ private OAEPParameterSpec() {
+ }
+
+ /**
+ * Constructs a parameter set for OAEP padding as defined in
+ * the PKCS #1 standard using the specified message digest
+ * algorithm <code>mdName</code>, mask generation function
+ * algorithm <code>mgfName</code>, parameters for the mask
+ * generation function <code>mgfSpec</code>, and source of
+ * the encoding input P <code>pSrc</code>.
+ *
+ * @param mdName the algorithm name for the message digest.
+ * @param mgfName the algorithm name for the mask generation
+ * function.
+ * @param mgfSpec the parameters for the mask generation function.
+ * If null is specified, null will be returned by getMGFParameters().
+ * @param pSrc the source of the encoding input P.
+ * @exception NullPointerException if <code>mdName</code>,
+ * <code>mgfName</code>, or <code>pSrc</code> is null.
+ */
+ public OAEPParameterSpec(String mdName, String mgfName,
+ AlgorithmParameterSpec mgfSpec,
+ PSource pSrc) {
+ if (mdName == null) {
+ throw new NullPointerException("digest algorithm is null");
+ }
+ if (mgfName == null) {
+ throw new NullPointerException("mask generation function " +
+ "algorithm is null");
+ }
+ if (pSrc == null) {
+ throw new NullPointerException("source of the encoding input " +
+ "is null");
+ }
+ this.mdName = mdName;
+ this.mgfName = mgfName;
+ this.mgfSpec = mgfSpec;
+ this.pSrc = pSrc;
+ }
+
+ /**
+ * Returns the message digest algorithm name.
+ *
+ * @return the message digest algorithm name.
+ */
+ public String getDigestAlgorithm() {
+ return mdName;
+ }
+
+ /**
+ * Returns the mask generation function algorithm name.
+ *
+ * @return the mask generation function algorithm name.
+ */
+ public String getMGFAlgorithm() {
+ return mgfName;
+ }
+
+ /**
+ * Returns the parameters for the mask generation function.
+ *
+ * @return the parameters for the mask generation function.
+ */
+ public AlgorithmParameterSpec getMGFParameters() {
+ return mgfSpec;
+ }
+
+ /**
+ * Returns the source of encoding input P.
+ *
+ * @return the source of encoding input P.
+ */
+ public PSource getPSource() {
+ return pSrc;
+ }
+}
diff --git a/javax/crypto/spec/PBEKeySpec.java b/javax/crypto/spec/PBEKeySpec.java
new file mode 100644
index 0000000..239231d
--- /dev/null
+++ b/javax/crypto/spec/PBEKeySpec.java
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.crypto.spec;
+
+import java.security.spec.KeySpec;
+
+/**
+ * A user-chosen password that can be used with password-based encryption
+ * (<i>PBE</i>).
+ *
+ * <p>The password can be viewed as some kind of raw key material, from which
+ * the encryption mechanism that uses it derives a cryptographic key.
+ *
+ * <p>Different PBE mechanisms may consume different bits of each password
+ * character. For example, the PBE mechanism defined in
+ * <a href="http://www.ietf.org/rfc/rfc2898.txt">
+ * PKCS #5</a> looks at only the low order 8 bits of each character, whereas
+ * PKCS #12 looks at all 16 bits of each character.
+ *
+ * <p>You convert the password characters to a PBE key by creating an
+ * instance of the appropriate secret-key factory. For example, a secret-key
+ * factory for PKCS #5 will construct a PBE key from only the low order 8 bits
+ * of each password character, whereas a secret-key factory for PKCS #12 will
+ * take all 16 bits of each character.
+ *
+ * <p>Also note that this class stores passwords as char arrays instead of
+ * <code>String</code> objects (which would seem more logical), because the
+ * String class is immutable and there is no way to overwrite its
+ * internal value when the password stored in it is no longer needed. Hence,
+ * this class requests the password as a char array, so it can be overwritten
+ * when done.
+ *
+ * @author Jan Luehe
+ * @author Valerie Peng
+ *
+ * @see javax.crypto.SecretKeyFactory
+ * @see PBEParameterSpec
+ * @since 1.4
+ */
+public class PBEKeySpec implements KeySpec {
+
+ private char[] password;
+ private byte[] salt = null;
+ private int iterationCount = 0;
+ private int keyLength = 0;
+
+ /**
+ * Constructor that takes a password. An empty char[] is used if
+ * null is specified.
+ *
+ * <p> Note: <code>password</code> is cloned before it is stored in
+ * the new <code>PBEKeySpec</code> object.
+ *
+ * @param password the password.
+ */
+ public PBEKeySpec(char[] password) {
+ if ((password == null) || (password.length == 0)) {
+ this.password = new char[0];
+ } else {
+ this.password = password.clone();
+ }
+ }
+
+
+ /**
+ * Constructor that takes a password, salt, iteration count, and
+ * to-be-derived key length for generating PBEKey of variable-key-size
+ * PBE ciphers. An empty char[] is used if null is specified for
+ * <code>password</code>.
+ *
+ * <p> Note: the <code>password</code> and <code>salt</code>
+ * are cloned before they are stored in
+ * the new <code>PBEKeySpec</code> object.
+ *
+ * @param password the password.
+ * @param salt the salt.
+ * @param iterationCount the iteration count.
+ * @param keyLength the to-be-derived key length.
+ * @exception NullPointerException if <code>salt</code> is null.
+ * @exception IllegalArgumentException if <code>salt</code> is empty,
+ * i.e. 0-length, <code>iterationCount</code> or
+ * <code>keyLength</code> is not positive.
+ */
+ public PBEKeySpec(char[] password, byte[] salt, int iterationCount,
+ int keyLength) {
+ if ((password == null) || (password.length == 0)) {
+ this.password = new char[0];
+ } else {
+ this.password = password.clone();
+ }
+ if (salt == null) {
+ throw new NullPointerException("the salt parameter " +
+ "must be non-null");
+ } else if (salt.length == 0) {
+ throw new IllegalArgumentException("the salt parameter " +
+ "must not be empty");
+ } else {
+ this.salt = salt.clone();
+ }
+ if (iterationCount<=0) {
+ throw new IllegalArgumentException("invalid iterationCount value");
+ }
+ if (keyLength<=0) {
+ throw new IllegalArgumentException("invalid keyLength value");
+ }
+ this.iterationCount = iterationCount;
+ this.keyLength = keyLength;
+ }
+
+
+ /**
+ * Constructor that takes a password, salt, iteration count for
+ * generating PBEKey of fixed-key-size PBE ciphers. An empty
+ * char[] is used if null is specified for <code>password</code>.
+ *
+ * <p> Note: the <code>password</code> and <code>salt</code>
+ * are cloned before they are stored in the new
+ * <code>PBEKeySpec</code> object.
+ *
+ * @param password the password.
+ * @param salt the salt.
+ * @param iterationCount the iteration count.
+ * @exception NullPointerException if <code>salt</code> is null.
+ * @exception IllegalArgumentException if <code>salt</code> is empty,
+ * i.e. 0-length, or <code>iterationCount</code> is not positive.
+ */
+ public PBEKeySpec(char[] password, byte[] salt, int iterationCount) {
+ if ((password == null) || (password.length == 0)) {
+ this.password = new char[0];
+ } else {
+ this.password = password.clone();
+ }
+ if (salt == null) {
+ throw new NullPointerException("the salt parameter " +
+ "must be non-null");
+ } else if (salt.length == 0) {
+ throw new IllegalArgumentException("the salt parameter " +
+ "must not be empty");
+ } else {
+ this.salt = salt.clone();
+ }
+ if (iterationCount<=0) {
+ throw new IllegalArgumentException("invalid iterationCount value");
+ }
+ this.iterationCount = iterationCount;
+ }
+
+ /**
+ * Clears the internal copy of the password.
+ *
+ */
+ public final void clearPassword() {
+ if (password != null) {
+ for (int i = 0; i < password.length; i++) {
+ password[i] = ' ';
+ }
+ password = null;
+ }
+ }
+
+ /**
+ * Returns a copy of the password.
+ *
+ * <p> Note: this method returns a copy of the password. It is
+ * the caller's responsibility to zero out the password information after
+ * it is no longer needed.
+ *
+ * @exception IllegalStateException if password has been cleared by
+ * calling <code>clearPassword</code> method.
+ * @return the password.
+ */
+ public final char[] getPassword() {
+ if (password == null) {
+ throw new IllegalStateException("password has been cleared");
+ }
+ return password.clone();
+ }
+
+ /**
+ * Returns a copy of the salt or null if not specified.
+ *
+ * <p> Note: this method should return a copy of the salt. It is
+ * the caller's responsibility to zero out the salt information after
+ * it is no longer needed.
+ *
+ * @return the salt.
+ */
+ public final byte[] getSalt() {
+ if (salt != null) {
+ return salt.clone();
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Returns the iteration count or 0 if not specified.
+ *
+ * @return the iteration count.
+ */
+ public final int getIterationCount() {
+ return iterationCount;
+ }
+
+ /**
+ * Returns the to-be-derived key length or 0 if not specified.
+ *
+ * <p> Note: this is used to indicate the preference on key length
+ * for variable-key-size ciphers. The actual key size depends on
+ * each provider's implementation.
+ *
+ * @return the to-be-derived key length.
+ */
+ public final int getKeyLength() {
+ return keyLength;
+ }
+}
diff --git a/javax/crypto/spec/PBEParameterSpec.java b/javax/crypto/spec/PBEParameterSpec.java
new file mode 100644
index 0000000..ca45c73
--- /dev/null
+++ b/javax/crypto/spec/PBEParameterSpec.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.crypto.spec;
+
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * This class specifies the set of parameters used with password-based
+ * encryption (PBE), as defined in the
+ * <a href="http://www.ietf.org/rfc/rfc2898.txt">PKCS #5</a>
+ * standard.
+ *
+ * @author Jan Luehe
+ *
+ * @since 1.4
+ */
+public class PBEParameterSpec implements AlgorithmParameterSpec {
+
+ private byte[] salt;
+ private int iterationCount;
+ private AlgorithmParameterSpec paramSpec = null;
+
+ /**
+ * Constructs a parameter set for password-based encryption as defined in
+ * the PKCS #5 standard.
+ *
+ * @param salt the salt. The contents of <code>salt</code> are copied
+ * to protect against subsequent modification.
+ * @param iterationCount the iteration count.
+ * @exception NullPointerException if <code>salt</code> is null.
+ */
+ public PBEParameterSpec(byte[] salt, int iterationCount) {
+ this.salt = salt.clone();
+ this.iterationCount = iterationCount;
+ }
+
+ /**
+ * Constructs a parameter set for password-based encryption as defined in
+ * the PKCS #5 standard.
+ *
+ * @param salt the salt. The contents of <code>salt</code> are copied
+ * to protect against subsequent modification.
+ * @param iterationCount the iteration count.
+ * @param paramSpec the cipher algorithm parameter specification, which
+ * may be null.
+ * @exception NullPointerException if <code>salt</code> is null.
+ *
+ * @since 1.8
+ */
+ public PBEParameterSpec(byte[] salt, int iterationCount,
+ AlgorithmParameterSpec paramSpec) {
+ this.salt = salt.clone();
+ this.iterationCount = iterationCount;
+ this.paramSpec = paramSpec;
+ }
+
+ /**
+ * Returns the salt.
+ *
+ * @return the salt. Returns a new array
+ * each time this method is called.
+ */
+ public byte[] getSalt() {
+ return this.salt.clone();
+ }
+
+ /**
+ * Returns the iteration count.
+ *
+ * @return the iteration count
+ */
+ public int getIterationCount() {
+ return this.iterationCount;
+ }
+
+ /**
+ * Returns the cipher algorithm parameter specification.
+ *
+ * @return the parameter specification, or null if none was set.
+ *
+ * @since 1.8
+ */
+ public AlgorithmParameterSpec getParameterSpec() {
+ return this.paramSpec;
+ }
+}
diff --git a/javax/crypto/spec/PSource.java b/javax/crypto/spec/PSource.java
new file mode 100644
index 0000000..a3d2efe
--- /dev/null
+++ b/javax/crypto/spec/PSource.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.crypto.spec;
+
+/**
+ * This class specifies the source for encoding input P in OAEP Padding,
+ * as defined in the
+ * <a href="http://www.ietf.org/rfc/rfc3447.txt">PKCS #1</a>
+ * standard.
+ * <pre>
+ * PKCS1PSourceAlgorithms ALGORITHM-IDENTIFIER ::= {
+ * { OID id-pSpecified PARAMETERS OCTET STRING },
+ * ... -- Allows for future expansion --
+ * }
+ * </pre>
+ * @author Valerie Peng
+ *
+ * @since 1.5
+ */
+public class PSource {
+
+ private String pSrcName;
+
+ /**
+ * Constructs a source of the encoding input P for OAEP
+ * padding as defined in the PKCS #1 standard using the
+ * specified PSource algorithm.
+ * @param pSrcName the algorithm for the source of the
+ * encoding input P.
+ * @exception NullPointerException if <code>pSrcName</code>
+ * is null.
+ */
+ protected PSource(String pSrcName) {
+ if (pSrcName == null) {
+ throw new NullPointerException("pSource algorithm is null");
+ }
+ this.pSrcName = pSrcName;
+ }
+ /**
+ * Returns the PSource algorithm name.
+ *
+ * @return the PSource algorithm name.
+ */
+ public String getAlgorithm() {
+ return pSrcName;
+ }
+
+ /**
+ * This class is used to explicitly specify the value for
+ * encoding input P in OAEP Padding.
+ *
+ * @since 1.5
+ */
+ public static final class PSpecified extends PSource {
+
+ private byte[] p = new byte[0];
+
+ /**
+ * The encoding input P whose value equals byte[0].
+ */
+ public static final PSpecified DEFAULT = new PSpecified(new byte[0]);
+
+ /**
+ * Constructs the source explicitly with the specified
+ * value <code>p</code> as the encoding input P.
+ * Note:
+ * @param p the value of the encoding input. The contents
+ * of the array are copied to protect against subsequent
+ * modification.
+ * @exception NullPointerException if <code>p</code> is null.
+ */
+ public PSpecified(byte[] p) {
+ super("PSpecified");
+ this.p = p.clone();
+ }
+ /**
+ * Returns the value of encoding input P.
+ * @return the value of encoding input P. A new array is
+ * returned each time this method is called.
+ */
+ public byte[] getValue() {
+ return (p.length==0? p: p.clone());
+ }
+ }
+}
diff --git a/javax/crypto/spec/RC2ParameterSpec.java b/javax/crypto/spec/RC2ParameterSpec.java
new file mode 100644
index 0000000..766b317
--- /dev/null
+++ b/javax/crypto/spec/RC2ParameterSpec.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.crypto.spec;
+
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * This class specifies the parameters used with the
+ * <a href="http://www.ietf.org/rfc/rfc2268.txt"><i>RC2</i></a>
+ * algorithm.
+ *
+ * <p> The parameters consist of an effective key size and optionally
+ * an 8-byte initialization vector (IV) (only in feedback mode).
+ *
+ * <p> This class can be used to initialize a <code>Cipher</code> object that
+ * implements the <i>RC2</i> algorithm.
+ *
+ * @author Jan Luehe
+ *
+ * @since 1.4
+ */
+public class RC2ParameterSpec implements AlgorithmParameterSpec {
+
+ private byte[] iv = null;
+ private int effectiveKeyBits;
+
+ /**
+ * Constructs a parameter set for RC2 from the given effective key size
+ * (in bits).
+ *
+ * @param effectiveKeyBits the effective key size in bits.
+ */
+ public RC2ParameterSpec(int effectiveKeyBits) {
+ this.effectiveKeyBits = effectiveKeyBits;
+ }
+
+ /**
+ * Constructs a parameter set for RC2 from the given effective key size
+ * (in bits) and an 8-byte IV.
+ *
+ * <p> The bytes that constitute the IV are those between
+ * <code>iv[0]</code> and <code>iv[7]</code> inclusive.
+ *
+ * @param effectiveKeyBits the effective key size in bits.
+ * @param iv the buffer with the 8-byte IV. The first 8 bytes of
+ * the buffer are copied to protect against subsequent modification.
+ * @exception IllegalArgumentException if <code>iv</code> is null.
+ */
+ public RC2ParameterSpec(int effectiveKeyBits, byte[] iv) {
+ this(effectiveKeyBits, iv, 0);
+ }
+
+ /**
+ * Constructs a parameter set for RC2 from the given effective key size
+ * (in bits) and IV.
+ *
+ * <p> The IV is taken from <code>iv</code>, starting at
+ * <code>offset</code> inclusive.
+ * The bytes that constitute the IV are those between
+ * <code>iv[offset]</code> and <code>iv[offset+7]</code> inclusive.
+ *
+ * @param effectiveKeyBits the effective key size in bits.
+ * @param iv the buffer with the IV. The first 8 bytes
+ * of the buffer beginning at <code>offset</code> inclusive
+ * are copied to protect against subsequent modification.
+ * @param offset the offset in <code>iv</code> where the 8-byte IV
+ * starts.
+ * @exception IllegalArgumentException if <code>iv</code> is null.
+ */
+ public RC2ParameterSpec(int effectiveKeyBits, byte[] iv, int offset) {
+ this.effectiveKeyBits = effectiveKeyBits;
+ if (iv == null) throw new IllegalArgumentException("IV missing");
+ int blockSize = 8;
+ if (iv.length - offset < blockSize) {
+ throw new IllegalArgumentException("IV too short");
+ }
+ this.iv = new byte[blockSize];
+ System.arraycopy(iv, offset, this.iv, 0, blockSize);
+ }
+
+ /**
+ * Returns the effective key size in bits.
+ *
+ * @return the effective key size in bits.
+ */
+ public int getEffectiveKeyBits() {
+ return this.effectiveKeyBits;
+ }
+
+ /**
+ * Returns the IV or null if this parameter set does not contain an IV.
+ *
+ * @return the IV or null if this parameter set does not contain an IV.
+ * Returns a new array each time this method is called.
+ */
+ public byte[] getIV() {
+ return (iv == null? null:iv.clone());
+ }
+
+ /**
+ * Tests for equality between the specified object and this
+ * object. Two RC2ParameterSpec objects are considered equal if their
+ * effective key sizes and IVs are equal.
+ * (Two IV references are considered equal if both are <tt>null</tt>.)
+ *
+ * @param obj the object to test for equality with this object.
+ *
+ * @return true if the objects are considered equal, false if
+ * <code>obj</code> is null or otherwise.
+ */
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (!(obj instanceof RC2ParameterSpec)) {
+ return false;
+ }
+ RC2ParameterSpec other = (RC2ParameterSpec) obj;
+
+ return ((effectiveKeyBits == other.effectiveKeyBits) &&
+ java.util.Arrays.equals(iv, other.iv));
+ }
+
+ /**
+ * Calculates a hash code value for the object.
+ * Objects that are equal will also have the same hashcode.
+ */
+ public int hashCode() {
+ int retval = 0;
+ if (iv != null) {
+ for (int i = 1; i < iv.length; i++) {
+ retval += iv[i] * i;
+ }
+ }
+ return (retval += effectiveKeyBits);
+ }
+}
diff --git a/javax/crypto/spec/RC5ParameterSpec.java b/javax/crypto/spec/RC5ParameterSpec.java
new file mode 100644
index 0000000..0eddb61
--- /dev/null
+++ b/javax/crypto/spec/RC5ParameterSpec.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.crypto.spec;
+
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * This class specifies the parameters used with the
+ * <a href="http://www.ietf.org/rfc/rfc2040.txt"><i>RC5</i></a>
+ * algorithm.
+ *
+ * <p> The parameters consist of a version number, a rounds count, a word
+ * size, and optionally an initialization vector (IV) (only in feedback mode).
+ *
+ * <p> This class can be used to initialize a <code>Cipher</code> object that
+ * implements the <i>RC5</i> algorithm as supplied by
+ * <a href="http://www.rsasecurity.com">RSA Security Inc.</a>,
+ * or any parties authorized by RSA Security.
+ *
+ * @author Jan Luehe
+ *
+ * @since 1.4
+ */
+public class RC5ParameterSpec implements AlgorithmParameterSpec {
+
+ private byte[] iv = null;
+ private int version;
+ private int rounds;
+ private int wordSize; // the word size in bits
+
+ /**
+ * Constructs a parameter set for RC5 from the given version, number of
+ * rounds and word size (in bits).
+ *
+ * @param version the version.
+ * @param rounds the number of rounds.
+ * @param wordSize the word size in bits.
+ */
+ public RC5ParameterSpec(int version, int rounds, int wordSize) {
+ this.version = version;
+ this.rounds = rounds;
+ this.wordSize = wordSize;
+ }
+
+ /**
+ * Constructs a parameter set for RC5 from the given version, number of
+ * rounds, word size (in bits), and IV.
+ *
+ * <p> Note that the size of the IV (block size) must be twice the word
+ * size. The bytes that constitute the IV are those between
+ * <code>iv[0]</code> and <code>iv[2*(wordSize/8)-1]</code> inclusive.
+ *
+ * @param version the version.
+ * @param rounds the number of rounds.
+ * @param wordSize the word size in bits.
+ * @param iv the buffer with the IV. The first <code>2*(wordSize/8)
+ * </code> bytes of the buffer are copied to protect against subsequent
+ * modification.
+ * @exception IllegalArgumentException if <code>iv</code> is
+ * <code>null</code> or {@code (iv.length < 2 * (wordSize / 8))}
+ */
+ public RC5ParameterSpec(int version, int rounds, int wordSize, byte[] iv) {
+ this(version, rounds, wordSize, iv, 0);
+ }
+
+ /**
+ * Constructs a parameter set for RC5 from the given version, number of
+ * rounds, word size (in bits), and IV.
+ *
+ * <p> The IV is taken from <code>iv</code>, starting at
+ * <code>offset</code> inclusive.
+ * Note that the size of the IV (block size), starting at
+ * <code>offset</code> inclusive, must be twice the word size.
+ * The bytes that constitute the IV are those between
+ * <code>iv[offset]</code> and <code>iv[offset+2*(wordSize/8)-1]</code>
+ * inclusive.
+ *
+ * @param version the version.
+ * @param rounds the number of rounds.
+ * @param wordSize the word size in bits.
+ * @param iv the buffer with the IV. The first <code>2*(wordSize/8)
+ * </code> bytes of the buffer beginning at <code>offset</code>
+ * inclusive are copied to protect against subsequent modification.
+ * @param offset the offset in <code>iv</code> where the IV starts.
+ * @exception IllegalArgumentException if <code>iv</code> is
+ * <code>null</code> or
+ * {@code (iv.length - offset < 2 * (wordSize / 8))}
+ */
+ public RC5ParameterSpec(int version, int rounds, int wordSize,
+ byte[] iv, int offset) {
+ this.version = version;
+ this.rounds = rounds;
+ this.wordSize = wordSize;
+ if (iv == null) throw new IllegalArgumentException("IV missing");
+ int blockSize = (wordSize / 8) * 2;
+ if (iv.length - offset < blockSize) {
+ throw new IllegalArgumentException("IV too short");
+ }
+ this.iv = new byte[blockSize];
+ System.arraycopy(iv, offset, this.iv, 0, blockSize);
+ }
+
+ /**
+ * Returns the version.
+ *
+ * @return the version.
+ */
+ public int getVersion() {
+ return this.version;
+ }
+
+ /**
+ * Returns the number of rounds.
+ *
+ * @return the number of rounds.
+ */
+ public int getRounds() {
+ return this.rounds;
+ }
+
+ /**
+ * Returns the word size in bits.
+ *
+ * @return the word size in bits.
+ */
+ public int getWordSize() {
+ return this.wordSize;
+ }
+
+ /**
+ * Returns the IV or null if this parameter set does not contain an IV.
+ *
+ * @return the IV or null if this parameter set does not contain an IV.
+ * Returns a new array each time this method is called.
+ */
+ public byte[] getIV() {
+ return (iv == null? null:iv.clone());
+ }
+
+ /**
+ * Tests for equality between the specified object and this
+ * object. Two RC5ParameterSpec objects are considered equal if their
+ * version numbers, number of rounds, word sizes, and IVs are equal.
+ * (Two IV references are considered equal if both are <tt>null</tt>.)
+ *
+ * @param obj the object to test for equality with this object.
+ *
+ * @return true if the objects are considered equal, false if
+ * <code>obj</code> is null or otherwise.
+ */
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (!(obj instanceof RC5ParameterSpec)) {
+ return false;
+ }
+ RC5ParameterSpec other = (RC5ParameterSpec) obj;
+
+ return ((version == other.version) &&
+ (rounds == other.rounds) &&
+ (wordSize == other.wordSize) &&
+ java.util.Arrays.equals(iv, other.iv));
+ }
+
+ /**
+ * Calculates a hash code value for the object.
+ * Objects that are equal will also have the same hashcode.
+ */
+ public int hashCode() {
+ int retval = 0;
+ if (iv != null) {
+ for (int i = 1; i < iv.length; i++) {
+ retval += iv[i] * i;
+ }
+ }
+ retval += (version + rounds + wordSize);
+ return retval;
+ }
+}
diff --git a/javax/crypto/spec/SecretKeySpec.java b/javax/crypto/spec/SecretKeySpec.java
new file mode 100644
index 0000000..767c0d2
--- /dev/null
+++ b/javax/crypto/spec/SecretKeySpec.java
@@ -0,0 +1,234 @@
+/*
+ * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.crypto.spec;
+
+import java.security.MessageDigest;
+import java.security.spec.KeySpec;
+import java.util.Locale;
+import javax.crypto.SecretKey;
+
+/**
+ * This class specifies a secret key in a provider-independent fashion.
+ *
+ * <p>It can be used to construct a <code>SecretKey</code> from a byte array,
+ * without having to go through a (provider-based)
+ * <code>SecretKeyFactory</code>.
+ *
+ * <p>This class is only useful for raw secret keys that can be represented as
+ * a byte array and have no key parameters associated with them, e.g., DES or
+ * Triple DES keys.
+ *
+ * @author Jan Luehe
+ *
+ * @see javax.crypto.SecretKey
+ * @see javax.crypto.SecretKeyFactory
+ * @since 1.4
+ */
+public class SecretKeySpec implements KeySpec, SecretKey {
+
+ private static final long serialVersionUID = 6577238317307289933L;
+
+ /**
+ * The secret key.
+ *
+ * @serial
+ */
+ private byte[] key;
+
+ /**
+ * The name of the algorithm associated with this key.
+ *
+ * @serial
+ */
+ private String algorithm;
+
+ /**
+ * Constructs a secret key from the given byte array.
+ *
+ * <p>This constructor does not check if the given bytes indeed specify a
+ * secret key of the specified algorithm. For example, if the algorithm is
+ * DES, this constructor does not check if <code>key</code> is 8 bytes
+ * long, and also does not check for weak or semi-weak keys.
+ * In order for those checks to be performed, an algorithm-specific
+ * <i>key specification</i> class (in this case:
+ * {@link DESKeySpec DESKeySpec})
+ * should be used.
+ *
+ * @param key the key material of the secret key. The contents of
+ * the array are copied to protect against subsequent modification.
+ * @param algorithm the name of the secret-key algorithm to be associated
+ * with the given key material.
+ * See Appendix A in the <a href=
+ * "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppA">
+ * Java Cryptography Architecture Reference Guide</a>
+ * for information about standard algorithm names.
+ * @exception IllegalArgumentException if <code>algorithm</code>
+ * is null or <code>key</code> is null or empty.
+ */
+ public SecretKeySpec(byte[] key, String algorithm) {
+ if (key == null || algorithm == null) {
+ throw new IllegalArgumentException("Missing argument");
+ }
+ if (key.length == 0) {
+ throw new IllegalArgumentException("Empty key");
+ }
+ this.key = key.clone();
+ this.algorithm = algorithm;
+ }
+
+ /**
+ * Constructs a secret key from the given byte array, using the first
+ * <code>len</code> bytes of <code>key</code>, starting at
+ * <code>offset</code> inclusive.
+ *
+ * <p> The bytes that constitute the secret key are
+ * those between <code>key[offset]</code> and
+ * <code>key[offset+len-1]</code> inclusive.
+ *
+ * <p>This constructor does not check if the given bytes indeed specify a
+ * secret key of the specified algorithm. For example, if the algorithm is
+ * DES, this constructor does not check if <code>key</code> is 8 bytes
+ * long, and also does not check for weak or semi-weak keys.
+ * In order for those checks to be performed, an algorithm-specific key
+ * specification class (in this case:
+ * {@link DESKeySpec DESKeySpec})
+ * must be used.
+ *
+ * @param key the key material of the secret key. The first
+ * <code>len</code> bytes of the array beginning at
+ * <code>offset</code> inclusive are copied to protect
+ * against subsequent modification.
+ * @param offset the offset in <code>key</code> where the key material
+ * starts.
+ * @param len the length of the key material.
+ * @param algorithm the name of the secret-key algorithm to be associated
+ * with the given key material.
+ * See Appendix A in the <a href=
+ * "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppA">
+ * Java Cryptography Architecture Reference Guide</a>
+ * for information about standard algorithm names.
+ * @exception IllegalArgumentException if <code>algorithm</code>
+ * is null or <code>key</code> is null, empty, or too short,
+ * i.e. {@code key.length-offset<len}.
+ * @exception ArrayIndexOutOfBoundsException is thrown if
+ * <code>offset</code> or <code>len</code> index bytes outside the
+ * <code>key</code>.
+ */
+ public SecretKeySpec(byte[] key, int offset, int len, String algorithm) {
+ if (key == null || algorithm == null) {
+ throw new IllegalArgumentException("Missing argument");
+ }
+ if (key.length == 0) {
+ throw new IllegalArgumentException("Empty key");
+ }
+ if (key.length-offset < len) {
+ throw new IllegalArgumentException
+ ("Invalid offset/length combination");
+ }
+ if (len < 0) {
+ throw new ArrayIndexOutOfBoundsException("len is negative");
+ }
+ this.key = new byte[len];
+ System.arraycopy(key, offset, this.key, 0, len);
+ this.algorithm = algorithm;
+ }
+
+ /**
+ * Returns the name of the algorithm associated with this secret key.
+ *
+ * @return the secret key algorithm.
+ */
+ public String getAlgorithm() {
+ return this.algorithm;
+ }
+
+ /**
+ * Returns the name of the encoding format for this secret key.
+ *
+ * @return the string "RAW".
+ */
+ public String getFormat() {
+ return "RAW";
+ }
+
+ /**
+ * Returns the key material of this secret key.
+ *
+ * @return the key material. Returns a new array
+ * each time this method is called.
+ */
+ public byte[] getEncoded() {
+ return this.key.clone();
+ }
+
+ /**
+ * Calculates a hash code value for the object.
+ * Objects that are equal will also have the same hashcode.
+ */
+ public int hashCode() {
+ int retval = 0;
+ for (int i = 1; i < this.key.length; i++) {
+ retval += this.key[i] * i;
+ }
+ if (this.algorithm.equalsIgnoreCase("TripleDES"))
+ return (retval ^= "desede".hashCode());
+ else
+ return (retval ^=
+ this.algorithm.toLowerCase(Locale.ENGLISH).hashCode());
+ }
+
+ /**
+ * Tests for equality between the specified object and this
+ * object. Two SecretKeySpec objects are considered equal if
+ * they are both SecretKey instances which have the
+ * same case-insensitive algorithm name and key encoding.
+ *
+ * @param obj the object to test for equality with this object.
+ *
+ * @return true if the objects are considered equal, false if
+ * <code>obj</code> is null or otherwise.
+ */
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+
+ if (!(obj instanceof SecretKey))
+ return false;
+
+ String thatAlg = ((SecretKey)obj).getAlgorithm();
+ if (!(thatAlg.equalsIgnoreCase(this.algorithm))) {
+ if ((!(thatAlg.equalsIgnoreCase("DESede"))
+ || !(this.algorithm.equalsIgnoreCase("TripleDES")))
+ && (!(thatAlg.equalsIgnoreCase("TripleDES"))
+ || !(this.algorithm.equalsIgnoreCase("DESede"))))
+ return false;
+ }
+
+ byte[] thatKey = ((SecretKey)obj).getEncoded();
+
+ return MessageDigest.isEqual(this.key, thatKey);
+ }
+}