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);
+    }
+}